graphiti 1.2.44 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1c0d06bf22a3732408737c7c603c500ba8f7c71f339f6782e96d93b290e2db84
4
- data.tar.gz: 47f4cadecfe0b119dd2ad3de56ff87a6cd1f59a1d2bda572a98c57d142d4a059
3
+ metadata.gz: c694cce2123c7ba03ae53b53b61b9aaa5c353681e28a93722bc73569845ea2e2
4
+ data.tar.gz: 2305bdf6566d1bcba126dbe893dd64f6f011367151e0a283185fba62781d0d02
5
5
  SHA512:
6
- metadata.gz: 13d3880b37b14c2d22f8702c8a5f09cebd6a2ce4768018f4e109e9d05666d3b0da19d5685462978cd76d3f6f5ac8400283e3298d7d558c96af3077ba83cd2955
7
- data.tar.gz: 3470e79878d650afb8ca1bddf70d510b8a0e0fdb208945307ffeb24436ab793428c6627d746200d1eb33718fd23f3e77163fbb97bf9f1147a4283e5388a53b6f
6
+ metadata.gz: 3d9d20b0b87720079461b0ce245970da308362616cb4c21c4232fb85c585a62694f3bdb874db3cf8d80e94e02ff3078c119e0a0a46e95dbdb94e439dbf5a1af8
7
+ data.tar.gz: 9cf83060d95a7789351f3f0979ccf46012238975248159d8a5fccd0e457b512cfc127b3a4295c46f668b80717dfec2152fea025d00a82a1ffcdd42edde9e5c7f
@@ -14,11 +14,19 @@ module Graphiti
14
14
  links[:self] = pagination_link(current_page)
15
15
  links[:first] = pagination_link(1)
16
16
  links[:last] = pagination_link(last_page)
17
- links[:prev] = pagination_link(current_page - 1) unless current_page == 1
18
- links[:next] = pagination_link(current_page + 1) unless current_page == last_page
17
+ links[:prev] = pagination_link(current_page - 1) if has_previous_page?
18
+ links[:next] = pagination_link(current_page + 1) if has_next_page?
19
19
  end.select { |k, v| !v.nil? }
20
20
  end
21
21
 
22
+ def has_next_page?
23
+ current_page != last_page && last_page.present?
24
+ end
25
+
26
+ def has_previous_page?
27
+ current_page != 1
28
+ end
29
+
22
30
  private
23
31
 
24
32
  def pagination_params
@@ -733,6 +733,12 @@ module Graphiti
733
733
  end
734
734
  end
735
735
 
736
+ class UnsupportedBeforeCursor < Base
737
+ def message
738
+ "Passing in page[before] and page[number] is not supported. Please create an issue if you need it!"
739
+ end
740
+ end
741
+
736
742
  class InvalidInclude < Base
737
743
  def initialize(resource, relationship)
738
744
  @resource = resource
@@ -101,6 +101,10 @@ module Graphiti
101
101
  hash[:_type] = jsonapi_type.to_s
102
102
  end
103
103
 
104
+ if (fields_list || []).include?(:_cursor)
105
+ hash[:_cursor] = cursor
106
+ end
107
+
104
108
  if (fields_list || []).include?(:__typename)
105
109
  resource_class = @resource.class
106
110
  if polymorphic_subclass?
@@ -142,6 +146,10 @@ module Graphiti
142
146
  nodes = get_nodes(serializers, opts)
143
147
  add_nodes(hash, top_level_key, options, nodes, @graphql)
144
148
  add_stats(hash, top_level_key, options, @graphql)
149
+ if @graphql
150
+ add_page_info(hash, serializers, top_level_key, options)
151
+ end
152
+
145
153
  hash
146
154
  end
147
155
 
@@ -160,7 +168,7 @@ module Graphiti
160
168
 
161
169
  def get_nodes(serializers, opts)
162
170
  if serializers.is_a?(Array)
163
- serializers.map do |s|
171
+ serializers.each_with_index.map do |s, index|
164
172
  s.to_hash(**opts)
165
173
  end
166
174
  else
