paginated 1.0.8 → 1.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
 - data/README.md +22 -5
 - data/lib/{grape_extensions → grape}/dsl.rb +5 -4
 - data/lib/grape-paginated/args.rb +63 -0
 - data/lib/grape-paginated/collection.rb +58 -0
 - data/lib/grape-paginated/configuration.rb +20 -0
 - data/lib/grape-paginated/search.rb +99 -0
 - data/lib/grape-paginated/sorting.rb +12 -0
 - data/lib/grape-paginated/spreadsheet.rb +69 -0
 - data/lib/paginated.rb +12 -12
 - metadata +25 -23
 - data/lib/paginated/args_andling.rb +0 -63
 - data/lib/paginated/collection.rb +0 -58
 - data/lib/paginated/search.rb +0 -99
 - data/lib/paginated/sorting.rb +0 -12
 - data/lib/paginated/spreadsheet.rb +0 -61
 
    
        checksums.yaml
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            ---
         
     | 
| 
       2 
2 
     | 
    
         
             
            SHA256:
         
     | 
| 
       3 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       4 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 3 
     | 
    
         
            +
              metadata.gz: b9bcce808539f59666e9f47ac429c4fb081f8d1ead5152ceb9cf33ba7bcb1e00
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: 665b4534980a20527920130fb5b9593517f82ce0a7d30de05c0bbd756fa6f76a
         
     | 
| 
       5 
5 
     | 
    
         
             
            SHA512:
         
     | 
| 
       6 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       7 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 6 
     | 
    
         
            +
              metadata.gz: a680390d0db51559a570dc52d373b6388dd9487bd179a572f75224b9d2b6d036e16cae112ea8d07478890926f6b01b38db3d8ccbcf7e3952939f21abb4546b13
         
     | 
| 
      
 7 
     | 
    
         
            +
              data.tar.gz: 0a6e40dd565c4d6b7887bf7174bd6984b087f09785ea049ff67a95c3a36732bfd3b2516309e4b58a47d2647d1f2d8644746ec7939a08911e869940b5a0f3921c
         
     | 
    
        data/README.md
    CHANGED
    
    | 
         @@ -1,6 +1,7 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            # Paginated
         
     | 
| 
      
 1 
     | 
    
         
            +
            # Grape Paginated
         
     | 
