graphiti 1.2.44 → 1.3.9
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/.github/workflows/ci.yml +96 -0
- data/.standard.yml +4 -4
- data/Appraisals +18 -44
- data/CHANGELOG.md +1 -0
- data/gemfiles/rails_5_2.gemfile +2 -2
- data/gemfiles/rails_5_2_graphiti_rails.gemfile +3 -4
- data/gemfiles/rails_6_graphiti_rails.gemfile +1 -2
- data/gemfiles/{rails_5_1.gemfile → rails_7.gemfile} +2 -2
- data/gemfiles/{rails_4.gemfile → rails_7_graphiti_rails.gemfile} +3 -2
- data/graphiti.gemspec +5 -5
- data/lib/graphiti/adapters/abstract.rb +5 -1
- data/lib/graphiti/adapters/active_record.rb +42 -34
- data/lib/graphiti/adapters/persistence/associations.rb +13 -15
- data/lib/graphiti/delegates/pagination.rb +14 -6
- data/lib/graphiti/errors.rb +17 -11
- data/lib/graphiti/extensions/temp_id.rb +1 -1
- data/lib/graphiti/filter_operators.rb +0 -1
- data/lib/graphiti/hash_renderer.rb +40 -2
- data/lib/graphiti/query.rb +71 -68
- data/lib/graphiti/railtie.rb +4 -4
- data/lib/graphiti/renderer.rb +1 -0
- data/lib/graphiti/request_validator.rb +1 -1
- data/lib/graphiti/resource/configuration.rb +2 -1
- data/lib/graphiti/resource/dsl.rb +14 -6
- data/lib/graphiti/resource/polymorphism.rb +1 -1
- data/lib/graphiti/resource/sideloading.rb +4 -4
- data/lib/graphiti/resource.rb +2 -1
- data/lib/graphiti/resource_proxy.rb +8 -2
- data/lib/graphiti/schema.rb +6 -4
- data/lib/graphiti/scope.rb +2 -2
- data/lib/graphiti/scoping/paginate.rb +28 -2
- data/lib/graphiti/scoping/sort.rb +4 -6
- data/lib/graphiti/serializer.rb +19 -1
- data/lib/graphiti/sideload/polymorphic_belongs_to.rb +3 -4
- data/lib/graphiti/stats/dsl.rb +0 -1
- data/lib/graphiti/util/serializer_attributes.rb +6 -0
- data/lib/graphiti/util/simple_errors.rb +3 -3
- data/lib/graphiti/version.rb +1 -1
- data/lib/graphiti.rb +1 -0
- metadata +17 -23
- data/.travis.yml +0 -94
- data/gemfiles/rails_5_0.gemfile +0 -18
- data/gemfiles/rails_5_0_graphiti_rails.gemfile +0 -20
- data/gemfiles/rails_5_1_graphiti_rails.gemfile +0 -20
@@ -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
|
@@ -184,12 +192,42 @@ module Graphiti
|
|
184
192
|
if options[:meta] && !options[:meta].empty?
|
185
193
|
if @graphql
|
186
194
|
if (stats = options[:meta][:stats])
|
187
|
-
|
195
|
+
camelized = {}
|
196
|
+
stats.each_pair do |key, value|
|
197
|
+
camelized[key.to_s.camelize(:lower).to_sym] = value
|
198
|
+
end
|
199
|
+
hash[top_level_key][:stats] = camelized
|
188
200
|
end
|
189
201
|
else
|
190
202
|
hash.merge!(options.slice(:meta))
|
191
203
|
end
|
192
204
|
end
|
193
205
|
end
|
206
|
+
|
207
|
+
# NB - this is only for top-level right now
|
208
|
+
# The casing here is GQL-specific, we can update later if needed.
|
209
|
+
def add_page_info(hash, serializers, top_level_key, options)
|
210
|
+
if (fields = options[:fields].try(:[], :page_info))
|
211
|
+
info = {}
|
212
|
+
|
213
|
+
if fields.include?(:has_next_page)
|
214
|
+
info[:hasNextPage] = options[:proxy].pagination.has_next_page?
|
215
|
+
end
|
216
|
+
|
217
|
+
if fields.include?(:has_previous_page)
|
218
|
+
info[:hasPreviousPage] = options[:proxy].pagination.has_previous_page?
|
219
|
+
end
|
220
|
+
|
221
|
+
if fields.include?(:start_cursor)
|
222
|
+
info[:startCursor] = serializers.first.try(:cursor)
|
223
|
+
end
|
224
|
+
|
225
|
+
if fields.include?(:end_cursor)
|
226
|
+
info[:endCursor] = serializers.last.try(:cursor)
|
227
|
+
end
|
228
|
+
|
229
|
+
hash[top_level_key][:pageInfo] = info
|
230
|
+
end
|
231
|
+
end
|
194
232
|
end
|
195
233
|
end
|
data/lib/graphiti/query.rb
CHANGED
@@ -69,11 +69,9 @@ module Graphiti
|
|
69
69
|
end
|
70
70
|
|
71
71
|
def sideload_hash
|
72
|
-
@sideload_hash =
|
73
|
-
|
74
|
-
|
75
|
-
hash[key] = sideloads[key].hash
|
76
|
-
end
|
72
|
+
@sideload_hash = {}.tap do |hash|
|
73
|
+
sideloads.each_pair do |key, value|
|
74
|
+
hash[key] = sideloads[key].hash
|
77
75
|
end
|
78
76
|
end
|
79
77
|
end
|
@@ -89,30 +87,28 @@ module Graphiti
|
|
89
87
|
end
|
90
88
|
|
91
89
|
def sideloads
|
92
|
-
@sideloads ||=
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
handle_missing_sideload(key)
|
115
|
-
end
|
90
|
+
@sideloads ||= {}.tap do |hash|
|
91
|
+
include_hash.each_pair do |key, sub_hash|
|
92
|
+
sideload = @resource.class.sideload(key)
|
93
|
+
|
94
|
+
if sideload || @resource.remote?
|
95
|
+
sl_resource = resource_for_sideload(sideload)
|
96
|
+
query_parents = parents + [self]
|
97
|
+
sub_hash = sub_hash[:include] if sub_hash.key?(:include)
|
98
|
+
|
99
|
+
# NB: To handle on__<type>--<name>
|
100
|
+
# A) relationship_name == :positions
|
101
|
+
# B) key == on__employees.positions
|
102
|
+
# This way A) ensures sideloads are resolved
|
103
|
+
# And B) ensures nested filters, sorts etc still work
|
104
|
+
relationship_name = sideload ? sideload.name : key
|
105
|
+
hash[relationship_name] = Query.new sl_resource,
|
106
|
+
@params,
|
107
|
+
key,
|
108
|
+
sub_hash,
|
109
|
+
query_parents, :all
|
110
|
+
else
|
111
|
+
handle_missing_sideload(key)
|
116
112
|
end
|
117
113
|
end
|
118
114
|
end
|
@@ -137,27 +133,25 @@ module Graphiti
|
|
137
133
|
end
|
138
134
|
|
139
135
|
def filters
|
140
|
-
@filters ||=
|
141
|
-
{}.
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
hash[filter_name] = filter_value
|
152
|
-
end
|
136
|
+
@filters ||= {}.tap do |hash|
|
137
|
+
(@params[:filter] || {}).each_pair do |name, value|
|
138
|
+
name = name.to_sym
|
139
|
+
|
140
|
+
if legacy_nested?(name)
|
141
|
+
value.keys.each do |key|
|
142
|
+
filter_name = key.to_sym
|
143
|
+
filter_value = value[key]
|
144
|
+
|
145
|
+
if @resource.get_attr!(filter_name, :filterable, request: true)
|
146
|
+
hash[filter_name] = filter_value
|
153
147
|
end
|
154
|
-
elsif nested?(name)
|
155
|
-
name = name.to_s.split(".").last.to_sym
|
156
|
-
validate!(name, :filterable)
|
157
|
-
hash[name] = value
|
158
|
-
elsif top_level? && validate!(name, :filterable)
|
159
|
-
hash[name] = value
|
160
148
|
end
|
149
|
+
elsif nested?(name)
|
150
|
+
name = name.to_s.split(".").last.to_sym
|
151
|
+
validate!(name, :filterable)
|
152
|
+
hash[name] = value
|
153
|
+
elsif top_level? && validate!(name, :filterable)
|
154
|
+
hash[name] = value
|
161
155
|
end
|
162
156
|
end
|
163
157
|
end
|
@@ -186,18 +180,17 @@ module Graphiti
|
|
186
180
|
end
|
187
181
|
|
188
182
|
def pagination
|
189
|
-
@pagination ||=
|
190
|
-
{}.
|
191
|
-
(
|
192
|
-
|
193
|
-
|
194
|
-
hash[k.to_sym] = v.to_i
|
195
|
-
end
|
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
|
183
|
+
@pagination ||= {}.tap do |hash|
|
184
|
+
(@params[:page] || {}).each_pair do |name, value|
|
185
|
+
if legacy_nested?(name)
|
186
|
+
value.each_pair do |k, v|
|
187
|
+
hash[k.to_sym] = cast_page_param(k.to_sym, v)
|
200
188
|
end
|
189
|
+
elsif nested?(name)
|
190
|
+
param_name = name.to_s.split(".").last.to_sym
|
191
|
+
hash[param_name] = cast_page_param(param_name, value)
|
192
|
+
elsif top_level? && Scoping::Paginate::PARAMS.include?(name.to_sym)
|
193
|
+
hash[name.to_sym] = cast_page_param(name.to_sym, value)
|
201
194
|
end
|
202
195
|
end
|
203
196
|
end
|
@@ -220,15 +213,13 @@ module Graphiti
|
|
220
213
|
end
|
221
214
|
|
222
215
|
def stats
|
223
|
-
@stats ||=
|
224
|
-
{}.
|
225
|
-
(
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
hash[k.to_sym] = Array(v).flatten.map(&:to_sym)
|
231
|
-
end
|
216
|
+
@stats ||= {}.tap do |hash|
|
217
|
+
(@params[:stats] || {}).each_pair do |k, v|
|
218
|
+
if legacy_nested?(k)
|
219
|
+
raise NotImplementedError.new("Association statistics are not currently supported")
|
220
|
+
elsif top_level?
|
221
|
+
v = v.split(",") if v.is_a?(String)
|
222
|
+
hash[k.to_sym] = Array(v).flatten.map(&:to_sym)
|
232
223
|
end
|
233
224
|
end
|
234
225
|
end
|
@@ -240,6 +231,18 @@ module Graphiti
|
|
240
231
|
|
241
232
|
private
|
242
233
|
|
234
|
+
def cast_page_param(name, value)
|
235
|
+
if [:before, :after].include?(name)
|
236
|
+
decode_cursor(value)
|
237
|
+
else
|
238
|
+
value.to_i
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
def decode_cursor(cursor)
|
243
|
+
JSON.parse(Base64.decode64(cursor)).symbolize_keys
|
244
|
+
end
|
245
|
+
|
243
246
|
# Try to find on this resource
|
244
247
|
# If not there, follow the legacy logic of scalling all other
|
245
248
|
# resource names/types
|
data/lib/graphiti/railtie.rb
CHANGED
@@ -110,10 +110,10 @@ module Graphiti
|
|
110
110
|
end
|
111
111
|
|
112
112
|
route = begin
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
113
|
+
::Rails.application.routes.recognize_path(path, method: method)
|
114
|
+
rescue
|
115
|
+
nil
|
116
|
+
end
|
117
117
|
"#{route[:controller]}_controller".classify.safe_constantize if route
|
118
118
|
}
|
119
119
|
end
|
data/lib/graphiti/renderer.rb
CHANGED
@@ -9,7 +9,11 @@ module Graphiti
|
|
9
9
|
opts = args.extract_options!
|
10
10
|
type_override = args[0]
|
11
11
|
|
12
|
-
if (att =
|
12
|
+
if (att = (attributes[name] || extra_attributes[name]))
|
13
|
+
# We're opting in to filtering, so force this
|
14
|
+
# UNLESS the filter is guarded at the attribute level
|
15
|
+
att[:filterable] = true if att[:filterable] == false
|
16
|
+
|
13
17
|
aliases = [name, opts[:aliases]].flatten.compact
|
14
18
|
operators = FilterOperators.build(self, att[:type], opts, &blk)
|
15
19
|
|
@@ -23,6 +27,8 @@ module Graphiti
|
|
23
27
|
end
|
24
28
|
|
25
29
|
required = att[:filterable] == :required || !!opts[:required]
|
30
|
+
schema = !!opts[:via_attribute_dsl] ? att[:schema] : opts[:schema] != false
|
31
|
+
|
26
32
|
config[:filters][name.to_sym] = {
|
27
33
|
aliases: aliases,
|
28
34
|
name: name.to_sym,
|
@@ -32,6 +38,7 @@ module Graphiti
|
|
32
38
|
single: !!opts[:single],
|
33
39
|
dependencies: opts[:dependent],
|
34
40
|
required: required,
|
41
|
+
schema: schema,
|
35
42
|
operators: operators.to_hash,
|
36
43
|
allow_nil: opts.fetch(:allow_nil, filters_accept_nil_by_default),
|
37
44
|
deny_empty: opts.fetch(:deny_empty, filters_deny_empty_by_default)
|
@@ -56,7 +63,7 @@ module Graphiti
|
|
56
63
|
end
|
57
64
|
|
58
65
|
def sort_all(&blk)
|
59
|
-
if
|
66
|
+
if blk
|
60
67
|
config[:_sort_all] = blk
|
61
68
|
else
|
62
69
|
config[:_sort_all]
|
@@ -130,7 +137,7 @@ module Graphiti
|
|
130
137
|
options[:sortable] ? sort(name) : config[:sorts].delete(name)
|
131
138
|
|
132
139
|
if options[:filterable]
|
133
|
-
filter(name, allow: options[:allow])
|
140
|
+
filter(name, allow: options[:allow], via_attribute_dsl: true)
|
134
141
|
else
|
135
142
|
config[:filters].delete(name)
|
136
143
|
end
|
@@ -144,7 +151,8 @@ module Graphiti
|
|
144
151
|
readable: true,
|
145
152
|
writable: false,
|
146
153
|
sortable: false,
|
147
|
-
filterable: false
|
154
|
+
filterable: false,
|
155
|
+
schema: true
|
148
156
|
}
|
149
157
|
options = defaults.merge(options)
|
150
158
|
attribute_option(options, :readable)
|
@@ -181,9 +189,9 @@ module Graphiti
|
|
181
189
|
def attribute_option(options, name, exclusive = false)
|
182
190
|
if options[name] != false
|
183
191
|
default = if (only = options[:only]) && !exclusive
|
184
|
-
Array(only).include?(name)
|
192
|
+
Array(only).include?(name)
|
185
193
|
elsif (except = options[:except]) && !exclusive
|
186
|
-
Array(except).include?(name)
|
194
|
+
!Array(except).include?(name)
|
187
195
|
else
|
188
196
|
send(:"attributes_#{name}_by_default")
|
189
197
|
end
|
@@ -72,7 +72,7 @@ module Graphiti
|
|
72
72
|
end
|
73
73
|
|
74
74
|
def resource_for_model(model)
|
75
|
-
resource = children.find { |c| model.
|
75
|
+
resource = children.find { |c| model.instance_of?(c.model) } ||
|
76
76
|
children.find { |c| model.is_a?(c.model) }
|
77
77
|
if resource.nil?
|
78
78
|
raise Errors::PolymorphicResourceChildNotFound.new(self, model: model)
|
@@ -68,10 +68,10 @@ module Graphiti
|
|
68
68
|
model_ref = model
|
69
69
|
has_many name, opts do
|
70
70
|
params do |hash|
|
71
|
-
hash[:filter][:"#{as}_type"] = model_ref.name
|
71
|
+
hash[:filter][:"#{as}_type"] = { eql: model_ref.name }
|
72
72
|
end
|
73
73
|
|
74
|
-
instance_eval(&blk) if
|
74
|
+
instance_eval(&blk) if blk
|
75
75
|
end
|
76
76
|
end
|
77
77
|
|
@@ -82,10 +82,10 @@ module Graphiti
|
|
82
82
|
model_ref = model
|
83
83
|
has_one name, opts do
|
84
84
|
params do |hash|
|
85
|
-
hash[:filter][:"#{as}_type"] = model_ref.name
|
85
|
+
hash[:filter][:"#{as}_type"] = { eql: model_ref.name }
|
86
86
|
end
|
87
87
|
|
88
|
-
instance_eval(&blk) if
|
88
|
+
instance_eval(&blk) if blk
|
89
89
|
end
|
90
90
|
end
|
91
91
|
|
data/lib/graphiti/resource.rb
CHANGED
@@ -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
|
|
@@ -73,7 +73,7 @@ module Graphiti
|
|
73
73
|
records
|
74
74
|
end
|
75
75
|
end
|
76
|
-
|
76
|
+
alias_method :to_a, :data
|
77
77
|
|
78
78
|
def meta
|
79
79
|
@meta ||= data.respond_to?(:meta) ? data.meta : {}
|
@@ -85,9 +85,15 @@ module Graphiti
|
|
85
85
|
|
86
86
|
def stats
|
87
87
|
@stats ||= if @query.hash[:stats]
|
88
|
+
scope = @scope.unpaginated_object
|
89
|
+
if resource.adapter.can_group?
|
90
|
+
if (group = @query.hash[:stats].delete(:group_by))
|
91
|
+
scope = resource.adapter.group(scope, group[0])
|
92
|
+
end
|
93
|
+
end
|
88
94
|
payload = Stats::Payload.new @resource,
|
89
95
|
@query,
|
90
|
-
|
96
|
+
scope,
|
91
97
|
data
|
92
98
|
payload.generate
|
93
99
|
else
|
data/lib/graphiti/schema.rb
CHANGED
@@ -153,6 +153,8 @@ module Graphiti
|
|
153
153
|
def extra_attributes(resource)
|
154
154
|
{}.tap do |attrs|
|
155
155
|
resource.extra_attributes.each_pair do |name, config|
|
156
|
+
next unless config[:schema]
|
157
|
+
|
156
158
|
attrs[name] = {
|
157
159
|
type: config[:type].to_s,
|
158
160
|
readable: flag(config[:readable]),
|
@@ -181,11 +183,11 @@ module Graphiti
|
|
181
183
|
def sorts(resource)
|
182
184
|
{}.tap do |s|
|
183
185
|
resource.sorts.each_pair do |name, sort|
|
184
|
-
|
186
|
+
attr = resource.all_attributes[name]
|
187
|
+
next unless attr[:schema]
|
185
188
|
|
186
189
|
config = {}
|
187
190
|
config[:only] = sort[:only] if sort[:only]
|
188
|
-
attr = resource.attributes[name]
|
189
191
|
if attr[:sortable].is_a?(Symbol)
|
190
192
|
config[:guard] = true
|
191
193
|
end
|
@@ -197,7 +199,7 @@ module Graphiti
|
|
197
199
|
def filters(resource)
|
198
200
|
{}.tap do |f|
|
199
201
|
resource.filters.each_pair do |name, filter|
|
200
|
-
next unless resource.
|
202
|
+
next unless resource.filters[name][:schema]
|
201
203
|
|
202
204
|
config = {
|
203
205
|
type: filter[:type].to_s,
|
@@ -209,7 +211,7 @@ module Graphiti
|
|
209
211
|
config[:deny] = filter[:deny].map(&:to_s) if filter[:deny]
|
210
212
|
config[:dependencies] = filter[:dependencies].map(&:to_s) if filter[:dependencies]
|
211
213
|
|
212
|
-
attr = resource.
|
214
|
+
attr = resource.all_attributes[name]
|
213
215
|
if attr[:filterable].is_a?(Symbol)
|
214
216
|
if attr[:filterable] == :required
|
215
217
|
config[:required] = true
|
data/lib/graphiti/scope.rb
CHANGED
@@ -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.
|
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
|
-
!
|
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
|
@@ -59,12 +59,10 @@ module Graphiti
|
|
59
59
|
end
|
60
60
|
|
61
61
|
def sort_param
|
62
|
-
@sort_param ||=
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
normalize(query_hash[:sort])
|
67
|
-
end
|
62
|
+
@sort_param ||= if query_hash[:sort].blank?
|
63
|
+
resource.default_sort || []
|
64
|
+
else
|
65
|
+
normalize(query_hash[:sort])
|
68
66
|
end
|
69
67
|
end
|
70
68
|
|
data/lib/graphiti/serializer.rb
CHANGED
@@ -25,8 +25,9 @@ module Graphiti
|
|
25
25
|
|
26
26
|
# See #requested_relationships
|
27
27
|
def self.relationship(name, options = {}, &block)
|
28
|
+
prev = Util::Hash.deep_dup(field_condition_blocks)
|
28
29
|
super
|
29
|
-
field_condition_blocks
|
30
|
+
self.field_condition_blocks = prev
|
30
31
|
_register_condition(relationship_condition_blocks, name, options)
|
31
32
|
end
|
32
33
|
|
@@ -45,6 +46,23 @@ module Graphiti
|
|
45
46
|
end
|
46
47
|
end
|
47
48
|
|
49
|
+
def cursor
|
50
|
+
starting_offset = 0
|
51
|
+
page_param = @proxy.query.pagination
|
52
|
+
if (page_number = page_param[:number])
|
53
|
+
page_size = page_param[:size] || @resource.default_page_size
|
54
|
+
starting_offset = (page_number - 1) * page_size
|
55
|
+
end
|
56
|
+
|
57
|
+
if (cursor = page_param[:after])
|
58
|
+
starting_offset = cursor[:offset]
|
59
|
+
end
|
60
|
+
|
61
|
+
current_offset = @object.instance_variable_get(:@__graphiti_index)
|
62
|
+
offset = starting_offset + current_offset + 1 # (+ 1 b/c o-base index)
|
63
|
+
Base64.encode64({offset: offset}.to_json).chomp
|
64
|
+
end
|
65
|
+
|
48
66
|
def as_jsonapi(kwargs = {})
|
49
67
|
super(**kwargs).tap do |hash|
|
50
68
|
strip_relationships!(hash) if strip_relationships?
|
@@ -7,7 +7,6 @@ class Graphiti::Sideload::PolymorphicBelongsTo < Graphiti::Sideload::BelongsTo
|
|
7
7
|
@calls = []
|
8
8
|
end
|
9
9
|
|
10
|
-
# rubocop: disable Style/MethodMissingSuper
|
11
10
|
def method_missing(name, *args, &blk)
|
12
11
|
@calls << [name, args, blk]
|
13
12
|
end
|
@@ -56,9 +55,9 @@ class Graphiti::Sideload::PolymorphicBelongsTo < Graphiti::Sideload::BelongsTo
|
|
56
55
|
args = call[1]
|
57
56
|
opts = args.extract_options!
|
58
57
|
opts.merge! as: sideload.name,
|
59
|
-
|
60
|
-
|
61
|
-
|
58
|
+
parent: sideload,
|
59
|
+
group_name: group.name,
|
60
|
+
polymorphic_child: true
|
62
61
|
unless sideload.resource.class.abstract_class?
|
63
62
|
opts[:foreign_key] ||= sideload.foreign_key
|
64
63
|
opts[:primary_key] ||= sideload.primary_key
|
data/lib/graphiti/stats/dsl.rb
CHANGED
@@ -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
|