@@ -191,5 +199,31 @@ module Graphiti
191
199
  end
192
200
  end
193
201
  end
202
+
203
+ # NB - this is only for top-level right now
204
+ # The casing here is GQL-specific, we can update later if needed.
205
+ def add_page_info(hash, serializers, top_level_key, options)
206
+ if (fields = options[:fields].try(:[], :page_info))
207
+ info = {}
208
+
209
+ if fields.include?(:has_next_page)
210
+ info[:hasNextPage] = options[:proxy].pagination.has_next_page?
211
+ end
212
+
213
+ if fields.include?(:has_previous_page)
214
+ info[:hasPreviousPage] = options[:proxy].pagination.has_previous_page?
215
+ end
216
+
217
+ if fields.include?(:start_cursor)
218
+ info[:startCursor] = serializers.first.cursor
219
+ end
220
+
221
+ if fields.include?(:end_cursor)
222
+ info[:endCursor] = serializers.last.cursor
223
+ end
224
+
225
+ hash[top_level_key][:pageInfo] = info
226
+ end
227
+ end
194
228
  end
195
229
  end
@@ -191,12 +191,13 @@ module Graphiti
191
191
  (@params[:page] || {}).each_pair do |name, value|
192
192
  if legacy_nested?(name)
193
193
  value.each_pair do |k, v|
194
- hash[k.to_sym] = v.to_i
194
+ hash[k.to_sym] = cast_page_param(k.to_sym, v)
195
195
  end
196
196
  elsif nested?(name)
197
- hash[name.to_s.split(".").last.to_sym] = value
198
- elsif top_level? && [:number, :size, :offset].include?(name.to_sym)
199
- hash[name.to_sym] = value.to_i
197
+ param_name = name.to_s.split(".").last.to_sym
198
+ hash[param_name] = cast_page_param(param_name, value)
199
+ elsif top_level? && Scoping::Paginate::PARAMS.include?(name.to_sym)
200
+ hash[name.to_sym] = cast_page_param(name.to_sym, value)
200
201
  end
201
202
  end
202
203
  end
@@ -240,6 +241,18 @@ module Graphiti
240
241
 
241
242
  private
242
243
 
244
+ def cast_page_param(name, value)
245
+ if [:before, :after].include?(name)
246
+ decode_cursor(value)
247
+ else
248
+ value.to_i
249
+ end
250
+ end
251
+
252
+ def decode_cursor(cursor)
253
+ JSON.parse(Base64.decode64(cursor)).symbolize_keys
254
+ end
255
+
243
256
  # Try to find on this resource
244
257
  # If not there, follow the legacy logic of scalling all other
245
258
  # resource names/types
@@ -66,6 +66,7 @@ module Graphiti
66
66
  options[:meta] ||= proxy.meta
67
67
  options[:meta][:stats] = proxy.stats unless proxy.stats.empty?
68
68
  options[:meta][:debug] = Debugger.to_a if debug_json?
69
+ options[:proxy] = proxy
69
70
 
70
71
  renderer.render(records, options)
71
72
  end
@@ -28,11 +28,12 @@ module Graphiti
28
28
  serializer
29
29
  end
30
30
 
31
- def decorate_record(record)
31
+ def decorate_record(record, index = nil)
32
32
  unless record.instance_variable_get(:@__graphiti_serializer)
33
33
  serializer = serializer_for(record)
34
34
  record.instance_variable_set(:@__graphiti_serializer, serializer)
35
35
  record.instance_variable_set(:@__graphiti_resource, self)
36
+ record.instance_variable_set(:@__graphiti_index, index) if index
36
37
  end
37
38
  end
38
39
 
@@ -92,7 +92,8 @@ module Graphiti
92
92
  :relationships_writable_by_default,
93
93
  :filters_accept_nil_by_default,
94
94
  :filters_deny_empty_by_default,
95
- :graphql_entrypoint
95
+ :graphql_entrypoint,
96
+ :cursor_paginatable
96
97
 
97
98
  class << self
98
99
  prepend Overrides
@@ -85,8 +85,8 @@ module Graphiti
85
85
  # Used to ensure the resource's serializer is used
