paginated 1.0.5 → 1.0.7

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 22aa1b0f64b6566bb94bfb250518c8e18a668c1ca3e16b73ebbc7ab7e1cd74fc
4
- data.tar.gz: e40ee2dc208873e2ea18b9798dbae255b6a536dbf279cae50c9a33e3eaa3e1c0
3
+ metadata.gz: cc3ad78511419953d52e6f0f45794b7ff5b11730cb5556dbecc64f9785d8a195
4
+ data.tar.gz: 136abe2c808ba73b848c8ecf68b8033d573c9c3dd87e351fab13be3fd16a6659
5
5
  SHA512:
6
- metadata.gz: 3454f5ddc9bbb5e7a419fdf7617ae0ba69bcd927c5e648227301c919f67ddf347f31ea14b1a49f4f2189c03b5e3fe0f56cc7eb8a3ec347aaa4a893b16a6f8a44
7
- data.tar.gz: 51de563f73d7225a37aea2ca3d59b6ac9dcfc8d67774fbf0acaacb7a0a4d37d87b35044963941aac2225a3b7d70a8a427a2b4a7eaea43c42ca40e04ffd31b7ab
6
+ metadata.gz: 6764684cb5a12b29b6ebd146bc7a5e8e77705b2d237c4dd60c553db1aa4461e5f9332fc56d30679bf97c3daf51e3f817a5bd60ea5a9c2523c5ae40cab112f656
7
+ data.tar.gz: 6074be3b096999fe2379345aa17e6d69441af45ae471d453c32be5125e1d98b5eb6c7c3033324d8500e32680e6e66817dc303779c4e0ab23504efceb09de5ea3
data/README.md CHANGED
@@ -18,27 +18,22 @@ bundle
18
18
 
19
19
  ## Использование
20
20
 
21
- Использование с помощью вызова метода `.collection` и передачи в него необходимых опций:
22
- ```
23
- Paginated.collection()
24
- ```
21
+ Использование с помощью вызова метода-хелпера `paginated` и передачи в него необходимых опций.
25
22
 
26
23
  Опции (с примерами):
27
24
 
28
25
  `model: 'User'` - название модели, записи которой нужно обработать.
29
26
 
30
- `fields: %i[...]` - список полей, которые должны присутствовать в списке записей (передается вместо `serializer`).
31
-
32
27
  `entity: 'UserEntity'` - название класса Grape Entity, который обработает каждую запись (передается вместо `fields`).
33
28
 
34
- `params:` - передаваемые параметры для фильтрации записей.
29
+ `fields: %i[...]` - список полей, которые должны присутствовать в списке записей (передается вместо `serializer`).
35
30
 
36
31
  `search: %w[...]` - список полей, по которым должна осуществляться фильтрация (поиск).
37
32
 
38
33
  Например:
39
34
 
40
35
  ```
41
- Paginated.collection(
36
+ paginated(
42
37
  model: 'User',
43
38
  fields: %i[
44
39
  email
@@ -48,8 +43,7 @@ Paginated.collection(
48
43
  email
49
44
  name|ilike
50
45
  role|custom.for_role
51
- ],
52
- params:
46
+ ]
53
47
  )
54
48
  ```
55
49
 
@@ -0,0 +1,63 @@
1
+ module Grape
2
+ module DSL
3
+ module InsideRoute
4
+
5
+ def paginated(model:, entity:, scopes: nil, search: nil)
6
+ opts = pagination_opts(model, entity, scopes, search)
7
+
8
+ if params[:spreadsheet]
9
+ paginated_spreadsheet(**opts)
10
+ else
11
+ paginated_collection(**opts)
12
+ end
13
+ end
14
+
15
+ private
16
+
17
+ def pagination_opts(model, entity, scopes, search)
18
+ # стандартные опции
19
+ opts = { model:, entity:, scopes:, search:, params:, current_user: }
20
+
21
+ # требуемый список полей (+стандартные)
22
+ if params[:columns]
23
+ opts[:only_columns] = params[:columns] + %w[id deleted_at]
24
+ end
25
+
26
+ # требуемый список полей эл. таблицы
27
+ if params[:spreadsheet]
28
+ opts[:spreadsheet_columns] = JSON.parse(params[:spreadsheet])
29
+ end
30
+
31
+ opts
32
+ end
33
+
34
+ def paginated_spreadsheet(opts)
35
+ Dir.mktmpdir do |tempdir|
36
+ file_path = Paginated.spreadsheet **opts.merge(tempdir:)
37
+
38
+ spreadsheet_file_headers File.basename(file_path)
39
+ File.open(file_path).read
40
+ end
41
+ end
42
+
43
+ def spreadsheet_file_headers(filename)
44
+ header['Content-Type'] =
45
+ case File.extname(filename)
46
+ when '.csv'
47
+ 'application/csv'
48
+ when '.xlsx'
49
+ 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
50
+ end
51
+
52
+ header['Access-Control-Expose-Headers'] = 'Content-Disposition'
53
+ header['Content-Disposition'] = "attachment; filename=#{Addressable::URI.escape(filename)}"
54
+ env['api.format'] = :binary
55
+ end
56
+
57
+ def paginated_collection(opts)
58
+ Paginated.collection(**opts)
59
+ end
60
+
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,63 @@
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
@@ -1,7 +1,19 @@
1
- module Serialization
1
+ module Collection
2
2
 
3
3
  extend ActiveSupport::Concern
4
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
+
5
17
  private
6
18
 
