paginated 1.0.6 → 1.0.7
Sign up to get free protection for your applications and to get access to all the features.
- 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} +14 -2
- data/lib/paginated/spreadsheet.rb +53 -0
- data/lib/paginated.rb +10 -66
- 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
|
@@ -33,7 +45,7 @@ module Serialization
|
|
33
45
|
def serialize_with_entity
|
34
46
|
opts = { current_user: @current_user }
|
35
47
|
|
36
|
-
# требуемый список
|
48
|
+
# требуемый список полей (если был передан)
|
37
49
|
opts[:only] = @only_columns if @only_columns
|
38
50
|
|
39
51
|
@objects = @objects.map { |i| @grape_entity.represent(i, opts).as_json }
|
@@ -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,69 +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
|
-
@only_columns = args[:only_columns]
|
59
|
-
|
60
|
-
# сортировка
|
61
|
-
@sort_by = @params['sort_by'] || :id
|
62
|
-
@sort_order = @params['sort_order'] || :desc
|
63
|
-
|
64
|
-
# подсчет кол-ва записей
|
65
|
-
@objects_count = records_count
|
66
|
-
end
|
67
|
-
|
68
|
-
def records_count
|
69
|
-
# получение кол-ва записей из кеша
|
70
|
-
cache_key = "#{@model}_records_count"
|
71
|
-
cached = Rails.cache.read(cache_key)
|
72
|
-
return cached if cached
|
73
|
-
|
74
|
-
# получение кол-ва записей из запроса к БД
|
75
|
-
count = @model.merge(@scopes).count(:id)
|
76
|
-
|
77
|
-
# кеширование кол-ва записей при превышении порогового значения
|
78
|
-
if count >= 1_000
|
79
|
-
Rails.cache.write(cache_key, count, expires_in: 30.minutes)
|
80
|
-
end
|
81
|
-
|
82
|
-
count
|
25
|
+
def self.spreadsheet(**args)
|
26
|
+
new(**args).spreadsheet
|
83
27
|
end
|
84
28
|
|
85
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: []
|