graphql 1.11.4 → 1.11.8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/generators/graphql/object_generator.rb +2 -0
- data/lib/generators/graphql/templates/union.erb +1 -1
- data/lib/graphql.rb +17 -0
- data/lib/graphql/argument.rb +3 -3
- data/lib/graphql/backtrace/tracer.rb +2 -1
- data/lib/graphql/define/assign_global_id_field.rb +2 -2
- data/lib/graphql/execution/interpreter.rb +10 -0
- data/lib/graphql/execution/interpreter/arguments.rb +21 -6
- data/lib/graphql/execution/interpreter/arguments_cache.rb +8 -0
- data/lib/graphql/execution/interpreter/runtime.rb +70 -42
- data/lib/graphql/integer_decoding_error.rb +17 -0
- data/lib/graphql/introspection.rb +96 -0
- data/lib/graphql/introspection/field_type.rb +7 -3
- data/lib/graphql/introspection/input_value_type.rb +6 -0
- data/lib/graphql/introspection/introspection_query.rb +6 -92
- data/lib/graphql/introspection/type_type.rb +7 -3
- data/lib/graphql/invalid_null_error.rb +1 -1
- data/lib/graphql/language/block_string.rb +24 -5
- data/lib/graphql/language/lexer.rb +7 -3
- data/lib/graphql/language/lexer.rl +7 -3
- data/lib/graphql/language/nodes.rb +1 -1
- data/lib/graphql/language/parser.rb +107 -103
- data/lib/graphql/language/parser.y +4 -0
- data/lib/graphql/language/sanitized_printer.rb +59 -26
- data/lib/graphql/name_validator.rb +6 -7
- data/lib/graphql/pagination/connections.rb +11 -3
- data/lib/graphql/query.rb +6 -3
- data/lib/graphql/query/context.rb +14 -3
- data/lib/graphql/query/validation_pipeline.rb +1 -1
- data/lib/graphql/relay/array_connection.rb +2 -2
- data/lib/graphql/relay/range_add.rb +14 -5
- data/lib/graphql/schema.rb +47 -19
- data/lib/graphql/schema/argument.rb +56 -5
- data/lib/graphql/schema/build_from_definition.rb +67 -38
- data/lib/graphql/schema/default_type_error.rb +2 -0
- data/lib/graphql/schema/directive/deprecated.rb +1 -1
- data/lib/graphql/schema/field.rb +32 -16
- data/lib/graphql/schema/field/connection_extension.rb +8 -7
- data/lib/graphql/schema/field/scope_extension.rb +1 -1
- data/lib/graphql/schema/input_object.rb +5 -3
- data/lib/graphql/schema/interface.rb +1 -1
- data/lib/graphql/schema/late_bound_type.rb +2 -2
- data/lib/graphql/schema/loader.rb +1 -0
- data/lib/graphql/schema/member/build_type.rb +14 -4
- data/lib/graphql/schema/member/has_arguments.rb +54 -53
- data/lib/graphql/schema/member/has_fields.rb +2 -2
- data/lib/graphql/schema/member/type_system_helpers.rb +2 -2
- data/lib/graphql/schema/relay_classic_mutation.rb +4 -2
- data/lib/graphql/schema/timeout.rb +29 -15
- data/lib/graphql/schema/unique_within_type.rb +1 -2
- data/lib/graphql/schema/validation.rb +8 -0
- data/lib/graphql/static_validation.rb +1 -0
- data/lib/graphql/static_validation/all_rules.rb +1 -0
- data/lib/graphql/static_validation/rules/fields_will_merge.rb +25 -17
- data/lib/graphql/static_validation/rules/input_object_names_are_unique.rb +30 -0
- data/lib/graphql/static_validation/rules/input_object_names_are_unique_error.rb +30 -0
- data/lib/graphql/static_validation/validation_timeout_error.rb +25 -0
- data/lib/graphql/static_validation/validator.rb +29 -7
- data/lib/graphql/subscriptions.rb +1 -3
- data/lib/graphql/subscriptions/action_cable_subscriptions.rb +21 -7
- data/lib/graphql/tracing/platform_tracing.rb +1 -1
- data/lib/graphql/tracing/prometheus_tracing/graphql_collector.rb +4 -1
- data/lib/graphql/types/int.rb +9 -2
- data/lib/graphql/types/relay/base_connection.rb +2 -1
- data/lib/graphql/types/relay/base_edge.rb +2 -1
- data/lib/graphql/types/string.rb +7 -1
- data/lib/graphql/unauthorized_error.rb +1 -1
- data/lib/graphql/version.rb +1 -1
- data/readme.md +1 -1
- metadata +7 -3
@@ -45,7 +45,8 @@ module GraphQL
|
|
45
45
|
# @param camelize [Boolean] if true, the name will be camelized when building the schema
|
46
46
|
# @param from_resolver [Boolean] if true, a Resolver class defined this argument
|
47
47
|
# @param method_access [Boolean] If false, don't build method access on legacy {Query::Arguments} instances.
|
48
|
-
|
48
|
+
# @param deprecation_reason [String]
|
49
|
+
def initialize(arg_name = nil, type_expr = nil, desc = nil, required:, type: nil, name: nil, loads: nil, description: nil, ast_node: nil, default_value: NO_DEFAULT, as: nil, from_resolver: false, camelize: true, prepare: nil, method_access: true, owner:, deprecation_reason: nil, &definition_block)
|
49
50
|
arg_name ||= name
|
50
51
|
@name = -(camelize ? Member::BuildType.camelize(arg_name.to_s) : arg_name.to_s)
|
51
52
|
@type_expr = type_expr || type
|
@@ -60,6 +61,7 @@ module GraphQL
|
|
60
61
|
@ast_node = ast_node
|
61
62
|
@from_resolver = from_resolver
|
62
63
|
@method_access = method_access
|
64
|
+
self.deprecation_reason = deprecation_reason
|
63
65
|
|
64
66
|
if definition_block
|
65
67
|
if definition_block.arity == 1
|
@@ -89,6 +91,18 @@ module GraphQL
|
|
89
91
|
end
|
90
92
|
end
|
91
93
|
|
94
|
+
# @return [String] Deprecation reason for this argument
|
95
|
+
def deprecation_reason(text = nil)
|
96
|
+
if text
|
97
|
+
validate_deprecated_or_optional(null: @null, deprecation_reason: text)
|
98
|
+
@deprecation_reason = text
|
99
|
+
else
|
100
|
+
@deprecation_reason
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
alias_method :deprecation_reason=, :deprecation_reason
|
105
|
+
|
92
106
|
def visible?(context)
|
93
107
|
true
|
94
108
|
end
|
@@ -143,15 +157,32 @@ module GraphQL
|
|
143
157
|
if NO_DEFAULT != @default_value
|
144
158
|
argument.default_value = @default_value
|
145
159
|
end
|
160
|
+
if @deprecation_reason
|
161
|
+
argument.deprecation_reason = @deprecation_reason
|
162
|
+
end
|
146
163
|
argument
|
147
164
|
end
|
148
165
|
|
149
|
-
|
166
|
+
def type=(new_type)
|
167
|
+
validate_input_type(new_type)
|
168
|
+
# This isn't true for LateBoundTypes, but we can assume those will
|
169
|
+
# be updated via this codepath later in schema setup.
|
170
|
+
if new_type.respond_to?(:non_null?)
|
171
|
+
validate_deprecated_or_optional(null: !new_type.non_null?, deprecation_reason: deprecation_reason)
|
172
|
+
end
|
173
|
+
@type = new_type
|
174
|
+
end
|
150
175
|
|
151
176
|
def type
|
152
|
-
@type ||=
|
153
|
-
|
154
|
-
|
177
|
+
@type ||= begin
|
178
|
+
parsed_type = begin
|
179
|
+
Member::BuildType.parse_type(@type_expr, null: @null)
|
180
|
+
rescue StandardError => err
|
181
|
+
raise ArgumentError, "Couldn't build type for Argument #{@owner.name}.#{name}: #{err.class.name}: #{err.message}", err.backtrace
|
182
|
+
end
|
183
|
+
# Use the setter method to get validations
|
184
|
+
self.type = parsed_type
|
185
|
+
end
|
155
186
|
end
|
156
187
|
|
157
188
|
def statically_coercible?
|
@@ -186,6 +217,26 @@ module GraphQL
|
|
186
217
|
raise "Invalid prepare for #{@owner.name}.name: #{@prepare.inspect}"
|
187
218
|
end
|
188
219
|
end
|
220
|
+
|
221
|
+
private
|
222
|
+
|
223
|
+
def validate_input_type(input_type)
|
224
|
+
if input_type.is_a?(String) || input_type.is_a?(GraphQL::Schema::LateBoundType)
|
225
|
+
# Do nothing; assume this will be validated later
|
226
|
+
elsif input_type.kind.non_null? || input_type.kind.list?
|
227
|
+
validate_input_type(input_type.unwrap)
|
228
|
+
elsif !input_type.kind.input?
|
229
|
+
raise ArgumentError, "Invalid input type for #{path}: #{input_type.graphql_name}. Must be scalar, enum, or input object, not #{input_type.kind.name}."
|
230
|
+
else
|
231
|
+
# It's an input type, we're OK
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
def validate_deprecated_or_optional(null:, deprecation_reason:)
|
236
|
+
if deprecation_reason && !null
|
237
|
+
raise ArgumentError, "Required arguments cannot be deprecated: #{path}."
|
238
|
+
end
|
239
|
+
end
|
189
240
|
end
|
190
241
|
end
|
191
242
|
end
|
@@ -4,17 +4,24 @@ require "graphql/schema/build_from_definition/resolve_map"
|
|
4
4
|
module GraphQL
|
5
5
|
class Schema
|
6
6
|
module BuildFromDefinition
|
7
|
+
if !String.method_defined?(:-@)
|
8
|
+
using GraphQL::StringDedupBackport
|
9
|
+
end
|
10
|
+
|
7
11
|
class << self
|
8
12
|
# @see {Schema.from_definition}
|
9
|
-
def from_definition(definition_string,
|
10
|
-
|
11
|
-
default_resolve ||= {}
|
12
|
-
Builder.build(document, default_resolve: default_resolve, relay: relay, using: using, interpreter: interpreter)
|
13
|
+
def from_definition(definition_string, parser: GraphQL.default_parser, **kwargs)
|
14
|
+
from_document(parser.parse(definition_string), **kwargs)
|
13
15
|
end
|
14
|
-
end
|
15
16
|
|
16
|
-
|
17
|
-
|
17
|
+
def from_definition_path(definition_path, parser: GraphQL.default_parser, **kwargs)
|
18
|
+
from_document(parser.parse_file(definition_path), **kwargs)
|
19
|
+
end
|
20
|
+
|
21
|
+
def from_document(document, default_resolve:, using: {}, relay: false, interpreter: true)
|
22
|
+
Builder.build(document, default_resolve: default_resolve || {}, relay: relay, using: using, interpreter: interpreter)
|
23
|
+
end
|
24
|
+
end
|
18
25
|
|
19
26
|
# @api private
|
20
27
|
module Builder
|
@@ -43,7 +50,7 @@ module GraphQL
|
|
43
50
|
when GraphQL::Language::Nodes::EnumTypeDefinition
|
44
51
|
types[definition.name] = build_enum_type(definition, type_resolver)
|
45
52
|
when GraphQL::Language::Nodes::ObjectTypeDefinition
|
46
|
-
types[definition.name] = build_object_type(definition, type_resolver
|
53
|
+
types[definition.name] = build_object_type(definition, type_resolver)
|
47
54
|
when GraphQL::Language::Nodes::InterfaceTypeDefinition
|
48
55
|
types[definition.name] = build_interface_type(definition, type_resolver)
|
49
56
|
when GraphQL::Language::Nodes::UnionTypeDefinition
|
@@ -111,11 +118,11 @@ module GraphQL
|
|
111
118
|
end
|
112
119
|
|
113
120
|
if default_resolve.respond_to?(:resolve_type)
|
114
|
-
|
115
|
-
|
121
|
+
def self.resolve_type(*args)
|
122
|
+
self.definition_default_resolve.resolve_type(*args)
|
116
123
|
end
|
117
124
|
else
|
118
|
-
|
125
|
+
def self.resolve_type(*args)
|
119
126
|
NullResolveType.call(*args)
|
120
127
|
end
|
121
128
|
end
|
@@ -141,6 +148,20 @@ module GraphQL
|
|
141
148
|
|
142
149
|
# Empty `orphan_types` -- this will make unreachable types ... unreachable.
|
143
150
|
own_orphan_types.clear
|
151
|
+
|
152
|
+
class << self
|
153
|
+
attr_accessor :definition_default_resolve
|
154
|
+
end
|
155
|
+
|
156
|
+
self.definition_default_resolve = default_resolve
|
157
|
+
|
158
|
+
def definition_default_resolve
|
159
|
+
self.class.definition_default_resolve
|
160
|
+
end
|
161
|
+
|
162
|
+
def self.inherited(child_class)
|
163
|
+
child_class.definition_default_resolve = self.definition_default_resolve
|
164
|
+
end
|
144
165
|
end
|
145
166
|
end
|
146
167
|
|
@@ -176,23 +197,27 @@ module GraphQL
|
|
176
197
|
end
|
177
198
|
|
178
199
|
def build_scalar_type(scalar_type_definition, type_resolver, default_resolve:)
|
200
|
+
builder = self
|
179
201
|
Class.new(GraphQL::Schema::Scalar) do
|
180
202
|
graphql_name(scalar_type_definition.name)
|
181
203
|
description(scalar_type_definition.description)
|
182
204
|
ast_node(scalar_type_definition)
|
183
205
|
|
184
206
|
if default_resolve.respond_to?(:coerce_input)
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
define_singleton_method(:coerce_result) do |val, ctx|
|
190
|
-
default_resolve.coerce_result(self, val, ctx)
|
191
|
-
end
|
207
|
+
# Put these method definitions in another method to avoid retaining `type_resolve`
|
208
|
+
# from this method's bindiing
|
209
|
+
builder.build_scalar_type_coerce_method(self, :coerce_input, default_resolve)
|
210
|
+
builder.build_scalar_type_coerce_method(self, :coerce_result, default_resolve)
|
192
211
|
end
|
193
212
|
end
|
194
213
|
end
|
195
214
|
|
215
|
+
def build_scalar_type_coerce_method(scalar_class, method_name, default_definition_resolve)
|
216
|
+
scalar_class.define_singleton_method(method_name) do |val, ctx|
|
217
|
+
default_definition_resolve.public_send(method_name, self, val, ctx)
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
196
221
|
def build_union_type(union_type_definition, type_resolver)
|
197
222
|
Class.new(GraphQL::Schema::Union) do
|
198
223
|
graphql_name(union_type_definition.name)
|
@@ -202,13 +227,10 @@ module GraphQL
|
|
202
227
|
end
|
203
228
|
end
|
204
229
|
|
205
|
-
def build_object_type(object_type_definition, type_resolver
|
230
|
+
def build_object_type(object_type_definition, type_resolver)
|
206
231
|
builder = self
|
207
|
-
type_def = nil
|
208
|
-
typed_resolve_fn = ->(field, obj, args, ctx) { default_resolve.call(type_def, field, obj, args, ctx) }
|
209
232
|
|
210
233
|
Class.new(GraphQL::Schema::Object) do
|
211
|
-
type_def = self
|
212
234
|
graphql_name(object_type_definition.name)
|
213
235
|
description(object_type_definition.description)
|
214
236
|
ast_node(object_type_definition)
|
@@ -218,7 +240,7 @@ module GraphQL
|
|
218
240
|
implements(interface_defn)
|
219
241
|
end
|
220
242
|
|
221
|
-
builder.build_fields(self, object_type_definition.fields, type_resolver, default_resolve:
|
243
|
+
builder.build_fields(self, object_type_definition.fields, type_resolver, default_resolve: true)
|
222
244
|
end
|
223
245
|
end
|
224
246
|
|
@@ -247,13 +269,16 @@ module GraphQL
|
|
247
269
|
end
|
248
270
|
end
|
249
271
|
|
272
|
+
NO_DEFAULT_VALUE = {}.freeze
|
273
|
+
|
250
274
|
def build_arguments(type_class, arguments, type_resolver)
|
251
275
|
builder = self
|
252
276
|
|
253
277
|
arguments.each do |argument_defn|
|
254
|
-
default_value_kwargs =
|
255
|
-
|
256
|
-
|
278
|
+
default_value_kwargs = if !argument_defn.default_value.nil?
|
279
|
+
{ default_value: builder.build_default_value(argument_defn.default_value) }
|
280
|
+
else
|
281
|
+
NO_DEFAULT_VALUE
|
257
282
|
end
|
258
283
|
|
259
284
|
type_class.argument(
|
@@ -261,6 +286,7 @@ module GraphQL
|
|
261
286
|
type: type_resolver.call(argument_defn.type),
|
262
287
|
required: false,
|
263
288
|
description: argument_defn.description,
|
289
|
+
deprecation_reason: builder.build_deprecation_reason(argument_defn.directives),
|
264
290
|
ast_node: argument_defn,
|
265
291
|
camelize: false,
|
266
292
|
method_access: false,
|
@@ -295,10 +321,10 @@ module GraphQL
|
|
295
321
|
def build_fields(owner, field_definitions, type_resolver, default_resolve:)
|
296
322
|
builder = self
|
297
323
|
|
298
|
-
field_definitions.
|
324
|
+
field_definitions.each do |field_definition|
|
299
325
|
type_name = resolve_type_name(field_definition.type)
|
300
|
-
resolve_method_name = "resolve_field_#{field_definition.name}"
|
301
|
-
owner.field(
|
326
|
+
resolve_method_name = -"resolve_field_#{field_definition.name}"
|
327
|
+
schema_field_defn = owner.field(
|
302
328
|
field_definition.name,
|
303
329
|
description: field_definition.description,
|
304
330
|
type: type_resolver.call(field_definition.type),
|
@@ -310,16 +336,19 @@ module GraphQL
|
|
310
336
|
method_conflict_warning: false,
|
311
337
|
camelize: false,
|
312
338
|
resolver_method: resolve_method_name,
|
313
|
-
)
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
339
|
+
)
|
340
|
+
|
341
|
+
builder.build_arguments(schema_field_defn, field_definition.arguments, type_resolver)
|
342
|
+
|
343
|
+
# Don't do this for interfaces
|
344
|
+
if default_resolve
|
345
|
+
owner.class_eval <<-RUBY, __FILE__, __LINE__
|
346
|
+
# frozen_string_literal: true
|
347
|
+
def #{resolve_method_name}(**args)
|
348
|
+
field_instance = self.class.get_field("#{field_definition.name}")
|
349
|
+
context.schema.definition_default_resolve.call(self.class, field_instance, object, args, context)
|
321
350
|
end
|
322
|
-
|
351
|
+
RUBY
|
323
352
|
end
|
324
353
|
end
|
325
354
|
end
|
@@ -4,7 +4,7 @@ module GraphQL
|
|
4
4
|
class Directive < GraphQL::Schema::Member
|
5
5
|
class Deprecated < GraphQL::Schema::Directive
|
6
6
|
description "Marks an element of a GraphQL schema as no longer supported."
|
7
|
-
locations(GraphQL::Schema::Directive::FIELD_DEFINITION, GraphQL::Schema::Directive::ENUM_VALUE)
|
7
|
+
locations(GraphQL::Schema::Directive::FIELD_DEFINITION, GraphQL::Schema::Directive::ENUM_VALUE, GraphQL::Schema::Directive::ARGUMENT_DEFINITION, GraphQL::Schema::Directive::INPUT_FIELD_DEFINITION)
|
8
8
|
|
9
9
|
reason_description = "Explains why this element was deprecated, usually also including a "\
|
10
10
|
"suggestion for how to access supported similar data. Formatted "\
|
data/lib/graphql/schema/field.rb
CHANGED
@@ -203,7 +203,7 @@ module GraphQL
|
|
203
203
|
# @param broadcastable [Boolean] Whether or not this field can be distributed in subscription broadcasts
|
204
204
|
# @param ast_node [Language::Nodes::FieldDefinition, nil] If this schema was parsed from definition, this AST node defined the field
|
205
205
|
# @param method_conflict_warning [Boolean] If false, skip the warning if this field's method conflicts with a built-in method
|
206
|
-
def initialize(type: nil, name: nil, owner: nil, null: nil, field: nil, function: nil, description: nil, deprecation_reason: nil, method: nil, hash_key: nil, resolver_method: nil, resolve: nil, connection: nil, max_page_size: :not_given, scope: nil, introspection: false, camelize: true, trace: nil, complexity: 1, ast_node: nil, extras:
|
206
|
+
def initialize(type: nil, name: nil, owner: nil, null: nil, field: nil, function: nil, description: nil, deprecation_reason: nil, method: nil, hash_key: nil, resolver_method: nil, resolve: nil, connection: nil, max_page_size: :not_given, scope: nil, introspection: false, camelize: true, trace: nil, complexity: 1, ast_node: nil, extras: EMPTY_ARRAY, extensions: EMPTY_ARRAY, connection_extension: self.class.connection_extension, resolver_class: nil, subscription_scope: nil, relay_node_field: false, relay_nodes_field: false, method_conflict_warning: true, broadcastable: nil, arguments: EMPTY_HASH, &definition_block)
|
207
207
|
if name.nil?
|
208
208
|
raise ArgumentError, "missing first `name` argument or keyword `name:`"
|
209
209
|
end
|
@@ -250,7 +250,7 @@ module GraphQL
|
|
250
250
|
method_name = method || hash_key || name_s
|
251
251
|
resolver_method ||= name_s.to_sym
|
252
252
|
|
253
|
-
@method_str = method_name.to_s
|
253
|
+
@method_str = -method_name.to_s
|
254
254
|
@method_sym = method_name.to_sym
|
255
255
|
@resolver_method = resolver_method
|
256
256
|
@complexity = complexity
|
@@ -274,7 +274,7 @@ module GraphQL
|
|
274
274
|
if arg.is_a?(Hash)
|
275
275
|
argument(name: name, **arg)
|
276
276
|
else
|
277
|
-
|
277
|
+
add_argument(arg)
|
278
278
|
end
|
279
279
|
end
|
280
280
|
|
@@ -282,7 +282,7 @@ module GraphQL
|
|
282
282
|
@subscription_scope = subscription_scope
|
283
283
|
|
284
284
|
# Do this last so we have as much context as possible when initializing them:
|
285
|
-
@extensions =
|
285
|
+
@extensions = EMPTY_ARRAY
|
286
286
|
if extensions.any?
|
287
287
|
self.extensions(extensions)
|
288
288
|
end
|
@@ -343,6 +343,9 @@ module GraphQL
|
|
343
343
|
# Read the value
|
344
344
|
@extensions
|
345
345
|
else
|
346
|
+
if @extensions.frozen?
|
347
|
+
@extensions = @extensions.dup
|
348
|
+
end
|
346
349
|
new_extensions.each do |extension|
|
347
350
|
if extension.is_a?(Hash)
|
348
351
|
extension = extension.to_a[0]
|
@@ -380,6 +383,9 @@ module GraphQL
|
|
380
383
|
# Read the value
|
381
384
|
@extras
|
382
385
|
else
|
386
|
+
if @extras.frozen?
|
387
|
+
@extras = @extras.dup
|
388
|
+
end
|
383
389
|
# Append to the set of extras on this field
|
384
390
|
@extras.concat(new_extras)
|
385
391
|
end
|
@@ -719,32 +725,42 @@ module GraphQL
|
|
719
725
|
if @extensions.empty?
|
720
726
|
yield(obj, args)
|
721
727
|
else
|
722
|
-
#
|
723
|
-
|
724
|
-
|
725
|
-
|
726
|
-
|
727
|
-
|
728
|
-
yield(extended_obj, extended_args)
|
728
|
+
# This is a hack to get the _last_ value for extended obj and args,
|
729
|
+
# in case one of the extensions doesn't `yield`.
|
730
|
+
# (There's another implementation that uses multiple-return, but I'm wary of the perf cost of the extra arrays)
|
731
|
+
extended = { args: args, obj: obj, memos: nil }
|
732
|
+
value = run_extensions_before_resolve(obj, args, ctx, extended) do |obj, args|
|
733
|
+
yield(obj, args)
|
729
734
|
end
|
730
735
|
|
736
|
+
extended_obj = extended[:obj]
|
737
|
+
extended_args = extended[:args]
|
738
|
+
memos = extended[:memos] || EMPTY_HASH
|
739
|
+
|
731
740
|
ctx.schema.after_lazy(value) do |resolved_value|
|
732
|
-
|
741
|
+
idx = 0
|
742
|
+
@extensions.each do |ext|
|
733
743
|
memo = memos[idx]
|
734
744
|
# TODO after_lazy?
|
735
|
-
resolved_value = ext.after_resolve(object:
|
745
|
+
resolved_value = ext.after_resolve(object: extended_obj, arguments: extended_args, context: ctx, value: resolved_value, memo: memo)
|
746
|
+
idx += 1
|
736
747
|
end
|
737
748
|
resolved_value
|
738
749
|
end
|
739
750
|
end
|
740
751
|
end
|
741
752
|
|
742
|
-
def run_extensions_before_resolve(
|
753
|
+
def run_extensions_before_resolve(obj, args, ctx, extended, idx: 0)
|
743
754
|
extension = @extensions[idx]
|
744
755
|
if extension
|
745
756
|
extension.resolve(object: obj, arguments: args, context: ctx) do |extended_obj, extended_args, memo|
|
746
|
-
|
747
|
-
|
757
|
+
if memo
|
758
|
+
memos = extended[:memos] ||= {}
|
759
|
+
memos[idx] = memo
|
760
|
+
end
|
761
|
+
extended[:obj] = extended_obj
|
762
|
+
extended[:args] = extended_args
|
763
|
+
run_extensions_before_resolve(extended_obj, extended_args, ctx, extended, idx: idx + 1) { |o, a| yield(o, a) }
|
748
764
|
end
|
749
765
|
else
|
750
766
|
yield(obj, args)
|
@@ -18,10 +18,11 @@ module GraphQL
|
|
18
18
|
next_args.delete(:last)
|
19
19
|
next_args.delete(:before)
|
20
20
|
next_args.delete(:after)
|
21
|
-
yield(object, next_args)
|
21
|
+
yield(object, next_args, arguments)
|
22
22
|
end
|
23
23
|
|
24
24
|
def after_resolve(value:, object:, arguments:, context:, memo:)
|
25
|
+
original_arguments = memo
|
25
26
|
# rename some inputs to avoid conflicts inside the block
|
26
27
|
maybe_lazy = value
|
27
28
|
value = nil
|
@@ -37,10 +38,10 @@ module GraphQL
|
|
37
38
|
# update the connection with some things that may not have been provided
|
38
39
|
value.context ||= context
|
39
40
|
value.parent ||= object.object
|
40
|
-
value.first_value ||=
|
41
|
-
value.after_value ||=
|
42
|
-
value.last_value ||=
|
43
|
-
value.before_value ||=
|
41
|
+
value.first_value ||= original_arguments[:first]
|
42
|
+
value.after_value ||= original_arguments[:after]
|
43
|
+
value.last_value ||= original_arguments[:last]
|
44
|
+
value.before_value ||= original_arguments[:before]
|
44
45
|
if field.has_max_page_size? && !value.has_max_page_size_override?
|
45
46
|
value.max_page_size = field.max_page_size
|
46
47
|
end
|
@@ -50,7 +51,7 @@ module GraphQL
|
|
50
51
|
value
|
51
52
|
elsif context.schema.new_connections?
|
52
53
|
wrappers = context.namespace(:connections)[:all_wrappers] ||= context.schema.connections.all_wrappers
|
53
|
-
context.schema.connections.wrap(field, object.object, value,
|
54
|
+
context.schema.connections.wrap(field, object.object, value, original_arguments, context, wrappers: wrappers)
|
54
55
|
else
|
55
56
|
if object.is_a?(GraphQL::Schema::Object)
|
56
57
|
object = object.object
|
@@ -58,7 +59,7 @@ module GraphQL
|
|
58
59
|
connection_class = GraphQL::Relay::BaseConnection.connection_for_nodes(value)
|
59
60
|
connection_class.new(
|
60
61
|
value,
|
61
|
-
|
62
|
+
original_arguments,
|
62
63
|
field: field,
|
63
64
|
max_page_size: field.max_page_size,
|
64
65
|
parent: object,
|