7
19
  def serialize
@@ -31,7 +43,12 @@ module Serialization
31
43
  end
32
44
 
33
45
  def serialize_with_entity
34
- @objects = @objects.map { |i| @grape_entity.represent(i, current_user: @current_user).as_json }
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 }
35
52
  end
36
53
 
37
54
  def obtain_fields_values(record)
@@ -0,0 +1,53 @@
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_columns.values, bold)
38
+
39
+ # содержимое
40
+ columns = @spreadsheet_columns.keys
41
+ records.each do |record|
42
+ values = columns.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
+ end
data/lib/paginated.rb CHANGED
@@ -1,15 +1,20 @@
1
+ require 'paginated/args_andling'
2
+ require 'paginated/collection'
1
3
  require 'paginated/search'
2
- require 'paginated/serialization'
3
4
  require 'paginated/sorting'
5
+ require 'paginated/spreadsheet'
6
+
7
+ require 'grape_extensions/dsl'
4
8
 
5
9
  class Paginated
6
10
 
11
+ include ArgsHandling
12
+ include Collection
7
13
  include Search
8
- include Serialization
9
14
  include Sorting
15
+ include Spreadsheet
10
16
 
11
17
  def initialize(**args)
12
- # обработка переданных аргументов
13
18
  handle_args(**args)
14
19
  end
15
20
 
@@ -17,66 +22,8 @@ class Paginated
17
22
  new(**args).collection
18
23
  end
19
24
 
20
- def collection
21
- if @objects_count > 0
22
- search
23
- serialize
24
- else
25
- @objects = []
26
- end
27
-
28
- # результат с пагинацией
29
- { count: @objects_count, objects: @objects }
30
- end
31
-
32
- private
33
-
34
- def handle_args(**args)
35
- # обрабатываемая Rails модель
36
- @model = args[:model]
37
-
38
- # параметры запроса и текущий пользователь
39
- serialization_scope = args[:serialization_scope]
40
- @params = serialization_scope.params.stringify_keys
41
- @current_user = serialization_scope.current_user
42
-
43
- # поля, по которым возможен поиск
44
- @search_fields = args[:search]
45
-
46
- # сериализация - через Grape Entity или список полей
47
- @grape_entity = args[:entity]
48
- @fields = args[:fields]
49
-
50
- # Rails scopes для применения
51
- @scopes = args[:scopes] || {}
52
-
53
- # offset / limit
54
- @offset = @params['offset'].to_i
55
- @limit = @params['limit'] || 20
56
-
57
- # сортировка
58
- @sort_by = @params['sort_by'] || :id
59
- @sort_order = @params['sort_order'] || :desc
60
-
61
- # подсчет кол-ва записей
62
- @objects_count = records_count
63
- end
64
-
65
- def records_count
66
- # получение кол-ва записей из кеша
67
- cache_key = "#{@model}_records_count"
68
- cached = Rails.cache.read(cache_key)
69
- return cached if cached
70
-
71
- # получение кол-ва записей из запроса к БД
72
- count = @model.merge(@scopes).count(:id)
73
-
74
- # кеширование кол-ва записей при превышении порогового значения
75
- if count >= 1_000
76
- Rails.cache.write(cache_key, count, expires_in: 30.minutes)
77
- end
78
-
79
- count
25
+ def self.spreadsheet(**args)
26
+ new(**args).spreadsheet
80
27
  end
81
28
 
82
29
  end
metadata CHANGED
@@ -1,68 +1,86 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: paginated
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.5
4
+ version: 1.0.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Павел Бабин
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-02-09 00:00:00.000000000 Z
11
+ date: 2024-02-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: rails
14
+ name: grape
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '6.0'
20
- type: :development
19
+ version: 2.0.0
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: '6.0'
26
+ version: 2.0.0
27
27
  - !ruby/object:Gem::Dependency
28
- name: grape
28
+ name: grape-entity
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: 1.7.0
34
- type: :development
33
+ version: 1.0.0
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: 1.7.0
40
+ version: 1.0.0
41
41
  - !ruby/object:Gem::Dependency
42
- name: grape-entity
42
+ name: addressable
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: 1.0.0
48
- type: :development
47
+ version: '2.6'
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: 1.0.0
55
- description: Простая пагинация записей и поиск для Rails-приложений
54
+ version: '2.6'
55
+ - !ruby/object:Gem::Dependency
56
+ name: fast_excel
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 0.5.0
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 0.5.0
69
+ description: Простая пагинация записей, поиск и формирование эл. таблиц для API на
70
+ базе Grape
56
71
  email: babin359@gmail.com
57
72
  executables: []
58
73
  extensions: []
59
74
  extra_rdoc_files: []
60
75
  files:
61
76
  - README.md
77
+ - lib/grape_extensions/dsl.rb
62
78
  - lib/paginated.rb
79
+ - lib/paginated/args_andling.rb
80
+ - lib/paginated/collection.rb
63
81
  - lib/paginated/search.rb
64
- - lib/paginated/serialization.rb
65
82
  - lib/paginated/sorting.rb
83
+ - lib/paginated/spreadsheet.rb
66
84
  homepage:
67
85
  licenses:
68
86
  - MIT
@@ -85,5 +103,5 @@ requirements: []
85
103
  rubygems_version: 3.0.6
86
104
  signing_key:
87
105
  specification_version: 4
88
- summary: Пагинация для Rails-приложений
106
+ summary: Пагинация для API на базе Grape
89
107
  test_files: []