paginated 1.0.5 → 1.0.7

Sign up to get free protection for your applications and to get access to all the features.
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: []