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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6ba8617bffac0ab4e4a01be9a04405601e47b623856460fac204877fc26317f7
4
- data.tar.gz: aeca947deec2736192248fef996310e5848acd3575e176c9d708c5b6623d8799
3
+ metadata.gz: 9a08651771c1b6b69a971b66317aa3691cb75d7da100f9407b16f78167481acf
4
+ data.tar.gz: b0df89ebcb77edc6f1117808fbc4a0945d0bead95b718e1327bfd2f308c77f1e
5
5
  SHA512:
6
- metadata.gz: c4cf61f5dde0b861f2cbeb372c324a02eaf9a1b71dcb6ff573f48b427abf0a10c0e232dc1851414094d0e103ee4000950d6f1a8c97553b0e9c62d01d6ee3a972
7
- data.tar.gz: cb98c65e16c43a058c1c513e223e6ff15b2a3b2a13acd538a29aba2167f232ebb363847123509efb54227ecf3abe8451bb43b6f7e34b808f676c5b7f83ca2c4d
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, caching: false, preload: nil)
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, caching, request_method, request_uri, preload)
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, caching, request_method, request_uri, preload)
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
- caching:,
37
+ cache:,
38
38
  request_method:,
39
39
  request_uri:
40
40
  }
@@ -0,0 +1,3 @@
1
+ module GrapeListing
2
+ VERSION = '1.4.1'.freeze
3
+ end
@@ -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
- @caching = args[:caching]
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
- if @objects_count > 0
6
- search
7
- list
8
- else
9
- @objects = []
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 list
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 = serialize(@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
- if @objects_count > 0
6
- search
7
- paginate
8
- else
9
- @objects = []
10
- end
5
+ # применение фильтрации
6
+ search
7
+
8
+ # обработка записей
9
+ handle_paginated_list
11
10
 
12
11
  # результат с пагинацией
13
- { count: @objects_count, objects: @objects }
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 paginate
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 = serialize(@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
@@ -41,10 +41,6 @@ module GrapeListing
41
41
  query = where_query(table, field, operator, value)
42
42
  @objects = list.where(query)
43
43
  end
44
-
45
- if @objects
46
- @objects_count = @objects.distinct.count
47
- end
48
44
  end
49
45
 
50
46
  def search_operands(field)
@@ -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
- if @caching
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'] || 'DESC'
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.3.8
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: 2024-12-13 00:00:00.000000000 Z
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
- - MIT
105
+ - Copyright
105
106
  metadata:
106
107
  rubygems_mfa_required: 'true'
107
108
  post_install_message: