grape-listing 1.3.8 → 1.4.1
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/lib/grape/dsl.rb +4 -4
- data/lib/grape_listing/version.rb +3 -0
- data/lib/listing_service/args_handling.rb +1 -36
- data/lib/listing_service/listing.rb +8 -9
- data/lib/listing_service/pagination.rb +50 -10
- data/lib/listing_service/search.rb +0 -4
- data/lib/listing_service/serialization.rb +20 -21
- data/lib/listing_service/sorting.rb +4 -3
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9a08651771c1b6b69a971b66317aa3691cb75d7da100f9407b16f78167481acf
|
4
|
+
data.tar.gz: b0df89ebcb77edc6f1117808fbc4a0945d0bead95b718e1327bfd2f308c77f1e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1e81de98a49503dae90ca57c69e3ee1e086376b920dc3d10bffc759f11d2aee07169901212295a6c0795da105784c9944876c5086c3420a8be21480c3b6e6fbb
|
7
|
+
data.tar.gz: 6dfd30da2944c35bafa79670fde3c4e47f8d2f70c6a5ad05b25b6fde159c2e1e129380d4c1eac7da7959a1e72d92fb5bd63d2259c5bead9525fd2d640f469d92
|
data/lib/grape/dsl.rb
CHANGED
@@ -4,13 +4,13 @@ module Grape
|
|
4
4
|
module DSL
|
5
5
|
module InsideRoute
|
6
6
|
|
7
|
-
def listing(model:, entity:, scopes: nil, search: nil, sortable: nil, paginate: true,
|
7
|
+
def listing(model:, entity:, scopes: nil, search: nil, sortable: nil, paginate: true, cache: nil, preload: nil)
|
8
8
|
# параметры запроса API
|
9
9
|
request_method = request.env['REQUEST_METHOD']
|
10
10
|
request_uri = request.env['REQUEST_URI']
|
11
11
|
|
12
12
|
# опции для сервиса
|
13
|
-
opts = listing_opts(model, entity, scopes, search, sortable,
|
13
|
+
opts = listing_opts(model, entity, scopes, search, sortable, cache, request_method, request_uri, preload)
|
14
14
|
|
15
15
|
if params[:spreadsheet]
|
16
16
|
listing_spreadsheet(**opts)
|
@@ -23,7 +23,7 @@ module Grape
|
|
23
23
|
|
24
24
|
private
|
25
25
|
|
26
|
-
def listing_opts(model, entity, scopes, search, sortable,
|
26
|
+
def listing_opts(model, entity, scopes, search, sortable, cache, request_method, request_uri, preload)
|
27
27
|
# стандартные опции
|
28
28
|
opts = {
|
29
29
|
model:,
|
@@ -34,7 +34,7 @@ module Grape
|
|
34
34
|
sortable:,
|
35
35
|
params:,
|
36
36
|
current_user:,
|
37
|
-
|
37
|
+
cache:,
|
38
38
|
request_method:,
|
39
39
|
request_uri:
|
40
40
|
}
|
@@ -43,46 +43,11 @@ module GrapeListing
|
|
43
43
|
# сортировка
|
44
44
|
@sortable = args[:sortable]
|
45
45
|
|
46
|
-
# подсчет кол-ва записей
|
47
|
-
@objects_count = records_count
|
48
|
-
|
49
46
|
# временная директория (для генерации файлов)
|
50
47
|
@tempdir = args[:tempdir]
|
51
48
|
|
52
49
|
# кеширование результатов обработки Grape Entity
|
53
|
-
@
|
54
|
-
end
|
55
|
-
|
56
|
-
def records_count
|
57
|
-
# получение кол-ва записей из кеша
|
58
|
-
key = count_cache_key
|
59
|
-
cached = GrapeListing.cache.read(key)
|
60
|
-
return cached if cached
|
61
|
-
|
62
|
-
# получение кол-ва записей из запроса к БД
|
63
|
-
count = @model.merge(@scopes).distinct.count(:id)
|
64
|
-
|
65
|
-
# кеширование кол-ва записей при превышении порогового значения
|
66
|
-
if count >= 1_000
|
67
|
-
GrapeListing.cache.write(key, count, expires_in: 30.minutes)
|
68
|
-
end
|
69
|
-
|
70
|
-
count
|
71
|
-
end
|
72
|
-
|
73
|
-
def count_cache_key
|
74
|
-
# необходимо убрать параметры offset и page из uri
|
75
|
-
uri_path, params = @request_uri.split('?')
|
76
|
-
if params
|
77
|
-
params = Rack::Utils.parse_query(params).except('offset', 'page')
|
78
|
-
@request_uri = params.present? ? "#{uri_path}?#{Rack::Utils.build_query(params)}" : uri_path
|
79
|
-
end
|
80
|
-
|
81
|
-
# пример: "GET api/v1/users?active=true"
|
82
|
-
body = "#{@request_method} #{@request_uri}"
|
83
|
-
|
84
|
-
enc = Digest::MD5.hexdigest(body)
|
85
|
-
"listing_cached_count_#{enc}"
|
50
|
+
@cache = args[:cache]
|
86
51
|
end
|
87
52
|
|
88
53
|
end
|
@@ -2,12 +2,11 @@ module GrapeListing
|
|
2
2
|
module Listing
|
3
3
|
|
4
4
|
def listed
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
end
|
5
|
+
# применение фильтрации
|
6
|
+
search
|
7
|
+
|
8
|
+
# обработка записей
|
9
|
+
handle_objects_list
|
11
10
|
|
12
11
|
# результат
|
13
12
|
@objects
|
@@ -15,15 +14,15 @@ module GrapeListing
|
|
15
14
|
|
16
15
|
private
|
17
16
|
|
18
|
-
def
|
17
|
+
def handle_objects_list
|
19
18
|
# коллекция записей ActiveRecord для применения аггрегирования
|
20
19
|
list = @objects || @model.preload(@preload).merge(@scopes)
|
21
20
|
|
22
21
|
# применение сортировки к коллекции записей
|
23
22
|
@objects = list.merge(sort_proc)
|
24
23
|
|
25
|
-
# сериализация
|
26
|
-
@objects =
|
24
|
+
# сериализация
|
25
|
+
@objects = represent(@objects)
|
27
26
|
end
|
28
27
|
|
29
28
|
end
|
@@ -2,29 +2,69 @@ module GrapeListing
|
|
2
2
|
module Pagination
|
3
3
|
|
4
4
|
def paginated
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
end
|
5
|
+
# применение фильтрации
|
6
|
+
search
|
7
|
+
|
8
|
+
# обработка записей
|
9
|
+
handle_paginated_list
|
11
10
|
|
12
11
|
# результат с пагинацией
|
13
|
-
{
|
12
|
+
{
|
13
|
+
sort_order: @sort_order,
|
14
|
+
sort_by: @params['sort_by'],
|
15
|
+
count: @objects_count,
|
16
|
+
objects: @objects
|
17
|
+
}
|
14
18
|
end
|
15
19
|
|
16
20
|
private
|
17
21
|
|
18
|
-
def
|
22
|
+
def handle_paginated_list
|
19
23
|
# коллекция записей ActiveRecord для применения аггрегирования
|
20
24
|
list = @objects || @model.preload(@preload).merge(@scopes)
|
21
25
|
|
26
|
+
# подсчет кол-ва записей
|
27
|
+
@objects_count = records_count(list)
|
28
|
+
|
22
29
|
# применение сортировки и пагинации к коллекции записей
|
23
30
|
@objects = list.offset(@offset).merge(sort_proc).limit(@limit)
|
24
31
|
|
25
|
-
# сериализация
|
26
|
-
@objects =
|
32
|
+
# сериализация
|
33
|
+
@objects = represent(@objects)
|
27
34
|
end
|
28
35
|
|
36
|
+
def records_count(list)
|
37
|
+
# получение кол-ва записей из кеша
|
38
|
+
key = count_cache_key
|
39
|
+
cached = GrapeListing.cache.read(key)
|
40
|
+
return cached if cached
|
41
|
+
|
42
|
+
# получение кол-ва записей из запроса к БД
|
43
|
+
count = list.distinct.count(:id)
|
44
|
+
|
45
|
+
# кеширование кол-ва записей при превышении порогового значения
|
46
|
+
if count >= 1_000
|
47
|
+
GrapeListing.cache.write(key, count, expires_in: 30.minutes)
|
48
|
+
end
|
49
|
+
|
50
|
+
count
|
51
|
+
end
|
52
|
+
|
53
|
+
def count_cache_key
|
54
|
+
# необходимо убрать параметры offset и page из uri
|
55
|
+
uri_path, params = @request_uri.split('?')
|
56
|
+
if params
|
57
|
+
params = Rack::Utils.parse_query(params).except('offset', 'page')
|
58
|
+
@request_uri = params.present? ? "#{uri_path}?#{Rack::Utils.build_query(params)}" : uri_path
|
59
|
+
end
|
60
|
+
|
61
|
+
# пример: "GET api/v1/users?active=true"
|
62
|
+
body = "#{@request_method} #{@request_uri}"
|
63
|
+
|
64
|
+
enc = Digest::MD5.hexdigest(body)
|
65
|
+
"listing_cached_count_#{enc}"
|
66
|
+
end
|
67
|
+
|
68
|
+
|
29
69
|
end
|
30
70
|
end
|
@@ -3,6 +3,14 @@ module GrapeListing
|
|
3
3
|
|
4
4
|
private
|
5
5
|
|
6
|
+
def represent(records)
|
7
|
+
if @cache.present?
|
8
|
+
cache { serialize(records) }
|
9
|
+
else
|
10
|
+
serialize(records)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
6
14
|
def serialize(records)
|
7
15
|
if @fields
|
8
16
|
serialize_with_fields(records)
|
@@ -11,6 +19,17 @@ module GrapeListing
|
|
11
19
|
end
|
12
20
|
end
|
13
21
|
|
22
|
+
def cache
|
23
|
+
# параметры кеширования
|
24
|
+
key = @cache[:key] || @model.table_name
|
25
|
+
opts = @cache.slice(:expires_in)
|
26
|
+
|
27
|
+
# непосредственное кеширование
|
28
|
+
GrapeListing.cache.fetch(key, opts) do
|
29
|
+
yield
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
14
33
|
def serialize_with_fields(records)
|
15
34
|
# добавление ID в список полей по умолчанию
|
16
35
|
@fields.push(:id)
|
@@ -33,11 +52,7 @@ module GrapeListing
|
|
33
52
|
|
34
53
|
# обработка результатов
|
35
54
|
records.map do |record|
|
36
|
-
|
37
|
-
caching_entity_representation(record)
|
38
|
-
else
|
39
|
-
@grape_entity.represent(record, @entity_opts).as_json
|
40
|
-
end
|
55
|
+
@grape_entity.represent(record, @entity_opts).as_json
|
41
56
|
end
|
42
57
|
end
|
43
58
|
|
@@ -45,21 +60,5 @@ module GrapeListing
|
|
45
60
|
@fields.map { |i| record.send(i) }
|
46
61
|
end
|
47
62
|
|
48
|
-
def caching_entity_representation(record)
|
49
|
-
key = "#{@grape_entity}:#{record.id}"
|
50
|
-
|
51
|
-
# опции кеширования
|
52
|
-
opts =
|
53
|
-
if @caching.is_a?(ActiveSupport::Duration)
|
54
|
-
{ expires_in: @caching }
|
55
|
-
else
|
56
|
-
{}
|
57
|
-
end
|
58
|
-
|
59
|
-
GrapeListing.cache.fetch(key, opts) do
|
60
|
-
@grape_entity.represent(record, @entity_opts).as_json
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
63
|
end
|
65
64
|
end
|
@@ -6,16 +6,17 @@ module GrapeListing
|
|
6
6
|
def sort_proc
|
7
7
|
# проверка необходимости нестандартной сортировки
|
8
8
|
if !@sortable.is_a?(Array) || @sortable.empty? || custom_sorting_field.blank?
|
9
|
+
@sort_by = 'id'
|
9
10
|
return proc { order('id DESC NULLS LAST') }
|
10
11
|
end
|
11
12
|
|
12
|
-
sort_order = @params['sort_order'] || '
|
13
|
+
@sort_order = @params['sort_order'] || 'desc'
|
13
14
|
sorting_scope = custom_sorting_field.split('|')[1]
|
14
15
|
|
15
16
|
if sorting_scope
|
16
|
-
proc { send(sorting_scope, sort_order) }
|
17
|
+
proc { send(sorting_scope, @sort_order) }
|
17
18
|
else
|
18
|
-
query = Arel.sql("#{custom_sorting_field} #{sort_order} NULLS LAST")
|
19
|
+
query = Arel.sql("#{custom_sorting_field} #{@sort_order} NULLS LAST")
|
19
20
|
proc { order(query) }
|
20
21
|
end
|
21
22
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: grape-listing
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.4.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Павел Бабин
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2025-02-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: actionpack
|
@@ -91,6 +91,7 @@ files:
|
|
91
91
|
- lib/grape/dsl.rb
|
92
92
|
- lib/grape_listing.rb
|
93
93
|
- lib/grape_listing/configuration.rb
|
94
|
+
- lib/grape_listing/version.rb
|
94
95
|
- lib/grape_listing_service.rb
|
95
96
|
- lib/listing_service/args_handling.rb
|
96
97
|
- lib/listing_service/listing.rb
|
@@ -101,7 +102,7 @@ files:
|
|
101
102
|
- lib/listing_service/spreadsheet.rb
|
102
103
|
homepage:
|
103
104
|
licenses:
|
104
|
-
-
|
105
|
+
- Copyright
|
105
106
|
metadata:
|
106
107
|
rubygems_mfa_required: 'true'
|
107
108
|
post_install_message:
|