86
86
  # Not one derived through the usual jsonapi-rb logic
87
87
  def assign_serializer(records)
88
- records.each do |r|
89
- @resource.decorate_record(r)
88
+ records.each_with_index do |r, index|
89
+ @resource.decorate_record(r, index)
90
90
  end
91
91
  end
92
92
 
@@ -1,6 +1,7 @@
1
1
  module Graphiti
2
2
  class Scoping::Paginate < Scoping::Base
3
3
  DEFAULT_PAGE_SIZE = 20
4
+ PARAMS = [:number, :size, :offset, :before, :after]
4
5
 
5
6
  def apply
6
7
  if size > resource.max_page_size
@@ -56,7 +57,7 @@ module Graphiti
56
57
  private
57
58
 
58
59
  def requested?
59
- ![page_param[:size], page_param[:number]].all?(&:nil?)
60
+ !PARAMS.map { |p| page_param[p] }.all?(&:nil?)
60
61
  end
61
62
 
62
63
  def page_param
@@ -64,9 +65,34 @@ module Graphiti
64
65
  end
65
66
 
66
67
  def offset
68
+ offset = nil
69
+
67
70
  if (value = page_param[:offset])
68
- value.to_i
71
+ offset = value.to_i
72
+ end
73
+
74
+ if before_cursor&.key?(:offset)
75
+ if page_param.key?(:number)
76
+ raise Errors::UnsupportedBeforeCursor
77
+ end
78
+
79
+ offset = before_cursor[:offset] - (size * number) - 1
80
+ offset = 0 if offset.negative?
81
+ end
82
+
83
+ if after_cursor&.key?(:offset)
84
+ offset = after_cursor[:offset]
69
85
  end
86
+
87
+ offset
88
+ end
89
+
90
+ def after_cursor
91
+ page_param[:after]
92
+ end
93
+
94
+ def before_cursor
95
+ page_param[:before]
70
96
  end
71
97
 
72
98
  def number
@@ -45,6 +45,23 @@ module Graphiti
45
45
  end
46
46
  end
47
47
 
48
+ def cursor
49
+ starting_offset = 0
50
+ page_param = @proxy.query.pagination
51
+ if (page_number = page_param[:number])
52
+ page_size = page_param[:size] || @resource.default_page_size
53
+ starting_offset = (page_number - 1) * page_size
54
+ end
55
+
56
+ if (cursor = page_param[:after])
57
+ starting_offset = cursor[:offset]
58
+ end
59
+
60
+ current_offset = @object.instance_variable_get(:@__graphiti_index)
61
+ offset = starting_offset + current_offset + 1 # (+ 1 b/c o-base index)
62
+ Base64.encode64({offset: offset}.to_json).chomp
63
+ end
64
+
48
65
  def as_jsonapi(kwargs = {})
49
66
  super(**kwargs).tap do |hash|
50
67
  strip_relationships!(hash) if strip_relationships?
@@ -28,6 +28,12 @@ module Graphiti
28
28
 
29
29
  existing = @serializer.send(applied_method)
30
30
  @serializer.send(:"#{applied_method}=", [@name] | existing)
31
+
32
+ @serializer.meta do
33
+ if !!@resource.try(:cursor_paginatable?) && !Graphiti.context[:graphql]
34
+ {cursor: cursor}
35
+ end
36
+ end
31
37
  end
32
38
 
33
39
  private
@@ -1,3 +1,3 @@
1
1
  module Graphiti
2
- VERSION = "1.2.44"
2
+ VERSION = "1.3.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: graphiti
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.44
4
+ version: 1.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Lee Richmond
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-06-25 00:00:00.000000000 Z
11
+ date: 2021-08-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: jsonapi-serializable
@@ -361,7 +361,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
361
361
  - !ruby/object:Gem::Version
362
362
  version: '0'
363
363
  requirements: []
364
- rubygems_version: 3.0.3
364
+ rubygems_version: 3.1.4
365
365
  signing_key:
366
366
  specification_version: 4
367
367
  summary: Easily build jsonapi.org-compatible APIs