| 
      
 2 
     | 
    
         
            +
            [](https://badge.fury.io/rb/paginated)
         
     | 
| 
       2 
3 
     | 
    
         | 
| 
       3 
     | 
    
         
            -
            Гем для пагинации и фильтрации  
     | 
| 
      
 4 
     | 
    
         
            +
            Гем для пагинации и фильтрации записей с возможностью формирования электронных таблиц (XLSX) на базе Grape.
         
     | 
| 
       4 
5 
     | 
    
         | 
| 
       5 
6 
     | 
    
         
             
            ## Установка
         
     | 
| 
       6 
7 
     | 
    
         | 
| 
         @@ -24,9 +25,12 @@ bundle 
     | 
|
| 
       24 
25 
     | 
    
         
             
            Например:
         
     | 
| 
       25 
26 
     | 
    
         | 
| 
       26 
27 
     | 
    
         
             
            ```
         
     | 
| 
       27 
     | 
    
         
            -
             
     | 
| 
       28 
     | 
    
         
            -
             
     | 
| 
       29 
     | 
    
         
            -
             
     | 
| 
      
 28 
     | 
    
         
            +
            get 'users' do
         
     | 
| 
      
 29 
     | 
    
         
            +
              paginated model: User,
         
     | 
| 
      
 30 
     | 
    
         
            +
                        entity: UserEntity,
         
     | 
| 
      
 31 
     | 
    
         
            +
                        search: %w[email name|ilike role|custom.for_role]
         
     | 
| 
      
 32 
     | 
    
         
            +
            end
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
       30 
34 
     | 
    
         
             
            ```
         
     | 
| 
       31 
35 
     | 
    
         | 
| 
       32 
36 
     | 
    
         
             
            Опции (с примерами):
         
     | 
| 
         @@ -70,3 +74,16 @@ paginated model: User, 
     | 
|
| 
       70 
74 
     | 
    
         
             
            - `sort_order` направление, по которому должна осуществляться сортировка (`asc/desc`).
         
     | 
| 
       71 
75 
     | 
    
         | 
| 
       72 
76 
     | 
    
         
             
            По умолчанию сортировка осуществляется по `id` записей в направлении `DESC`.
         
     | 
| 
      
 77 
     | 
    
         
            +
             
     | 
| 
      
 78 
     | 
    
         
            +
            ## Конфигурация
         
     | 
| 
      
 79 
     | 
    
         
            +
             
     | 
| 
      
 80 
     | 
    
         
            +
            Добавьте файл конфигурации `config/initializers/grape_paginated.rb` с содержимым:
         
     | 
| 
      
 81 
     | 
    
         
            +
             
     | 
| 
      
 82 
     | 
    
         
            +
            ```
         
     | 
| 
      
 83 
     | 
    
         
            +
            GrapePaginated::Configuration.configure do |config|
         
     | 
| 
      
 84 
     | 
    
         
            +
            end
         
     | 
| 
      
 85 
     | 
    
         
            +
            ```
         
     | 
| 
      
 86 
     | 
    
         
            +
             
     | 
| 
      
 87 
     | 
    
         
            +
            Доступные опции для конфигурирования:
         
     | 
| 
      
 88 
     | 
    
         
            +
             
     | 
| 
      
 89 
     | 
    
         
            +
            `spreadsheet_limit` - максимальный размер формируемой электронной таблицы. По умолчанию отстутствует.
         
     | 
| 
         @@ -39,15 +39,16 @@ module Grape 
     | 
|
| 
       39 
39 
     | 
    
         
             
                  end
         
     | 
| 
       40 
40 
     | 
    
         | 
| 
       41 
41 
     | 
    
         
             
                  def paginated_spreadsheet(opts)
         
     | 
| 
       42 
     | 
    
         
            -
                    Dir.mktmpdir do | 
     | 
| 
       43 
     | 
    
         
            -
                       
     | 
| 
      
 42 
     | 
    
         
            +
                    Dir.mktmpdir do |dir|
         
     | 
| 
      
 43 
     | 
    
         
            +
                      opts[:tempdir] = dir
         
     | 
| 
      
 44 
     | 
    
         
            +
                      file_path = Paginated.spreadsheet(**opts)
         
     | 
| 
       44 
45 
     | 
    
         | 
| 
       45 
46 
     | 
    
         
             
                      spreadsheet_file_headers File.basename(file_path)
         
     | 
| 
       46 
     | 
    
         
            -
                      File. 
     | 
| 
      
 47 
     | 
    
         
            +
                      File.read(file_path)
         
     | 
| 
       47 
48 
     | 
    
         
             
                    end
         
     | 
| 
       48 
49 
     | 
    
         
             
                  end
         
     | 
| 
       49 
50 
     | 
    
         | 
| 
       50 
     | 
    
         
            -
                  def spreadsheet_file_headers(filename) 
     | 
| 
      
 51 
     | 
    
         
            +
                  def spreadsheet_file_headers(filename)
         
     | 
| 
       51 
52 
     | 
    
         
             
                    header['Content-Type'] =
         
     | 
| 
       52 
53 
     | 
    
         
             
                      case File.extname(filename)
         
     | 
| 
       53 
54 
     | 
    
         
             
                      when '.csv'
         
     | 
| 
         @@ -0,0 +1,63 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module GrapePaginated
         
     | 
| 
      
 2 
     | 
    
         
            +
              module Args
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
                private
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
                def handle_args(**args)
         
     | 
| 
      
 7 
     | 
    
         
            +
                  # обрабатываемая Rails модель
         
     | 
| 
      
 8 
     | 
    
         
            +
                  @model = args[:model]
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                  # параметры запроса и текущий пользователь
         
     | 
| 
      
 11 
     | 
    
         
            +
                  @params = args[:params].stringify_keys
         
     | 
| 
      
 12 
     | 
    
         
            +
                  @current_user = args[:current_user]
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                  # поля, по которым возможен поиск
         
     | 
| 
      
 15 
     | 
    
         
            +
                  @search_fields = args[:search]
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                  # сериализация - через Grape Entity или список полей
         
     | 
| 
      
 18 
     | 
    
         
            +
                  @grape_entity = args[:entity]
         
     | 
| 
      
 19 
     | 
    
         
            +
                  @fields = args[:fields]
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                  # Rails scopes для применения
         
     | 
| 
      
 22 
     | 
    
         
            +
                  @scopes = args[:scopes] || {}
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                  # offset / limit
         
     | 
| 
      
 25 
     | 
    
         
            +
                  @offset = @params['offset'].to_i
         
     | 
| 
      
 26 
     | 
    
         
            +
                  @limit = @params['limit'] || 20
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
                  # требуемый список полей для коллекции
         
     | 
| 
      
 29 
     | 
    
         
            +
                  @only_columns = args[:only_columns]
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
                  # список полей для эл. таблицы
         
     | 
| 
      
 32 
     | 
    
         
            +
                  @spreadsheet_columns = args[:spreadsheet_columns]
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
                  # сортировка
         
     | 
| 
      
 35 
     | 
    
         
            +
                  @sort_by = @params['sort_by'] || :id
         
     | 
| 
      
 36 
     | 
    
         
            +
                  @sort_order = @params['sort_order'] || :desc
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
                  # подсчет кол-ва записей
         
     | 
| 
      
 39 
     | 
    
         
            +
                  @objects_count = records_count
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
                  # временная директория (для генерации файлов)
         
     | 
| 
      
 42 
     | 
    
         
            +
                  @tempdir = args[:tempdir]
         
     | 
| 
      
 43 
     | 
    
         
            +
                end
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
                def records_count
         
     | 
| 
      
 46 
     | 
    
         
            +
                  # получение кол-ва записей из кеша
         
     | 
| 
      
 47 
     | 
    
         
            +
                  cache_key = "#{@model}_records_count"
         
     | 
| 
      
 48 
     | 
    
         
            +
                  cached = Rails.cache.read(cache_key)
         
     | 
| 
      
 49 
     | 
    
         
            +
                  return cached if cached
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
                  # получение кол-ва записей из запроса к БД
         
     | 
| 
      
 52 
     | 
    
         
            +
                  count = @model.merge(@scopes).count(:id)
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
                  # кеширование кол-ва записей при превышении порогового значения
         
     | 
| 
      
 55 
     | 
    
         
            +
                  if count >= 1_000
         
     | 
| 
      
 56 
     | 
    
         
            +
                    Rails.cache.write(cache_key, count, expires_in: 30.minutes)
         
     | 
| 
      
 57 
     | 
    
         
            +
                  end
         
     | 
| 
      
 58 
     | 
    
         
            +
             
     | 
| 
      
 59 
     | 
    
         
            +
                  count
         
     | 
| 
      
 60 
     | 
    
         
            +
                end
         
     | 
| 
      
 61 
     | 
    
         
            +
             
     | 
| 
      
 62 
     | 
    
         
            +
              end
         
     | 
| 
      
 63 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,58 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module GrapePaginated
         
     | 
| 
      
 2 
     | 
    
         
            +
              module Collection
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
                def collection
         
     | 
| 
      
 5 
     | 
    
         
            +
                  if @objects_count > 0
         
     | 
| 
      
 6 
     | 
    
         
            +
                    search
         
     | 
| 
      
 7 
     | 
    
         
            +
                    serialize
         
     | 
| 
      
 8 
     | 
    
         
            +
                  else
         
     | 
| 
      
 9 
     | 
    
         
            +
                    @objects = []
         
     | 
| 
      
 10 
     | 
    
         
            +
                  end
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                  # результат с пагинацией
         
     | 
| 
      
 13 
     | 
    
         
            +
                  { count: @objects_count, objects: @objects }
         
     | 
| 
      
 14 
     | 
    
         
            +
                end
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
                private
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                def serialize
         
     | 
| 
      
 19 
     | 
    
         
            +
                  # коллекция записей ActiveRecord для применения аггрегирования
         
     | 
| 
      
 20 
     | 
    
         
            +
                  list = @objects || @model.unscoped.merge(@scopes)
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                  # применение сортировки и пагинации к коллекции записей
         
     | 
| 
      
 23 
     | 
    
         
            +
                  @objects = list.offset(@offset).merge(sort_proc).limit(@limit)
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                  # сериализация с помощью переданных полей или сериалайзера
         
     | 
| 
      
 26 
     | 
    
         
            +
                  if @fields
         
     | 
| 
      
 27 
     | 
    
         
            +
                    serialize_with_fields
         
     | 
| 
      
 28 
     | 
    
         
            +
                  elsif @grape_entity
         
     | 
| 
      
 29 
     | 
    
         
            +
                    serialize_with_entity
         
     | 
| 
      
 30 
     | 
    
         
            +
                  end
         
     | 
| 
      
 31 
     | 
    
         
            +
                end
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                def serialize_with_fields
         
     | 
| 
      
 34 
     | 
    
         
            +
                  # добавление ID в список полей по умолчанию
         
     | 
| 
      
 35 
     | 
    
         
            +
                  @fields.push(:id)
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
                  # список массивов значений
         
     | 
| 
      
 38 
     | 
    
         
            +
                  @objects = @objects.map { |i| obtain_fields_values(i) }
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
                  # трансформация массивов значений в объекты (ключ-значение)
         
     | 
| 
      
 41 
     | 
    
         
            +
                  @objects = @objects.map { |i| @fields.zip(i).to_h }
         
     | 
| 
      
 42 
     | 
    
         
            +
                end
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
                def serialize_with_entity
         
     | 
| 
      
 45 
     | 
    
         
            +
                  opts = { current_user: @current_user }
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
                  # требуемый список полей (если был передан)
         
     | 
| 
      
 48 
     | 
    
         
            +
                  opts[:only] = @only_columns if @only_columns
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
                  @objects = @objects.map { |i| @grape_entity.represent(i, opts).as_json }
         
     | 
| 
      
 51 
     | 
    
         
            +
                end
         
     | 
| 
      
 52 
     | 
    
         
            +
             
     | 
| 
      
 53 
     | 
    
         
            +
                def obtain_fields_values(record)
         
     | 
| 
      
 54 
     | 
    
         
            +
                  @fields.map { |i| record.send(i) }
         
     | 
| 
      
 55 
     | 
    
         
            +
                end
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
              end
         
     | 
| 
      
 58 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,20 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module GrapePaginated
         
     | 
| 
      
 2 
     | 
    
         
            +
              class Configuration
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
                attr_accessor :spreadsheet_limit
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
                def spreadsheet_limit
         
     | 
| 
      
 7 
     | 
    
         
            +
                  @spreadsheet_limit || Float::INFINITY
         
     | 
| 
      
 8 
     | 
    
         
            +
                end
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                def self.configure
         
     | 
| 
      
 11 
     | 
    
         
            +
                  yield(config)
         
     | 
| 
      
 12 
     | 
    
         
            +
                  config
         
     | 
| 
      
 13 
     | 
    
         
            +
                end
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                def self.config
         
     | 
| 
      
 16 
     | 
    
         
            +
                  @config ||= Configuration.new
         
     | 
| 
      
 17 
     | 
    
         
            +
                end
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
              end
         
     | 
| 
      
 20 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,99 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module GrapePaginated
         
     | 
| 
      
 2 
     | 
    
         
            +
              module Search
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
                private
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
                def search
         
     | 
| 
      
 7 
     | 
    
         
            +
                  @search_fields&.each do |field|
         
     | 
| 
      
 8 
     | 
    
         
            +
                    # коллекция записей для дальнейшей фильтрации
         
     | 
| 
      
 9 
     | 
    
         
            +
                    list = @objects || @model.unscoped.merge(@scopes)
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                    # оператор и значение для поиска
         
     | 
| 
      
 12 
     | 
    
         
            +
                    operator, value = search_operands(field)
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                    # пропускаем, если параметр для поиска не передан
         
     | 
| 
      
 15 
     | 
    
         
            +
                    next if value.blank? || value == 'null'
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                    # кастомный поиск
         
     | 
| 
      
 18 
     | 
    
         
            +
                    if operator.include?('custom') && value.present?
         
     | 
| 
      
 19 
     | 
    
         
            +
                      # название скоупа из модели, который нужно применить
         
     | 
| 
      
 20 
     | 
    
         
            +
                      scope_name = operator.split('.')[1]
         
     | 
| 
      
 21 
     | 
    
         
            +
                      # применение скоупа
         
     | 
| 
      
 22 
     | 
    
         
            +
                      @objects = list.send(scope_name, value)
         
     | 
| 
      
 23 
     | 
    
         
            +
                      @objects_count = @objects.count
         
     | 
| 
      
 24 
     | 
    
         
            +
                      next
         
     | 
| 
      
 25 
     | 
    
         
            +
                    end
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                    # форматирование кавычек
         
     | 
| 
      
 28 
     | 
    
         
            +
                    if operator != 'IN' && !@model.defined_enums.key?(field)
         
     | 
| 
      
 29 
     | 
    
         
            +
                      value = quotations_formatting(value)
         
     | 
| 
      
 30 
     | 
    
         
            +
                    end
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
                    if field.include?('.')
         
     | 
| 
      
 33 
     | 
    
         
            +
                      # нужно приджойнить таблицу
         
     | 
| 
      
 34 
     | 
    
         
            +
                      join_assoc, field = field.split('.')
         
     | 
| 
      
 35 
     | 
    
         
            +
                      table = join_assoc.tableize
         
     | 
| 
      
 36 
     | 
    
         
            +
                      list = list.joins(join_assoc.to_sym)
         
     | 
| 
      
 37 
     | 
    
         
            +
                    else
         
     | 
| 
      
 38 
     | 
    
         
            +
                      table = @model.table_name
         
     | 
| 
      
 39 
     | 
    
         
            +
                      field = field.split('|')[0]
         
     | 
| 
      
 40 
     | 
    
         
            +
                    end
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
                    query = where_query(table, field, operator, value)
         
     | 
| 
      
 43 
     | 
    
         
            +
                    @objects = list.where(query)
         
     | 
| 
      
 44 
     | 
    
         
            +
                    @objects_count = @objects.count
         
     | 
| 
      
 45 
     | 
    
         
            +
                  end
         
     | 
| 
      
 46 
     | 
    
         
            +
                end
         
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
      
 48 
     | 
    
         
            +
                def search_operands(field)
         
     | 
| 
      
 49 
     | 
    
         
            +
                  value = default_param_value(field)
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
                  # WHERE query operator
         
     | 
| 
      
 52 
     | 
    
         
            +
                  operator = field.split('|').size > 1 ? field.split('|').last : '='
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
                  # условие для поиска ILIKE
         
     | 
| 
      
 55 
     | 
    
         
            +
                  value = "%#{value}%" if operator == 'ilike' && value.present?
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
                  # проверка мульти-поиска по параметру с массивом
         
     | 
| 
      
 58 
     | 
    
         
            +
                  if operator == 'multi' && !value.blank?
         
     | 
| 
      
 59 
     | 
    
         
            +
                    operator = 'IN'
         
     | 
| 
      
 60 
     | 
    
         
            +
                    value = "(#{value.join(', ')})"
         
     | 
| 
      
 61 
     | 
    
         
            +
                  end
         
     | 
| 
      
 62 
     | 
    
         
            +
             
     | 
| 
      
 63 
     | 
    
         
            +
                  # проверка диапазона (MIN/MAX)
         
     | 
| 
      
 64 
     | 
    
         
            +
                  if %w[min max].include?(operator)
         
     | 
| 
      
 65 
     | 
    
         
            +
                    range_field = field.split('.').last.split(':')[0].try { |i| i.split('|')[0] }
         
     | 
| 
      
 66 
     | 
    
         
            +
                    value = @params["#{range_field}_#{operator}"]
         
     | 
| 
      
 67 
     | 
    
         
            +
                    operator = operator == 'min' ? '>=' : '<='
         
     | 
| 
      
 68 
     | 
    
         
            +
                  end
         
     | 
| 
      
 69 
     | 
    
         
            +
             
     | 
| 
      
 70 
     | 
    
         
            +
                  # check array operator
         
     | 
| 
      
 71 
     | 
    
         
            +
                  if operator == 'array' && value.present?
         
     | 
| 
      
 72 
     | 
    
         
            +
                    operator = '='
         
     | 
| 
      
 73 
     | 
    
         
            +
                    value = "{#{value}}"
         
     | 
| 
      
 74 
     | 
    
         
            +
                  end
         
     | 
| 
      
 75 
     | 
    
         
            +
             
     | 
| 
      
 76 
     | 
    
         
            +
                  [operator, value]
         
     | 
| 
      
 77 
     | 
    
         
            +
                end
         
     | 
| 
      
 78 
     | 
    
         
            +
             
     | 
| 
      
 79 
     | 
    
         
            +
                def default_param_value(field)
         
     | 
| 
      
 80 
     | 
    
         
            +
                  # название ключа-поля без оператора (напр. ilike)
         
     | 
| 
      
 81 
     | 
    
         
            +
                  key = field.split('|')[0]
         
     | 
| 
      
 82 
     | 
    
         
            +
             
     | 
| 
      
 83 
     | 
    
         
            +
                  @params[key]
         
     | 
| 
      
 84 
     | 
    
         
            +
                end
         
     | 
| 
      
 85 
     | 
    
         
            +
             
     | 
| 
      
 86 
     | 
    
         
            +
                def where_query(table, field, operator, value)
         
     | 
| 
      
 87 
     | 
    
         
            +
                  "#{table}.#{field} #{operator} #{value}"
         
     | 
| 
      
 88 
     | 
    
         
            +
                end
         
     | 
| 
      
 89 
     | 
    
         
            +
             
     | 
| 
      
 90 
     | 
    
         
            +
                def quotations_formatting(string)
         
     | 
| 
      
 91 
     | 
    
         
            +
                  # удаление одинарных кавычек (напр. внутри строки)
         
     | 
| 
      
 92 
     | 
    
         
            +
                  value = string.to_s.gsub("'", '')
         
     | 
| 
      
 93 
     | 
    
         
            +
             
     | 
| 
      
 94 
     | 
    
         
            +
                  # добавление одинарных кавычек вокруг строки
         
     | 
| 
      
 95 
     | 
    
         
            +
                  "'#{value}'"
         
     | 
| 
      
 96 
     | 
    
         
            +
                end
         
     | 
| 
      
 97 
     | 
    
         
            +
             
     | 
| 
      
 98 
     | 
    
         
            +
              end
         
     | 
| 
      
 99 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,69 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'fast_excel'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module GrapePaginated
         
     | 
| 
      
 4 
     | 
    
         
            +
              module Spreadsheet
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
                def spreadsheet
         
     | 
| 
      
 7 
     | 
    
         
            +
                  # поиск и фильтрация
         
     | 
| 
      
 8 
     | 
    
         
            +
                  search
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                  # коллекция записей ActiveRecord для формирования эл. таблицы
         
     | 
| 
      
 11 
     | 
    
         
            +
                  records = @objects || @model.unscoped.merge(@scopes)
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                  # exception в случае превышения лимита записей
         
     | 
| 
      
 14 
     | 
    
         
            +
                  raise StandardError.new('Кол-во записей превышает заданный лимит') if records.count > spreadsheet_limit
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
                  # формирования файла эл. таблицы
         
     | 
| 
      
 17 
     | 
    
         
            +
                  generate_spreadsheet(records)
         
     | 
| 
      
 18 
     | 
    
         
            +
                end
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                private
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                def spreadsheet_limit
         
     | 
| 
      
 23 
     | 
    
         
            +
                  GrapePaginated::Configuration.config.spreadsheet_limit
         
     | 
| 
      
 24 
     | 
    
         
            +
                end
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
                def generate_spreadsheet(records)
         
     | 
| 
      
 27 
     | 
    
         
            +
                  filepath = "#{@tempdir}/#{Time.now.strftime('%Y%m%d_%H%M%S')}.xlsx"
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                  # создание таблицы и ее конфигурация
         
     | 
| 
      
 30 
     | 
    
         
            +
                  workbook = FastExcel.open(filepath, constant_memory: true)
         
     | 
| 
      
 31 
     | 
    
         
            +
                  workbook.default_format.set(
         
     | 
| 
      
 32 
     | 
    
         
            +
                    font_size: 0,
         
     | 
| 
      
 33 
     | 
    
         
            +
                    font_family: 'Arial'
         
     | 
| 
      
 34 
     | 
    
         
            +
                  )
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
                  # стили
         
     | 
| 
      
 37 
     | 
    
         
            +
                  bold = workbook.bold_format
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
                  # лист
         
     | 
| 
      
 40 
     | 
    
         
            +
                  worksheet = workbook.add_worksheet('Основной')
         
     | 
| 
      
 41 
     | 
    
         
            +
                  worksheet.auto_width = true
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
                  # заголовки
         
     | 
| 
      
 44 
     | 
    
         
            +
                  worksheet.append_row(spreadsheet_titles, bold)
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
                  # содержимое
         
     | 
| 
      
 47 
     | 
    
         
            +
                  cols = spreadsheet_columns
         
     | 
| 
      
 48 
     | 
    
         
            +
                  records.order(:id).each do |record|
         
     | 
| 
      
 49 
     | 
    
         
            +
                    values = cols.map { |col| record.send(col) }
         
     | 
| 
      
 50 
     | 
    
         
            +
                    worksheet.append_row(values)
         
     | 
| 
      
 51 
     | 
    
         
            +
                  end
         
     | 
| 
      
 52 
     | 
    
         
            +
             
     | 
| 
      
 53 
     | 
    
         
            +
                  # закрытие/сохранение файла
         
     | 
| 
      
 54 
     | 
    
         
            +
                  workbook.close
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
      
 56 
     | 
    
         
            +
                  # путь до файла для дальнейшей обработки
         
     | 
| 
      
 57 
     | 
    
         
            +
                  filepath
         
     | 
| 
      
 58 
     | 
    
         
            +
                end
         
     | 
| 
      
 59 
     | 
    
         
            +
             
     | 
| 
      
 60 
     | 
    
         
            +
                def spreadsheet_titles
         
     | 
| 
      
 61 
     | 
    
         
            +
                  @spreadsheet_columns.map { |i| i['title'] }
         
     | 
| 
      
 62 
     | 
    
         
            +
                end
         
     | 
| 
      
 63 
     | 
    
         
            +
             
     | 
| 
      
 64 
     | 
    
         
            +
                def spreadsheet_columns
         
     | 
| 
      
 65 
     | 
    
         
            +
                  @spreadsheet_columns.map { |i| i['column'] }
         
     | 
| 
      
 66 
     | 
    
         
            +
                end
         
     | 
| 
      
 67 
     | 
    
         
            +
             
     | 
| 
      
 68 
     | 
    
         
            +
              end
         
     | 
| 
      
 69 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/paginated.rb
    CHANGED
    
    | 
         @@ -1,18 +1,18 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            require ' 
     | 
| 
       2 
     | 
    
         
            -
            require 'paginated/ 
     | 
| 
       3 
     | 
    
         
            -
            require 'paginated/ 
     | 
| 
       4 
     | 
    
         
            -
            require 'paginated/ 
     | 
| 
       5 
     | 
    
         
            -
            require 'paginated/ 
     | 
| 
       6 
     | 
    
         
            -
             
     | 
| 
       7 
     | 
    
         
            -
            require ' 
     | 
| 
      
 1 
     | 
    
         
            +
            require 'grape/dsl'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'grape-paginated/args'
         
     | 
| 
      
 3 
     | 
    
         
            +
            require 'grape-paginated/collection'
         
     | 
| 
      
 4 
     | 
    
         
            +
            require 'grape-paginated/configuration'
         
     | 
| 
      
 5 
     | 
    
         
            +
            require 'grape-paginated/search'
         
     | 
| 
      
 6 
     | 
    
         
            +
            require 'grape-paginated/sorting'
         
     | 
| 
      
 7 
     | 
    
         
            +
            require 'grape-paginated/spreadsheet'
         
     | 
| 
       8 
8 
     | 
    
         | 
| 
       9 
9 
     | 
    
         
             
            class Paginated
         
     | 
| 
       10 
10 
     | 
    
         | 
| 
       11 
     | 
    
         
            -
              include  
     | 
| 
       12 
     | 
    
         
            -
              include Collection
         
     | 
| 
       13 
     | 
    
         
            -
              include Search
         
     | 
| 
       14 
     | 
    
         
            -
              include Sorting
         
     | 
| 
       15 
     | 
    
         
            -
              include Spreadsheet
         
     | 
| 
      
 11 
     | 
    
         
            +
              include GrapePaginated::Args
         
     | 
| 
      
 12 
     | 
    
         
            +
              include GrapePaginated::Collection
         
     | 
| 
      
 13 
     | 
    
         
            +
              include GrapePaginated::Search
         
     | 
| 
      
 14 
     | 
    
         
            +
              include GrapePaginated::Sorting
         
     | 
| 
      
 15 
     | 
    
         
            +
              include GrapePaginated::Spreadsheet
         
     | 
| 
       16 
16 
     | 
    
         | 
| 
       17 
17 
     | 
    
         
             
              def initialize(**args)
         
     | 
| 
       18 
18 
     | 
    
         
             
                handle_args(**args)
         
     | 
    
        metadata
    CHANGED
    
    | 
         @@ -1,71 +1,71 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            --- !ruby/object:Gem::Specification
         
     | 
| 
       2 
2 
     | 
    
         
             
            name: paginated
         
     | 
| 
       3 
3 
     | 
    
         
             
            version: !ruby/object:Gem::Version
         
     | 
| 
       4 
     | 
    
         
            -
              version: 1.0. 
     | 
| 
      
 4 
     | 
    
         
            +
              version: 1.0.9
         
     | 
| 
       5 
5 
     | 
    
         
             
            platform: ruby
         
     | 
| 
       6 
6 
     | 
    
         
             
            authors:
         
     | 
| 
       7 
7 
     | 
    
         
             
            - Павел Бабин
         
     | 
| 
       8 
8 
     | 
    
         
             
            autorequire:
         
     | 
| 
       9 
9 
     | 
    
         
             
            bindir: bin
         
     | 
| 
       10 
10 
     | 
    
         
             
            cert_chain: []
         
     | 
| 
       11 
     | 
    
         
            -
            date: 2024-02- 
     | 
| 
      
 11 
     | 
    
         
            +
            date: 2024-02-27 00:00:00.000000000 Z
         
     | 
| 
       12 
12 
     | 
    
         
             
            dependencies:
         
     | 
| 
       13 
13 
     | 
    
         
             
            - !ruby/object:Gem::Dependency
         
     | 
| 
       14 
     | 
    
         
            -
              name:  
     | 
| 
      
 14 
     | 
    
         
            +
              name: fast_excel
         
     | 
| 
       15 
15 
     | 
    
         
             
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
       16 
16 
     | 
    
         
             
                requirements:
         
     | 
| 
       17 
17 
     | 
    
         
             
                - - "~>"
         
     | 
| 
       18 
18 
     | 
    
         
             
                  - !ruby/object:Gem::Version
         
     | 
| 
       19 
     | 
    
         
            -
                    version:  
     | 
| 
      
 19 
     | 
    
         
            +
                    version: 0.5.0
         
     | 
| 
       20 
20 
     | 
    
         
             
              type: :runtime
         
     | 
| 
       21 
21 
     | 
    
         
             
              prerelease: false
         
     | 
| 
       22 
22 
     | 
    
         
             
              version_requirements: !ruby/object:Gem::Requirement
         
     | 
| 
       23 
23 
     | 
    
         
             
                requirements:
         
     | 
| 
       24 
24 
     | 
    
         
             
                - - "~>"
         
     | 
| 
       25 
25 
     | 
    
         
             
                  - !ruby/object:Gem::Version
         
     | 
| 
       26 
     | 
    
         
            -
                    version:  
     | 
| 
      
 26 
     | 
    
         
            +
                    version: 0.5.0
         
     | 
| 
       27 
27 
     | 
    
         
             
            - !ruby/object:Gem::Dependency
         
     | 
| 
       28 
     | 
    
         
            -
              name: grape 
     | 
| 
      
 28 
     | 
    
         
            +
              name: grape
         
     | 
| 
       29 
29 
     | 
    
         
             
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
       30 
30 
     | 
    
         
             
                requirements:
         
     | 
| 
       31 
31 
     | 
    
         
             
                - - "~>"
         
     | 
| 
       32 
32 
     | 
    
         
             
                  - !ruby/object:Gem::Version
         
     | 
| 
       33 
     | 
    
         
            -
                    version:  
     | 
| 
      
 33 
     | 
    
         
            +
                    version: 2.0.0
         
     | 
| 
       34 
34 
     | 
    
         
             
              type: :runtime
         
     | 
| 
       35 
35 
     | 
    
         
             
              prerelease: false
         
     | 
| 
       36 
36 
     | 
    
         
             
              version_requirements: !ruby/object:Gem::Requirement
         
     | 
| 
       37 
37 
     | 
    
         
             
                requirements:
         
     | 
| 
       38 
38 
     | 
    
         
             
                - - "~>"
         
     | 
| 
       39 
39 
     | 
    
         
             
                  - !ruby/object:Gem::Version
         
     | 
| 
       40 
     | 
    
         
            -
                    version:  
     | 
| 
      
 40 
     | 
    
         
            +
                    version: 2.0.0
         
     | 
| 
       41 
41 
     | 
    
         
             
            - !ruby/object:Gem::Dependency
         
     | 
| 
       42 
     | 
    
         
            -
              name:  
     | 
| 
      
 42 
     | 
    
         
            +
              name: grape-entity
         
     | 
| 
       43 
43 
     | 
    
         
             
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
       44 
44 
     | 
    
         
             
                requirements:
         
     | 
| 
       45 
45 
     | 
    
         
             
                - - "~>"
         
     | 
| 
       46 
46 
     | 
    
         
             
                  - !ruby/object:Gem::Version
         
     | 
| 
       47 
     | 
    
         
            -
                    version:  
     | 
| 
      
 47 
     | 
    
         
            +
                    version: 1.0.0
         
     | 
| 
       48 
48 
     | 
    
         
             
              type: :runtime
         
     | 
| 
       49 
49 
     | 
    
         
             
              prerelease: false
         
     | 
| 
       50 
50 
     | 
    
         
             
              version_requirements: !ruby/object:Gem::Requirement
         
     | 
| 
       51 
51 
     | 
    
         
             
                requirements:
         
     | 
| 
       52 
52 
     | 
    
         
             
                - - "~>"
         
     | 
| 
       53 
53 
     | 
    
         
             
                  - !ruby/object:Gem::Version
         
     | 
| 
       54 
     | 
    
         
            -
                    version:  
     | 
| 
      
 54 
     | 
    
         
            +
                    version: 1.0.0
         
     | 
| 
       55 
55 
     | 
    
         
             
            - !ruby/object:Gem::Dependency
         
     | 
| 
       56 
     | 
    
         
            -
              name:  
     | 
| 
      
 56 
     | 
    
         
            +
              name: rails
         
     | 
| 
       57 
57 
     | 
    
         
             
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
       58 
58 
     | 
    
         
             
                requirements:
         
     | 
| 
       59 
59 
     | 
    
         
             
                - - "~>"
         
     | 
| 
       60 
60 
     | 
    
         
             
                  - !ruby/object:Gem::Version
         
     | 
| 
       61 
     | 
    
         
            -
                    version:  
     | 
| 
      
 61 
     | 
    
         
            +
                    version: '7.0'
         
     | 
| 
       62 
62 
     | 
    
         
             
              type: :runtime
         
     | 
| 
       63 
63 
     | 
    
         
             
              prerelease: false
         
     | 
| 
       64 
64 
     | 
    
         
             
              version_requirements: !ruby/object:Gem::Requirement
         
     | 
| 
       65 
65 
     | 
    
         
             
                requirements:
         
     | 
| 
       66 
66 
     | 
    
         
             
                - - "~>"
         
     | 
| 
       67 
67 
     | 
    
         
             
                  - !ruby/object:Gem::Version
         
     | 
| 
       68 
     | 
    
         
            -
                    version:  
     | 
| 
      
 68 
     | 
    
         
            +
                    version: '7.0'
         
     | 
| 
       69 
69 
     | 
    
         
             
            description: Простая пагинация записей, поиск и формирование эл. таблиц для API на
         
     | 
| 
       70 
70 
     | 
    
         
             
              базе Grape
         
     | 
| 
       71 
71 
     | 
    
         
             
            email: babin359@gmail.com
         
     | 
| 
         @@ -74,17 +74,19 @@ extensions: [] 
     | 
|
| 
       74 
74 
     | 
    
         
             
            extra_rdoc_files: []
         
     | 
| 
       75 
75 
     | 
    
         
             
            files:
         
     | 
| 
       76 
76 
     | 
    
         
             
            - README.md
         
     | 
| 
       77 
     | 
    
         
            -
            - lib/ 
     | 
| 
      
 77 
     | 
    
         
            +
            - lib/grape-paginated/args.rb
         
     | 
| 
      
 78 
     | 
    
         
            +
            - lib/grape-paginated/collection.rb
         
     | 
| 
      
 79 
     | 
    
         
            +
            - lib/grape-paginated/configuration.rb
         
     | 
| 
      
 80 
     | 
    
         
            +
            - lib/grape-paginated/search.rb
         
     | 
| 
      
 81 
     | 
    
         
            +
            - lib/grape-paginated/sorting.rb
         
     | 
| 
      
 82 
     | 
    
         
            +
            - lib/grape-paginated/spreadsheet.rb
         
     | 
| 
      
 83 
     | 
    
         
            +
            - lib/grape/dsl.rb
         
     | 
| 
       78 
84 
     | 
    
         
             
            - lib/paginated.rb
         
     | 
| 
       79 
     | 
    
         
            -
            - lib/paginated/args_andling.rb
         
     | 
| 
       80 
     | 
    
         
            -
            - lib/paginated/collection.rb
         
     | 
| 
       81 
     | 
    
         
            -
            - lib/paginated/search.rb
         
     | 
| 
       82 
     | 
    
         
            -
            - lib/paginated/sorting.rb
         
     | 
| 
       83 
     | 
    
         
            -
            - lib/paginated/spreadsheet.rb
         
     | 
| 
       84 
85 
     | 
    
         
             
            homepage:
         
     | 
| 
       85 
86 
     | 
    
         
             
            licenses:
         
     | 
| 
       86 
87 
     | 
    
         
             
            - MIT
         
     | 
| 
       87 
     | 
    
         
            -
            metadata: 
     | 
| 
      
 88 
     | 
    
         
            +
            metadata:
         
     | 
| 
      
 89 
     | 
    
         
            +
              rubygems_mfa_required: 'true'
         
     | 
| 
       88 
90 
     | 
    
         
             
            post_install_message:
         
     | 
| 
       89 
91 
     | 
    
         
             
            rdoc_options: []
         
     | 
| 
       90 
92 
     | 
    
         
             
            require_paths:
         
     | 
| 
         @@ -93,14 +95,14 @@ required_ruby_version: !ruby/object:Gem::Requirement 
     | 
|
| 
       93 
95 
     | 
    
         
             
              requirements:
         
     | 
| 
       94 
96 
     | 
    
         
             
              - - ">="
         
     | 
| 
       95 
97 
     | 
    
         
             
                - !ruby/object:Gem::Version
         
     | 
| 
       96 
     | 
    
         
            -
                  version: 3. 
     | 
| 
      
 98 
     | 
    
         
            +
                  version: 3.1.0
         
     | 
| 
       97 
99 
     | 
    
         
             
            required_rubygems_version: !ruby/object:Gem::Requirement
         
     | 
| 
       98 
100 
     | 
    
         
             
              requirements:
         
     | 
| 
       99 
101 
     | 
    
         
             
              - - ">="
         
     | 
| 
       100 
102 
     | 
    
         
             
                - !ruby/object:Gem::Version
         
     | 
| 
       101 
103 
     | 
    
         
             
                  version: '0'
         
     | 
| 
       102 
104 
     | 
    
         
             
            requirements: []
         
     | 
| 
       103 
     | 
    
         
            -
            rubygems_version: 3. 
     | 
| 
      
 105 
     | 
    
         
            +
            rubygems_version: 3.4.10
         
     | 
| 
       104 
106 
     | 
    
         
             
            signing_key:
         
     | 
| 
       105 
107 
     | 
    
         
             
            specification_version: 4
         
     | 
| 
       106 
108 
     | 
    
         
             
            summary: Пагинация для API на базе Grape
         
     | 
| 
         @@ -1,63 +0,0 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            module ArgsHandling
         
     | 
| 
       2 
     | 
    
         
            -
             
     | 
| 
       3 
     | 
    
         
            -
              extend ActiveSupport::Concern
         
     | 
| 
       4 
     | 
    
         
            -
             
     | 
| 
       5 
     | 
    
         
            -
              private
         
     | 
| 
       6 
     | 
    
         
            -
             
     | 
| 
       7 
     | 
    
         
            -
              def handle_args(**args)
         
     | 
| 
       8 
     | 
    
         
            -
                # обрабатываемая Rails модель
         
     | 
| 
       9 
     | 
    
         
            -
                @model = args[:model]
         
     | 
| 
       10 
     | 
    
         
            -
             
     | 
| 
       11 
     | 
    
         
            -
                # параметры запроса и текущий пользователь
         
     | 
| 
       12 
     | 
    
         
            -
                @params = args[:params].stringify_keys
         
     | 
| 
       13 
     | 
    
         
            -
                @current_user = args[:current_user]
         
     | 
| 
       14 
     | 
    
         
            -
             
     | 
| 
       15 
     | 
    
         
            -
                # поля, по которым возможен поиск
         
     | 
| 
       16 
     | 
    
         
            -
                @search_fields = args[:search]
         
     | 
| 
       17 
     | 
    
         
            -
             
     | 
| 
       18 
     | 
    
         
            -
                # сериализация - через Grape Entity или список полей
         
     | 
| 
       19 
     | 
    
         
            -
                @grape_entity = args[:entity]
         
     | 
| 
       20 
     | 
    
         
            -
                @fields = args[:fields]
         
     | 
| 
       21 
     | 
    
         
            -
             
     | 
| 
       22 
     | 
    
         
            -
                # Rails scopes для применения
         
     | 
| 
       23 
     | 
    
         
            -
                @scopes = args[:scopes] || {}
         
     | 
| 
       24 
     | 
    
         
            -
             
     | 
| 
       25 
     | 
    
         
            -
                # offset / limit
         
     | 
| 
       26 
     | 
    
         
            -
                @offset = @params['offset'].to_i
         
     | 
| 
       27 
     | 
    
         
            -
                @limit = @params['limit'] || 20
         
     | 
| 
       28 
     | 
    
         
            -
             
     | 
| 
       29 
     | 
    
         
            -
                # требуемый список полей для коллекции
         
     | 
| 
       30 
     | 
    
         
            -
                @only_columns = args[:only_columns]
         
     | 
| 
       31 
     | 
    
         
            -
             
     | 
| 
       32 
     | 
    
         
            -
                # список полей для эл. таблицы
         
     | 
| 
       33 
     | 
    
         
            -
                @spreadsheet_columns = args[:spreadsheet_columns]
         
     | 
| 
       34 
     | 
    
         
            -
             
     | 
| 
       35 
     | 
    
         
            -
                # сортировка
         
     | 
| 
       36 
     | 
    
         
            -
                @sort_by = @params['sort_by'] || :id
         
     | 
| 
       37 
     | 
    
         
            -
                @sort_order = @params['sort_order'] || :desc
         
     | 
| 
       38 
     | 
    
         
            -
             
     | 
| 
       39 
     | 
    
         
            -
                # подсчет кол-ва записей
         
     | 
| 
       40 
     | 
    
         
            -
                @objects_count = records_count
         
     | 
| 
       41 
     | 
    
         
            -
             
     | 
| 
       42 
     | 
    
         
            -
                # временная директория (для генерации файлов)
         
     | 
| 
       43 
     | 
    
         
            -
                @tempdir = args[:tempdir]
         
     | 
| 
       44 
     | 
    
         
            -
              end
         
     | 
| 
       45 
     | 
    
         
            -
             
     | 
| 
       46 
     | 
    
         
            -
              def records_count
         
     | 
| 
       47 
     | 
    
         
            -
                # получение кол-ва записей из кеша
         
     | 
| 
       48 
     | 
    
         
            -
                cache_key = "#{@model}_records_count"
         
     | 
| 
       49 
     | 
    
         
            -
                cached = Rails.cache.read(cache_key)
         
     | 
| 
       50 
     | 
    
         
            -
                return cached if cached
         
     | 
| 
       51 
     | 
    
         
            -
             
     | 
| 
       52 
     | 
    
         
            -
                # получение кол-ва записей из запроса к БД
         
     | 
| 
       53 
     | 
    
         
            -
                count = @model.merge(@scopes).count(:id)
         
     | 
| 
       54 
     | 
    
         
            -
             
     | 
| 
       55 
     | 
    
         
            -
                # кеширование кол-ва записей при превышении порогового значения
         
     | 
| 
       56 
     | 
    
         
            -
                if count >= 1_000
         
     | 
| 
       57 
     | 
    
         
            -
                  Rails.cache.write(cache_key, count, expires_in: 30.minutes)
         
     | 
| 
       58 
     | 
    
         
            -
                end
         
     | 
| 
       59 
     | 
    
         
            -
             
     | 
| 
       60 
     | 
    
         
            -
                count
         
     | 
| 
       61 
     | 
    
         
            -
              end
         
     | 
| 
       62 
     | 
    
         
            -
             
     | 
| 
       63 
     | 
    
         
            -
            end
         
     | 
    
        data/lib/paginated/collection.rb
    DELETED
    
    | 
         @@ -1,58 +0,0 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            module Collection
         
     | 
| 
       2 
     | 
    
         
            -
             
     | 
| 
       3 
     | 
    
         
            -
              extend ActiveSupport::Concern
         
     | 
| 
       4 
     | 
    
         
            -
             
     | 
| 
       5 
     | 
    
         
            -
              def collection
         
     | 
| 
       6 
     | 
    
         
            -
                if @objects_count > 0
         
     | 
| 
       7 
     | 
    
         
            -
                  search
         
     | 
| 
       8 
     | 
    
         
            -
                  serialize
         
     | 
| 
       9 
     | 
    
         
            -
                else
         
     | 
| 
       10 
     | 
    
         
            -
                  @objects = []
         
     | 
| 
       11 
     | 
    
         
            -
                end
         
     | 
| 
       12 
     | 
    
         
            -
             
     | 
| 
       13 
     | 
    
         
            -
                # результат с пагинацией
         
     | 
| 
       14 
     | 
    
         
            -
                { count: @objects_count, objects: @objects }
         
     | 
| 
       15 
     | 
    
         
            -
              end
         
     | 
| 
       16 
     | 
    
         
            -
             
     | 
| 
       17 
     | 
    
         
            -
              private
         
     | 
| 
       18 
     | 
    
         
            -
             
     | 
| 
       19 
     | 
    
         
            -
              def serialize
         
     | 
| 
       20 
     | 
    
         
            -
                # коллекция записей ActiveRecord для применения аггрегирования
         
     | 
| 
       21 
     | 
    
         
            -
                list = @objects || @model.unscoped.merge(@scopes)
         
     | 
| 
       22 
     | 
    
         
            -
             
     | 
| 
       23 
     | 
    
         
            -
                # применение сортировки и пагинации к коллекции записей
         
     | 
| 
       24 
     | 
    
         
            -
                @objects = list.offset(@offset).merge(sort_proc).limit(@limit)
         
     | 
| 
       25 
     | 
    
         
            -
             
     | 
| 
       26 
     | 
    
         
            -
                # сериализация с помощью переданных полей или сериалайзера
         
     | 
| 
       27 
     | 
    
         
            -
                if @fields
         
     | 
| 
       28 
     | 
    
         
            -
                  serialize_with_fields
         
     | 
| 
       29 
     | 
    
         
            -
                elsif @grape_entity
         
     | 
| 
       30 
     | 
    
         
            -
                  serialize_with_entity
         
     | 
| 
       31 
     | 
    
         
            -
                end
         
     | 
| 
       32 
     | 
    
         
            -
              end
         
     | 
| 
       33 
     | 
    
         
            -
             
     | 
| 
       34 
     | 
    
         
            -
              def serialize_with_fields
         
     | 
| 
       35 
     | 
    
         
            -
                # добавление ID в список полей по умолчанию
         
     | 
| 
       36 
     | 
    
         
            -
                @fields.push(:id)
         
     | 
| 
       37 
     | 
    
         
            -
             
     | 
| 
       38 
     | 
    
         
            -
                # список массивов значений
         
     | 
| 
       39 
     | 
    
         
            -
                @objects = @objects.map { |i| obtain_fields_values(i) }
         
     | 
| 
       40 
     | 
    
         
            -
             
     | 
| 
       41 
     | 
    
         
            -
                # трансформация массивов значений в объекты (ключ-значение)
         
     | 
| 
       42 
     | 
    
         
            -
                @objects = @objects.map { |i| @fields.zip(i).to_h }
         
     | 
| 
       43 
     | 
    
         
            -
              end
         
     | 
| 
       44 
     | 
    
         
            -
             
     | 
| 
       45 
     | 
    
         
            -
              def serialize_with_entity
         
     | 
| 
       46 
     | 
    
         
            -
                opts = { current_user: @current_user }
         
     | 
| 
       47 
     | 
    
         
            -
             
     | 
| 
       48 
     | 
    
         
            -
                # требуемый список полей (если был передан)
         
     | 
| 
       49 
     | 
    
         
            -
                opts[:only] = @only_columns if @only_columns
         
     | 
| 
       50 
     | 
    
         
            -
             
     | 
| 
       51 
     | 
    
         
            -
                @objects = @objects.map { |i| @grape_entity.represent(i, opts).as_json }
         
     | 
| 
       52 
     | 
    
         
            -
              end
         
     | 
| 
       53 
     | 
    
         
            -
             
     | 
| 
       54 
     | 
    
         
            -
              def obtain_fields_values(record)
         
     | 
| 
       55 
     | 
    
         
            -
                @fields.map { |i| record.send(i) }
         
     | 
| 
       56 
     | 
    
         
            -
              end
         
     | 
| 
       57 
     | 
    
         
            -
             
     | 
| 
       58 
     | 
    
         
            -
            end
         
     | 
    
        data/lib/paginated/search.rb
    DELETED
    
    | 
         @@ -1,99 +0,0 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            module Search
         
     | 
| 
       2 
     | 
    
         
            -
             
     | 
| 
       3 
     | 
    
         
            -
              extend ActiveSupport::Concern
         
     | 
| 
       4 
     | 
    
         
            -
             
     | 
| 
       5 
     | 
    
         
            -
              private
         
     | 
| 
       6 
     | 
    
         
            -
             
     | 
| 
       7 
     | 
    
         
            -
              def search
         
     | 
| 
       8 
     | 
    
         
            -
                @search_fields&.each do |field|
         
     | 
| 
       9 
     | 
    
         
            -
                  # коллекция записей для дальнейшей фильтрации
         
     | 
| 
       10 
     | 
    
         
            -
                  list = @objects || @model.unscoped.merge(@scopes)
         
     | 
| 
       11 
     | 
    
         
            -
             
     | 
| 
       12 
     | 
    
         
            -
                  # оператор и значение для поиска
         
     | 
| 
       13 
     | 
    
         
            -
                  operator, value = search_operands(field)
         
     | 
| 
       14 
     | 
    
         
            -
             
     | 
| 
       15 
     | 
    
         
            -
                  # пропускаем, если параметр для поиска не передан
         
     | 
| 
       16 
     | 
    
         
            -
                  next if value.blank? || value == 'null'
         
     | 
| 
       17 
     | 
    
         
            -
             
     | 
| 
       18 
     | 
    
         
            -
                  # кастомный поиск
         
     | 
| 
       19 
     | 
    
         
            -
                  if operator.include?('custom') && value.present?
         
     | 
| 
       20 
     | 
    
         
            -
                    # название скоупа из модели, который нужно применить
         
     | 
| 
       21 
     | 
    
         
            -
                    scope_name = operator.split('.')[1]
         
     | 
| 
       22 
     | 
    
         
            -
                    # применение скоупа
         
     | 
| 
       23 
     | 
    
         
            -
                    @objects = list.send(scope_name, value)
         
     | 
| 
       24 
     | 
    
         
            -
                    @objects_count = @objects.count
         
     | 
| 
       25 
     | 
    
         
            -
                    next
         
     | 
| 
       26 
     | 
    
         
            -
                  end
         
     | 
| 
       27 
     | 
    
         
            -
             
     | 
| 
       28 
     | 
    
         
            -
                  # форматирование кавычек
         
     | 
| 
       29 
     | 
    
         
            -
                  if operator != 'IN' && !@model.defined_enums.key?(field)
         
     | 
| 
       30 
     | 
    
         
            -
                    value = quotations_formatting(value)
         
     | 
| 
       31 
     | 
    
         
            -
                  end
         
     | 
| 
       32 
     | 
    
         
            -
             
     | 
| 
       33 
     | 
    
         
            -
                  if field.include?('.')
         
     | 
| 
       34 
     | 
    
         
            -
                    # нужно приджойнить таблицу
         
     | 
| 
       35 
     | 
    
         
            -
                    join_assoc, field = field.split('.')
         
     | 
| 
       36 
     | 
    
         
            -
                    table = join_assoc.tableize
         
     | 
| 
       37 
     | 
    
         
            -
                    list = list.joins(join_assoc.to_sym)
         
     | 
| 
       38 
     | 
    
         
            -
                  else
         
     | 
| 
       39 
     | 
    
         
            -
                    table = @model.table_name
         
     | 
| 
       40 
     | 
    
         
            -
                    field = field.split('|')[0]
         
     | 
| 
       41 
     | 
    
         
            -
                  end
         
     | 
| 
       42 
     | 
    
         
            -
             
     | 
| 
       43 
     | 
    
         
            -
                  query = where_query(table, field, operator, value)
         
     | 
| 
       44 
     | 
    
         
            -
                  @objects = list.where(query)
         
     | 
| 
       45 
     | 
    
         
            -
                  @objects_count = @objects.count
         
     | 
| 
       46 
     | 
    
         
            -
                end
         
     | 
| 
       47 
     | 
    
         
            -
              end
         
     | 
| 
       48 
     | 
    
         
            -
             
     | 
| 
       49 
     | 
    
         
            -
              def search_operands(field)
         
     | 
| 
       50 
     | 
    
         
            -
                value = default_param_value(field)
         
     | 
| 
       51 
     | 
    
         
            -
             
     | 
| 
       52 
     | 
    
         
            -
                # WHERE query operator
         
     | 
| 
       53 
     | 
    
         
            -
                operator = field.split('|').size > 1 ? field.split('|').last : '='
         
     | 
| 
       54 
     | 
    
         
            -
             
     | 
| 
       55 
     | 
    
         
            -
                # условие для поиска ILIKE
         
     | 
| 
       56 
     | 
    
         
            -
                value = "%#{value}%" if operator == 'ilike' && value.present?
         
     | 
| 
       57 
     | 
    
         
            -
             
     | 
| 
       58 
     | 
    
         
            -
                # проверка мульти-поиска по параметру с массивом
         
     | 
| 
       59 
     | 
    
         
            -
                if operator == 'multi' && !value.blank?
         
     | 
| 
       60 
     | 
    
         
            -
                  operator = 'IN'
         
     | 
| 
       61 
     | 
    
         
            -
                  value = "(#{value.join(', ')})"
         
     | 
| 
       62 
     | 
    
         
            -
                end
         
     | 
| 
       63 
     | 
    
         
            -
             
     | 
| 
       64 
     | 
    
         
            -
                # проверка диапазона (MIN/MAX)
         
     | 
| 
       65 
     | 
    
         
            -
                if %w[min max].include?(operator)
         
     | 
| 
       66 
     | 
    
         
            -
                  range_field = field.split('.').last.split(':')[0].try { |i| i.split('|')[0] }
         
     | 
| 
       67 
     | 
    
         
            -
                  value = @params["#{range_field}_#{operator}"]
         
     | 
| 
       68 
     | 
    
         
            -
                  operator = operator == 'min' ? '>=' : '<='
         
     | 
| 
       69 
     | 
    
         
            -
                end
         
     | 
| 
       70 
     | 
    
         
            -
             
     | 
| 
       71 
     | 
    
         
            -
                # check array operator
         
     | 
| 
       72 
     | 
    
         
            -
                if operator == 'array' && value.present?
         
     | 
| 
       73 
     | 
    
         
            -
                  operator = '='
         
     | 
| 
       74 
     | 
    
         
            -
                  value = "{#{value}}"
         
     | 
| 
       75 
     | 
    
         
            -
                end
         
     | 
| 
       76 
     | 
    
         
            -
             
     | 
| 
       77 
     | 
    
         
            -
                [operator, value]
         
     | 
| 
       78 
     | 
    
         
            -
              end
         
     | 
| 
       79 
     | 
    
         
            -
             
     | 
| 
       80 
     | 
    
         
            -
              def default_param_value(field)
         
     | 
| 
       81 
     | 
    
         
            -
                # название ключа-поля без оператора (напр. ilike)
         
     | 
| 
       82 
     | 
    
         
            -
                key = field.split('|')[0]
         
     | 
| 
       83 
     | 
    
         
            -
             
     | 
| 
       84 
     | 
    
         
            -
                @params[key]
         
     | 
| 
       85 
     | 
    
         
            -
              end
         
     | 
| 
       86 
     | 
    
         
            -
             
     | 
| 
       87 
     | 
    
         
            -
              def where_query(table, field, operator, value)
         
     | 
| 
       88 
     | 
    
         
            -
                "#{table}.#{field} #{operator} #{value}"
         
     | 
| 
       89 
     | 
    
         
            -
              end
         
     | 
| 
       90 
     | 
    
         
            -
             
     | 
| 
       91 
     | 
    
         
            -
              def quotations_formatting(string)
         
     | 
| 
       92 
     | 
    
         
            -
                # удаление одинарных кавычек (напр. внутри строки)
         
     | 
| 
       93 
     | 
    
         
            -
                value = string.to_s.gsub(/'/, '')
         
     | 
| 
       94 
     | 
    
         
            -
             
     | 
| 
       95 
     | 
    
         
            -
                # добавление одинарных кавычек вокруг строки
         
     | 
| 
       96 
     | 
    
         
            -
                "'#{value}'"
         
     | 
| 
       97 
     | 
    
         
            -
              end
         
     | 
| 
       98 
     | 
    
         
            -
             
     | 
| 
       99 
     | 
    
         
            -
            end
         
     | 
    
        data/lib/paginated/sorting.rb
    DELETED
    
    
| 
         @@ -1,61 +0,0 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            require 'fast_excel'
         
     | 
| 
       2 
     | 
    
         
            -
             
     | 
| 
       3 
     | 
    
         
            -
            module Spreadsheet
         
     | 
| 
       4 
     | 
    
         
            -
             
     | 
| 
       5 
     | 
    
         
            -
              extend ActiveSupport::Concern
         
     | 
| 
       6 
     | 
    
         
            -
             
     | 
| 
       7 
     | 
    
         
            -
              def spreadsheet
         
     | 
| 
       8 
     | 
    
         
            -
                search if @objects_count > 0
         
     | 
| 
       9 
     | 
    
         
            -
             
     | 
| 
       10 
     | 
    
         
            -
                # коллекция записей ActiveRecord для формирования эл. таблицы
         
     | 
| 
       11 
     | 
    
         
            -
                records = @objects || @model.unscoped.merge(@scopes)
         
     | 
| 
       12 
     | 
    
         
            -
             
     | 
| 
       13 
     | 
    
         
            -
                # формирования файла эл. таблицы
         
     | 
| 
       14 
     | 
    
         
            -
                generate_spreadsheet(records)
         
     | 
| 
       15 
     | 
    
         
            -
              end
         
     | 
| 
       16 
     | 
    
         
            -
             
     | 
| 
       17 
     | 
    
         
            -
              private
         
     | 
| 
       18 
     | 
    
         
            -
             
     | 
| 
       19 
     | 
    
         
            -
              def generate_spreadsheet(records)
         
     | 
| 
       20 
     | 
    
         
            -
                filepath = "#{@tempdir}/#{Time.now.strftime('%Y%m%d_%H%M%S')}.xlsx"
         
     | 
| 
       21 
     | 
    
         
            -
             
     | 
| 
       22 
     | 
    
         
            -
                # создание таблицы и ее конфигурация
         
     | 
| 
       23 
     | 
    
         
            -
                workbook = FastExcel.open(filepath, constant_memory: true)
         
     | 
| 
       24 
     | 
    
         
            -
                workbook.default_format.set(
         
     | 
| 
       25 
     | 
    
         
            -
                  font_size: 0,
         
     | 
| 
       26 
     | 
    
         
            -
                  font_family: 'Arial'
         
     | 
| 
       27 
     | 
    
         
            -
                )
         
     | 
| 
       28 
     | 
    
         
            -
             
     | 
| 
       29 
     | 
    
         
            -
                # стили
         
     | 
| 
       30 
     | 
    
         
            -
                bold = workbook.bold_format
         
     | 
| 
       31 
     | 
    
         
            -
             
     | 
| 
       32 
     | 
    
         
            -
                # лист
         
     | 
| 
       33 
     | 
    
         
            -
                worksheet = workbook.add_worksheet('Основной')
         
     | 
| 
       34 
     | 
    
         
            -
                worksheet.auto_width = true
         
     | 
| 
       35 
     | 
    
         
            -
             
     | 
| 
       36 
     | 
    
         
            -
                # заголовки
         
     | 
| 
       37 
     | 
    
         
            -
                worksheet.append_row(spreadsheet_titles, bold)
         
     | 
| 
       38 
     | 
    
         
            -
             
     | 
| 
       39 
     | 
    
         
            -
                # содержимое
         
     | 
| 
       40 
     | 
    
         
            -
                cols = spreadsheet_columns
         
     | 
| 
       41 
     | 
    
         
            -
                records.each do |record|
         
     | 
| 
       42 
     | 
    
         
            -
                  values = cols.map { |col| record.send(col) }
         
     | 
| 
       43 
     | 
    
         
            -
                  worksheet.append_row(values)
         
     | 
| 
       44 
     | 
    
         
            -
                end
         
     | 
| 
       45 
     | 
    
         
            -
             
     | 
| 
       46 
     | 
    
         
            -
                # закрытие/сохранение файла
         
     | 
| 
       47 
     | 
    
         
            -
                workbook.close
         
     | 
| 
       48 
     | 
    
         
            -
             
     | 
| 
       49 
     | 
    
         
            -
                # путь до файла для дальнейшей обработки
         
     | 
| 
       50 
     | 
    
         
            -
                filepath
         
     | 
| 
       51 
     | 
    
         
            -
              end
         
     | 
| 
       52 
     | 
    
         
            -
             
     | 
| 
       53 
     | 
    
         
            -
              def spreadsheet_titles
         
     | 
| 
       54 
     | 
    
         
            -
                @spreadsheet_columns.map { |i| i['title'] }
         
     | 
| 
       55 
     | 
    
         
            -
              end
         
     | 
| 
       56 
     | 
    
         
            -
             
     | 
| 
       57 
     | 
    
         
            -
              def spreadsheet_columns
         
     | 
| 
       58 
     | 
    
         
            -
                @spreadsheet_columns.map { |i| i['column'] }
         
     | 
| 
       59 
     | 
    
         
            -
              end
         
     | 
| 
       60 
     | 
    
         
            -
             
     | 
| 
       61 
     | 
    
         
            -
            end
         
     |