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 +4 -4
- data/README.md +4 -10
- data/lib/grape_extensions/dsl.rb +63 -0
- data/lib/paginated/args_andling.rb +63 -0
- data/lib/paginated/{serialization.rb → collection.rb} +19 -2
- data/lib/paginated/spreadsheet.rb +53 -0
- data/lib/paginated.rb +10 -63
- metadata +35 -17
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cc3ad78511419953d52e6f0f45794b7ff5b11730cb5556dbecc64f9785d8a195
|
4
|
+
data.tar.gz: 136abe2c808ba73b848c8ecf68b8033d573c9c3dd87e351fab13be3fd16a6659
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
-
Использование с помощью вызова
|
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
|
-
`
|
29
|
+
`fields: %i[...]` - список полей, которые должны присутствовать в списке записей (передается вместо `serializer`).
|
35
30
|
|
36
31
|
`search: %w[...]` - список полей, по которым должна осуществляться фильтрация (поиск).
|
37
32
|
|
38
33
|
Например:
|
39
34
|
|
40
35
|
```
|
41
|
-
|
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
|
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
|
-
|
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
|
21
|
-
|
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.
|
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-
|
11
|
+
date: 2024-02-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
14
|
+
name: grape
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
20
|
-
type: :
|
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:
|
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.
|
34
|
-
type: :
|
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.
|
40
|
+
version: 1.0.0
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
|
-
name:
|
42
|
+
name: addressable
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
45
|
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version:
|
48
|
-
type: :
|
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:
|
55
|
-
|
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: Пагинация для
|
106
|
+
summary: Пагинация для API на базе Grape
|
89
107
|
test_files: []
|