jsonapi-query_builder 0.3.0 → 0.4.0

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: c0bbac3427e5cd55ee1f3528925a7d5f06817bef89e232a668821450a8cbedf0
4
- data.tar.gz: 622b993193db4a2644187a99099ed5470380dae1d4f576efccf0465d84a8e7f3
3
+ metadata.gz: e9ea254260274b96b7d2374e9b1b6940467f86d619b2507abcffc9a592fbd1e6
4
+ data.tar.gz: 21d0c563ed3593a7ff198b645e92fae84a5fbe144309a71d14c0799c09e21bf6
5
5
  SHA512:
6
- metadata.gz: 5719e6ab6411803bd98cc6aa06ce8471a19c90f713c4b1c014106338bde1b7d7495bcac4be216349524c92489d5873327ba31cc7d4e99c075249ce6db149a54f
7
- data.tar.gz: 6151a1cd285f11ed2f48c7c140442a3f67ba85f656d601d8a5ad4c2c686c973aad0526340a37271194e9400642db951d071d43993f7d37095fc47861ae89daf0
6
+ metadata.gz: ec7b08f99bd292f0c33105e22be664f92832efee849785cc4f5da9dab1d9575993b546c10722eafd9d2e8472e4ae6d6bc23d9cff3cb48c9bdf4faa0815a9bbc8
7
+ data.tar.gz: 30f6711fab7a8be90960417e545dd2bbf7b3778a4997fceab15f56587fad040018f0a9d3f6f4f845c890e7a8ea2985771823160ff18d9e2672f93dbc59cfedf6
@@ -8,7 +8,7 @@ on:
8
8
 
9
9
  jobs:
10
10
  standardrb:
11
- runs-on: ubuntu-18.04
11
+ runs-on: ubuntu-24.04
12
12
 
13
13
  steps:
14
14
  - uses: actions/checkout@v2
@@ -19,7 +19,7 @@ jobs:
19
19
  run: bundle exec standardrb
20
20
 
21
21
  rubocop-rspec:
22
- runs-on: ubuntu-18.04
22
+ runs-on: ubuntu-24.04
23
23
 
24
24
  steps:
25
25
  - uses: actions/checkout@v2
@@ -8,10 +8,10 @@ on:
8
8
 
9
9
  jobs:
10
10
  rake-spec:
11
- runs-on: ubuntu-18.04
11
+ runs-on: ubuntu-24.04
12
12
  strategy:
13
13
  matrix:
14
- ruby: [2.5, 2.6, 2.7, 3.0]
14
+ ruby: ['3.2', '3.3', '3.4']
15
15
 
16
16
  steps:
17
17
  - uses: actions/checkout@v2
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- 3.0.2
1
+ 3.4.5
data/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  # Change log
2
2
 
3
+ ## 0.4.0 (2025-11-03)
4
+
5
+ ### Enhancements
6
+ - Added support for dynamic (prefix-based) sorting [#31](https://github.com/infinum/jsonapi-query_builder/pull/31)
7
+ - Added Pagy countless paginator [#26](https://github.com/infinum/jsonapi-query_builder/pull/26)
8
+
9
+ ### Changes
10
+ - Dropped support for Ruby < 3.2
11
+ - Dropped Rails < 7.2 support
12
+
3
13
  ## 0.3.0 (2021-12-07)
4
14
 
5
15
  ### Enhancements
data/Gemfile.lock CHANGED
@@ -1,42 +1,56 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- jsonapi-query_builder (0.3.0)
5
- activerecord (>= 5)
4
+ jsonapi-query_builder (0.4.0)
5
+ activerecord (>= 7.2)
6
6
  pagy (>= 3.5)
7
7
 
8
8
  GEM
9
9
  remote: https://rubygems.org/
10
10
  specs:
11
- actionview (6.1.4.1)
12
- activesupport (= 6.1.4.1)
11
+ actionview (8.0.2.1)
12
+ activesupport (= 8.0.2.1)
13
13
  builder (~> 3.1)
14
- erubi (~> 1.4)
15
- rails-dom-testing (~> 2.0)
16
- rails-html-sanitizer (~> 1.1, >= 1.2.0)
17
- activemodel (6.1.4.1)
18
- activesupport (= 6.1.4.1)
19
- activerecord (6.1.4.1)
20
- activemodel (= 6.1.4.1)
21
- activesupport (= 6.1.4.1)
22
- activesupport (6.1.4.1)
23
- concurrent-ruby (~> 1.0, >= 1.0.2)
14
+ erubi (~> 1.11)
15
+ rails-dom-testing (~> 2.2)
16
+ rails-html-sanitizer (~> 1.6)
17
+ activemodel (8.0.2.1)
18
+ activesupport (= 8.0.2.1)
19
+ activerecord (8.0.2.1)
20
+ activemodel (= 8.0.2.1)
21
+ activesupport (= 8.0.2.1)
22
+ timeout (>= 0.4.0)
23
+ activesupport (8.0.2.1)
24
+ base64
25
+ benchmark (>= 0.3)
26
+ bigdecimal
27
+ concurrent-ruby (~> 1.0, >= 1.3.1)
28
+ connection_pool (>= 2.2.5)
29
+ drb
24
30
  i18n (>= 1.6, < 2)
31
+ logger (>= 1.4.2)
25
32
  minitest (>= 5.1)
26
- tzinfo (~> 2.0)
27
- zeitwerk (~> 2.3)
33
+ securerandom (>= 0.3)
34
+ tzinfo (~> 2.0, >= 2.0.5)
35
+ uri (>= 0.13.1)
28
36
  ast (2.4.2)
37
+ base64 (0.3.0)
38
+ benchmark (0.4.1)
39
+ bigdecimal (3.2.3)
29
40
  builder (3.2.4)
30
41
  bundler-audit (0.9.0.1)
31
42
  bundler (>= 1.2.0, < 3)
32
43
  thor (~> 1.0)
33
44
  coderay (1.1.3)
34
- concurrent-ruby (1.1.9)
45
+ concurrent-ruby (1.3.5)
46
+ connection_pool (2.5.4)
35
47
  crass (1.0.6)
36
48
  diff-lcs (1.4.4)
37
- erubi (1.10.0)
49
+ drb (2.2.3)
50
+ erubi (1.13.1)
38
51
  i18n (1.8.10)
39
52
  concurrent-ruby (~> 1.0)
53
+ json (2.13.2)
40
54
  kaminari (1.2.1)
41
55
  activesupport (>= 4.1.0)
42
56
  kaminari-actionview (= 1.2.1)
@@ -49,33 +63,39 @@ GEM
49
63
  activerecord
50
64
  kaminari-core (= 1.2.1)
51
65
  kaminari-core (1.2.1)
66
+ language_server-protocol (3.17.0.5)
52
67
  lefthook (0.7.6)
53
- loofah (2.12.0)
68
+ lint_roller (1.1.0)
69
+ logger (1.7.0)
70
+ loofah (2.24.1)
54
71
  crass (~> 1.0.2)
55
- nokogiri (>= 1.5.9)
72
+ nokogiri (>= 1.12.0)
56
73
  method_source (1.0.0)
57
- mini_portile2 (2.6.1)
74
+ mini_portile2 (2.8.9)
58
75
  minitest (5.14.4)
59
- nokogiri (1.12.5)
60
- mini_portile2 (~> 2.6.1)
76
+ nokogiri (1.18.9)
77
+ mini_portile2 (~> 2.8.2)
61
78
  racc (~> 1.4)
62
79
  pagy (3.11.0)
63
80
  parallel (1.21.0)
64
- parser (3.0.2.0)
81
+ parser (3.3.9.0)
65
82
  ast (~> 2.4.1)
83
+ racc
84
+ prism (1.4.0)
66
85
  pry (0.14.1)
67
86
  coderay (~> 1.1)
68
87
  method_source (~> 1.0)
69
88
  racc (1.5.2)
70
- rails-dom-testing (2.0.3)
71
- activesupport (>= 4.2.0)
89
+ rails-dom-testing (2.3.0)
90
+ activesupport (>= 5.0.0)
91
+ minitest
72
92
  nokogiri (>= 1.6)
73
- rails-html-sanitizer (1.4.2)
74
- loofah (~> 2.3)
93
+ rails-html-sanitizer (1.6.2)
94
+ loofah (~> 2.21)
95
+ nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0)
75
96
  rainbow (3.0.0)
76
97
  rake (13.0.6)
77
- regexp_parser (2.1.1)
78
- rexml (3.2.5)
98
+ regexp_parser (2.11.2)
79
99
  rspec (3.10.0)
80
100
  rspec-core (~> 3.10.0)
81
101
  rspec-expectations (~> 3.10.0)
@@ -89,34 +109,52 @@ GEM
89
109
  diff-lcs (>= 1.2.0, < 2.0)
90
110
  rspec-support (~> 3.10.0)
91
111
  rspec-support (3.10.2)
92
- rubocop (1.20.0)
112
+ rubocop (1.80.2)
113
+ json (~> 2.3)
114
+ language_server-protocol (~> 3.17.0.2)
115
+ lint_roller (~> 1.1.0)
93
116
  parallel (~> 1.10)
94
- parser (>= 3.0.0.0)
117
+ parser (>= 3.3.0.2)
95
118
  rainbow (>= 2.2.2, < 4.0)
96
- regexp_parser (>= 1.8, < 3.0)
97
- rexml
98
- rubocop-ast (>= 1.9.1, < 2.0)
119
+ regexp_parser (>= 2.9.3, < 3.0)
120
+ rubocop-ast (>= 1.46.0, < 2.0)
99
121
  ruby-progressbar (~> 1.7)
100
- unicode-display_width (>= 1.4.0, < 3.0)
101
- rubocop-ast (1.12.0)
102
- parser (>= 3.0.1.1)
103
- rubocop-performance (1.11.5)
104
- rubocop (>= 1.7.0, < 2.0)
105
- rubocop-ast (>= 0.4.0)
122
+ unicode-display_width (>= 2.4.0, < 4.0)
123
+ rubocop-ast (1.46.0)
124
+ parser (>= 3.3.7.2)
125
+ prism (~> 1.4)
126
+ rubocop-performance (1.25.0)
127
+ lint_roller (~> 1.1)
128
+ rubocop (>= 1.75.0, < 2.0)
129
+ rubocop-ast (>= 1.38.0, < 2.0)
106
130
  rubocop-rspec (2.5.0)
107
131
  rubocop (~> 1.19)
108
132
  ruby-progressbar (1.11.0)
109
- sqlite3 (1.4.2)
110
- standard (1.3.0)
111
- rubocop (= 1.20.0)
112
- rubocop-performance (= 1.11.5)
133
+ securerandom (0.4.1)
134
+ sqlite3 (2.7.3)
135
+ mini_portile2 (~> 2.8.0)
136
+ standard (1.51.0)
137
+ language_server-protocol (~> 3.17.0.2)
138
+ lint_roller (~> 1.0)
139
+ rubocop (~> 1.80.2)
140
+ standard-custom (~> 1.0.0)
141
+ standard-performance (~> 1.8)
142
+ standard-custom (1.0.2)
143
+ lint_roller (~> 1.0)
144
+ rubocop (~> 1.50)
145
+ standard-performance (1.8.0)
146
+ lint_roller (~> 1.1)
147
+ rubocop-performance (~> 1.25.0)
113
148
  standardrb (1.0.0)
114
149
  standard
115
- thor (1.1.0)
116
- tzinfo (2.0.4)
150
+ thor (1.4.0)
151
+ timeout (0.4.3)
152
+ tzinfo (2.0.6)
117
153
  concurrent-ruby (~> 1.0)
118
- unicode-display_width (2.1.0)
119
- zeitwerk (2.4.2)
154
+ unicode-display_width (3.2.0)
155
+ unicode-emoji (~> 4.1)
156
+ unicode-emoji (4.1.0)
157
+ uri (1.0.4)
120
158
 
121
159
  PLATFORMS
122
160
  ruby
@@ -137,4 +175,4 @@ DEPENDENCIES
137
175
  standardrb
138
176
 
139
177
  BUNDLED WITH
140
- 2.2.22
178
+ 2.7.2
data/README.md CHANGED
@@ -27,7 +27,7 @@ Or install it yourself as:
27
27
 
28
28
  ```ruby
29
29
  class UserQuery < Jsonapi::QueryBuilder::BaseQuery
30
- ## pagination
30
+ ## pagination
31
31
  paginator Jsonapi::QueryBuilder::Paginator::Pagy # default paginator
32
32
 
33
33
  ## sorting
@@ -62,9 +62,9 @@ pass the scoped collection to the `Jsonapi::QueryBuilder::BaseQuery` object.
62
62
  ### Pagination
63
63
 
64
64
  Pagination support is configurable using the `paginator` method to define the paginator. It defaults to the `Pagy`
65
- paginator, a lightweight and fast paginator. Other paginators currently supported are `Kaminari` and an implementation
66
- of keyset pagination. Before using these paginators we need to explicitly require the gems in our Gemfile and the
67
- paginator file in question. Additionally one can implement it's own paginator by inheriting
65
+ paginator, a lightweight and fast paginator. Other paginators currently supported are `Kaminari`, `PagyCountless` and
66
+ an implementation of keyset pagination. Before using these paginators we need to explicitly require the gems in our
67
+ Gemfile and the paginator file in question. Additionally one can implement it's own paginator by inheriting
68
68
  from `Jsonapi::QueryBuilder::Paginator::BasePaginator`. The minimum required implementation is a `#paginate` method that
69
69
  receives page params and returns a page of the collection. It can return the pagination details as the second item of
70
70
  the returned array, that can be used in the serializer for pagination metadata.
@@ -85,6 +85,14 @@ require "jsonapi/query_builder/paginator/keyset"
85
85
  paginator Jsonapi::QueryBuilder::Paginator::Keyset
86
86
  ```
87
87
 
88
+ #### Using the Pagy Countless Paginator
89
+
90
+ ```ruby
91
+ require "jsonapi/query_builder/paginator/pagy_countless"
92
+
93
+ paginator Jsonapi::QueryBuilder::Paginator::PagyCountless
94
+ ```
95
+
88
96
  ### Sorting
89
97
 
90
98
  #### Ensuring deterministic results
@@ -142,6 +150,38 @@ But since we're devout followers of the SOLID principles, we can define a sort c
142
150
  which returns the sorted collection. Under the hood the sort class is initialized with the current scope and the
143
151
  direction parameter.
144
152
 
153
+ #### Dynamic sorting (prefix-based)
154
+
155
+ Sometimes you want to allow sorting by a dynamic subset of attributes that share a common prefix (e.g., JSON/JSONB keys, translated columns, join records). You can register a dynamic sort by attribute prefix using `dynamically_sorts_by`.
156
+
157
+ - The configured prefix is matched against each parsed sort attribute.
158
+ - The prefix is stripped and only the dynamic part is passed to your sort handler.
159
+ - You can provide either a lambda/proc or a class. The callable receives `(collection, dynamic_attribute, direction)`.
160
+
161
+ Example with a lambda (PostgreSQL JSONB text value):
162
+
163
+ ```ruby
164
+ # Allows sorting by any key in the `data` column: e.g. sort=-data.name,data.created_at
165
+ dynamically_sorts_by :'data.', ->(collection, attribute, direction) {
166
+ # attribute is the part after the prefix, e.g. "name" or "created_at"
167
+ quoted_attribute = ActiveRecord::Base.connection.quote(attribute)
168
+ collection.order(Arel.sql("(data->>#{quoted_attribute}) #{direction}"))
169
+ }
170
+ ```
171
+
172
+ Example with a sort class (PostgreSQL JSONB text value):
173
+
174
+ ```ruby
175
+ class DataSort < Jsonapi::QueryBuilder::DynamicSort
176
+ def results
177
+ quoted_attribute = ActiveRecord::Base.connection.quote(dynamic_attribute)
178
+ collection.order(Arel.sql("(data->>#{quoted_attribute}) #{direction}"))
179
+ end
180
+ end
181
+
182
+ dynamically_sorts_by :'data.', DataSort
183
+ ```
184
+
145
185
  ### Filtering
146
186
 
147
187
  #### Simple exact match filters
@@ -36,9 +36,9 @@ Gem::Specification.new do |spec|
36
36
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
37
37
  spec.require_paths = ["lib"]
38
38
 
39
- spec.required_ruby_version = ">= 2.5"
39
+ spec.required_ruby_version = ">= 3.2"
40
40
 
41
- spec.add_runtime_dependency "activerecord", ">= 5"
41
+ spec.add_runtime_dependency "activerecord", ">= 7.2"
42
42
  spec.add_runtime_dependency "pagy", ">= 3.5"
43
43
 
44
44
  spec.add_development_dependency "bundler", "~> 2.0"
data/lefthook.yml CHANGED
@@ -2,7 +2,7 @@ lint:
2
2
  commands: &lint
3
3
  lint-frozen-strings:
4
4
  glob: "*.rb"
5
- run: bundle exec rubocop --only Style/FrozenStringLiteralComment,Layout/EmptyLineAfterMagicComment --format quiet --auto-correct
5
+ run: bundle exec rubocop --only Style/FrozenStringLiteralComment,Layout/EmptyLineAfterMagicComment --format quiet --autocorrect
6
6
 
7
7
  rubocop:
8
8
  commands: &rubocop
@@ -13,8 +13,7 @@ rubocop:
13
13
  pre-commit:
14
14
  parallel: true
15
15
  commands:
16
- <<: *lint
17
- <<: *rubocop
16
+ <<: [*lint, *rubocop]
18
17
  standardrb:
19
18
  glob: "*.rb"
20
19
  run: bundle exec standardrb {staged_files}
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "jsonapi/query_builder/base_sort"
4
+
5
+ module Jsonapi
6
+ module QueryBuilder
7
+ class DynamicSort < BaseSort
8
+ attr_reader :dynamic_attribute
9
+
10
+ # @param [ActiveRecord::Relation] collection
11
+ # @param [Symbol] dynamic_attribute, which attribute to dynamically sort by
12
+ # @param [Symbol] direction of the ordering, one of :asc or :desc
13
+ def initialize(collection, dynamic_attribute, direction = :asc)
14
+ super(collection, direction)
15
+ @dynamic_attribute = dynamic_attribute
16
+ end
17
+
18
+ # @return [ActiveRecord::Relation] Collection with order applied
19
+ def results
20
+ raise NotImplementedError, "#{self.class} should implement #results"
21
+ end
22
+ end
23
+ end
24
+ end
@@ -5,11 +5,11 @@ module Jsonapi
5
5
  module Errors
6
6
  class UnpermittedSortParameters < ArgumentError
7
7
  def initialize(unpermitted_parameters)
8
- super [
8
+ super([
9
9
  unpermitted_parameters.to_sentence,
10
- unpermitted_parameters.count == 1 ? "is not a" : "are not",
10
+ (unpermitted_parameters.count == 1) ? "is not a" : "are not",
11
11
  "permitted sort attribute".pluralize(unpermitted_parameters.count)
12
- ].join(" ")
12
+ ].join(" "))
13
13
  end
14
14
  end
15
15
  end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Jsonapi
4
+ module QueryBuilder
5
+ module Mixins
6
+ module Sort
7
+ class Dynamic
8
+ attr_reader :attribute_prefix, :sort
9
+
10
+ def initialize(attribute_prefix, sort)
11
+ @attribute_prefix = attribute_prefix.to_s
12
+ @sort = sort
13
+ end
14
+
15
+ def matches?(sort_attribute)
16
+ sort_attribute.to_s.start_with?(attribute_prefix)
17
+ end
18
+
19
+ def results(collection, sort_param)
20
+ dynamic_attribute = sort_param.attribute.delete_prefix(attribute_prefix)
21
+ if sort.respond_to?(:call)
22
+ sort.call(collection, dynamic_attribute, sort_param.direction)
23
+ else
24
+ sort.new(collection, dynamic_attribute, sort_param.direction).results
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Jsonapi
4
+ module QueryBuilder
5
+ module Mixins
6
+ module Sort
7
+ class Static
8
+ attr_reader :attribute, :sort
9
+
10
+ def initialize(attribute, sort)
11
+ @attribute = attribute
12
+ @sort = sort || ->(collection, direction) { collection.order(attribute => direction) }
13
+ end
14
+
15
+ def results(collection, sort_param)
16
+ if sort.respond_to?(:call)
17
+ sort.call(collection, sort_param.direction)
18
+ else
19
+ sort.new(collection, sort_param.direction).results
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -1,6 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "jsonapi/query_builder/mixins/sort/param"
4
+ require "jsonapi/query_builder/mixins/sort/static"
5
+ require "jsonapi/query_builder/mixins/sort/dynamic"
4
6
  require "jsonapi/query_builder/errors/unpermitted_sort_parameters"
5
7
 
6
8
  module Jsonapi
@@ -16,8 +18,14 @@ module Jsonapi
16
18
  @_unique_sort_attributes || [id: :asc]
17
19
  end
18
20
 
21
+ # @return [Hash<Symbol, Jsonapi::QueryBuilder::Mixins::Sort::Static>] Supported sorts
19
22
  def supported_sorts
20
- @supported_sorts || {}
23
+ @supported_sorts ||= {}
24
+ end
25
+
26
+ # @return [Array<Jsonapi::QueryBuilder::Mixins::Sort::Dynamic>] Supported dynamic sorts
27
+ def supported_dynamic_sorts
28
+ @supported_dynamic_sorts ||= []
21
29
  end
22
30
 
23
31
  # Ensures deterministic ordering. Defaults to :id in ascending direction.
@@ -43,8 +51,14 @@ module Jsonapi
43
51
  # @param [Symbol] attribute The "sortable" attribute
44
52
  # @param [proc, Class] sort A proc or a sort class, defaults to a simple order(attribute => direction)
45
53
  def sorts_by(attribute, sort = nil)
46
- sort ||= ->(collection, direction) { collection.order(attribute => direction) }
47
- @supported_sorts = {**supported_sorts, attribute => sort}
54
+ supported_sorts[attribute] = Sort::Static.new(attribute, sort)
55
+ end
56
+
57
+ # Registers an attribute prefix that can be dynamically used for sorting. Attribute prefix is stripped from parsed sort parameter and passed to the sort proc or class.
58
+ # @param [Symbol] attribute_prefix The "sortable" attribute prefix, e.g. `:'data.'` for sorting by `data.name` and `data.created_at`
59
+ # @param [proc, Class] sort A proc or a sort class, defaults to a simple order(attribute => direction)
60
+ def dynamically_sorts_by(attribute_prefix, sort)
61
+ supported_dynamic_sorts << Sort::Dynamic.new(attribute_prefix, sort)
48
62
  end
49
63
  end
50
64
 
@@ -76,7 +90,9 @@ module Jsonapi
76
90
  end
77
91
 
78
92
  def ensure_permitted_sort_params!(sort_params)
79
- unpermitted_parameters = sort_params.map(&:attribute).map(&:to_sym) - self.class.supported_sorts.keys
93
+ unpermitted_parameters = sort_params.map(&:attribute).filter do |attribute|
94
+ !self.class.supported_sorts.key?(attribute.to_sym) && self.class.supported_dynamic_sorts.none? { |dynamic_sort| dynamic_sort.matches?(attribute) }
95
+ end
80
96
  return if unpermitted_parameters.size.zero?
81
97
 
82
98
  raise Errors::UnpermittedSortParameters, unpermitted_parameters
@@ -87,13 +103,11 @@ module Jsonapi
87
103
  return sort_by_default(collection) if sort_params.blank?
88
104
 
89
105
  sort_params.reduce(collection) do |sorted_collection, sort_param|
90
- sort = self.class.supported_sorts.fetch(sort_param.attribute.to_sym)
91
-
92
- if sort.respond_to?(:call)
93
- sort.call(sorted_collection, sort_param.direction)
94
- else
95
- sort.new(sorted_collection, sort_param.direction).results
106
+ sort = self.class.supported_sorts.fetch(sort_param.attribute.to_sym) do
107
+ self.class.supported_dynamic_sorts.find { |dynamic_sort| dynamic_sort.matches?(sort_param.attribute) }
96
108
  end
109
+
110
+ sort.results(sorted_collection, sort_param)
97
111
  end
98
112
  end
99
113
 
@@ -12,9 +12,8 @@ module Jsonapi
12
12
  def paginate(page_params)
13
13
  @params = {page: page_params}
14
14
 
15
- pagination_details, records = pagy collection, page: page_params[:number],
16
- items: page_params[:size],
17
- outset: page_params[:offset]
15
+ pagination_details, records = pagy(collection, page: page_params[:number], items: page_params[:size], outset: page_params[:offset])
16
+
18
17
  [records, pagination_details]
19
18
  end
20
19
 
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "pagy"
4
+ require "pagy/extras/items"
5
+ require "pagy/extras/countless"
6
+
7
+ module Jsonapi
8
+ module QueryBuilder
9
+ module Paginator
10
+ class PagyCountless < BasePaginator
11
+ include ::Pagy::Backend
12
+
13
+ def paginate(page_params)
14
+ @params = {page: page_params}
15
+
16
+ pagination_details, records = pagy_countless(collection, page: page_params[:number],
17
+ items: page_params[:size],
18
+ outset: page_params[:offset])
19
+
20
+ [records, pagination_details]
21
+ end
22
+
23
+ private
24
+
25
+ attr_reader :params
26
+ end
27
+ end
28
+ end
29
+ end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Jsonapi
4
4
  module QueryBuilder
5
- VERSION = "0.3.0"
5
+ VERSION = "0.4.0"
6
6
  end
7
7
  end
@@ -9,3 +9,4 @@ require "jsonapi/query_builder/version"
9
9
  require "jsonapi/query_builder/base_query"
10
10
  require "jsonapi/query_builder/base_filter"
11
11
  require "jsonapi/query_builder/base_sort"
12
+ require "jsonapi/query_builder/dynamic_sort"
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jsonapi-query_builder
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jure Cindro
8
- autorequire:
9
8
  bindir: exe
10
9
  cert_chain: []
11
- date: 2021-12-07 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: activerecord
@@ -16,14 +15,14 @@ dependencies:
16
15
  requirements:
17
16
  - - ">="
18
17
  - !ruby/object:Gem::Version
19
- version: '5'
18
+ version: '7.2'
20
19
  type: :runtime
21
20
  prerelease: false
22
21
  version_requirements: !ruby/object:Gem::Requirement
23
22
  requirements:
24
23
  - - ">="
25
24
  - !ruby/object:Gem::Version
26
- version: '5'
25
+ version: '7.2'
27
26
  - !ruby/object:Gem::Dependency
28
27
  name: pagy
29
28
  requirement: !ruby/object:Gem::Requirement
@@ -236,17 +235,21 @@ files:
236
235
  - lib/jsonapi/query_builder/base_filter.rb
237
236
  - lib/jsonapi/query_builder/base_query.rb
238
237
  - lib/jsonapi/query_builder/base_sort.rb
238
+ - lib/jsonapi/query_builder/dynamic_sort.rb
239
239
  - lib/jsonapi/query_builder/errors/unpermitted_sort_parameters.rb
240
240
  - lib/jsonapi/query_builder/mixins/filter.rb
241
241
  - lib/jsonapi/query_builder/mixins/include.rb
242
242
  - lib/jsonapi/query_builder/mixins/paginate.rb
243
243
  - lib/jsonapi/query_builder/mixins/sort.rb
244
+ - lib/jsonapi/query_builder/mixins/sort/dynamic.rb
244
245
  - lib/jsonapi/query_builder/mixins/sort/param.rb
246
+ - lib/jsonapi/query_builder/mixins/sort/static.rb
245
247
  - lib/jsonapi/query_builder/paginator.rb
246
248
  - lib/jsonapi/query_builder/paginator/base_paginator.rb
247
249
  - lib/jsonapi/query_builder/paginator/kaminari.rb
248
250
  - lib/jsonapi/query_builder/paginator/keyset.rb
249
251
  - lib/jsonapi/query_builder/paginator/pagy.rb
252
+ - lib/jsonapi/query_builder/paginator/pagy_countless.rb
250
253
  - lib/jsonapi/query_builder/version.rb
251
254
  homepage: https://github.com/infinum/jsonapi-query_builder
252
255
  licenses:
@@ -255,7 +258,6 @@ metadata:
255
258
  homepage_uri: https://github.com/infinum/jsonapi-query_builder
256
259
  source_code_uri: https://github.com/infinum/jsonapi-query_builder
257
260
  changelog_uri: https://github.com/infinum/jsonapi-query_builder/blob/master/CHANGELOG.md
258
- post_install_message:
259
261
  rdoc_options: []
260
262
  require_paths:
261
263
  - lib
@@ -263,15 +265,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
263
265
  requirements:
264
266
  - - ">="
265
267
  - !ruby/object:Gem::Version
266
- version: '2.5'
268
+ version: '3.2'
267
269
  required_rubygems_version: !ruby/object:Gem::Requirement
268
270
  requirements:
269
271
  - - ">="
270
272
  - !ruby/object:Gem::Version
271
273
  version: '0'
272
274
  requirements: []
273
- rubygems_version: 3.2.22
274
- signing_key:
275
+ rubygems_version: 3.6.9
275
276
  specification_version: 4
276
277
  summary: Support `json:api` querying with ease!
277
278
  test_files: []