graphql 1.11.5 → 1.11.9
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/graphql/define/assign_global_id_field.rb +2 -2
- 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 +53 -39
- data/lib/graphql/integer_decoding_error.rb +17 -0
- data/lib/graphql/invalid_null_error.rb +1 -1
- data/lib/graphql/pagination/connections.rb +11 -5
- data/lib/graphql/query/context.rb +4 -1
- data/lib/graphql/query/validation_pipeline.rb +1 -1
- data/lib/graphql/query.rb +4 -1
- data/lib/graphql/relay/array_connection.rb +2 -2
- data/lib/graphql/relay/range_add.rb +14 -5
- data/lib/graphql/schema/build_from_definition.rb +11 -7
- data/lib/graphql/schema/default_type_error.rb +2 -0
- data/lib/graphql/schema/field/connection_extension.rb +8 -7
- data/lib/graphql/schema/field/scope_extension.rb +1 -1
- data/lib/graphql/schema/field.rb +22 -12
- data/lib/graphql/schema/member/has_arguments.rb +51 -52
- data/lib/graphql/schema/member/has_fields.rb +2 -2
- data/lib/graphql/schema/relay_classic_mutation.rb +1 -1
- data/lib/graphql/schema/unique_within_type.rb +1 -2
- data/lib/graphql/schema.rb +39 -11
- data/lib/graphql/static_validation/all_rules.rb +1 -0
- data/lib/graphql/static_validation/base_visitor.rb +3 -0
- data/lib/graphql/static_validation/rules/fields_will_merge.rb +29 -21
- data/lib/graphql/static_validation/rules/fragments_are_finite.rb +2 -2
- 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_context.rb +6 -1
- data/lib/graphql/static_validation/validation_timeout_error.rb +25 -0
- data/lib/graphql/static_validation/validator.rb +33 -10
- data/lib/graphql/static_validation.rb +1 -0
- 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/lib/graphql.rb +1 -0
- data/readme.md +1 -1
- metadata +10 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: '03288f39c878bbb9e7e0831ec3b7f5238e4063439df8f1a8a297b6d2e88798c4'
|
4
|
+
data.tar.gz: 157ad2e363c871c5fe5e13322fe5ea98aedfee77febd0c77ea092507fa11d696
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6ab05e247b8a3a3a1d08daec2edeb20fdc29b2cf196e34a5f84fbf228da1bd5da7ce445b2972648b6ce4c74f15e6d1dfc8b2eb1fc0929dd0df2b67f2db4e73da
|
7
|
+
data.tar.gz: 4ce3349c4cd3623827d1596bfbdb9b8974a26cc5ffc5be162c1f3b6fc1fb8922d8902e166345d14afcba77f8b693607769eee2db52907b79190f6beb5ee2ece2
|
@@ -2,9 +2,9 @@
|
|
2
2
|
module GraphQL
|
3
3
|
module Define
|
4
4
|
module AssignGlobalIdField
|
5
|
-
def self.call(type_defn, field_name)
|
5
|
+
def self.call(type_defn, field_name, **field_kwargs)
|
6
6
|
resolve = GraphQL::Relay::GlobalIdResolve.new(type: type_defn)
|
7
|
-
GraphQL::Define::AssignObjectField.call(type_defn, field_name, type: GraphQL::ID_TYPE.to_non_null_type, resolve: resolve)
|
7
|
+
GraphQL::Define::AssignObjectField.call(type_defn, field_name, **field_kwargs, type: GraphQL::ID_TYPE.to_non_null_type, resolve: resolve)
|
8
8
|
end
|
9
9
|
end
|
10
10
|
end
|
@@ -14,18 +14,33 @@ module GraphQL
|
|
14
14
|
# This hash is the one used at runtime.
|
15
15
|
#
|
16
16
|
# @return [Hash<Symbol, Object>]
|
17
|
-
|
17
|
+
def keyword_arguments
|
18
|
+
@keyword_arguments ||= begin
|
19
|
+
kwargs = {}
|
20
|
+
argument_values.each do |name, arg_val|
|
21
|
+
kwargs[name] = arg_val.value
|
22
|
+
end
|
23
|
+
kwargs
|
24
|
+
end
|
25
|
+
end
|
18
26
|
|
19
|
-
|
20
|
-
|
27
|
+
# @param argument_values [nil, Hash{Symbol => ArgumentValue}]
|
28
|
+
def initialize(argument_values:)
|
21
29
|
@argument_values = argument_values
|
30
|
+
@empty = argument_values.nil? || argument_values.empty?
|
22
31
|
end
|
23
32
|
|
24
33
|
# @return [Hash{Symbol => ArgumentValue}]
|
25
|
-
|
34
|
+
def argument_values
|
35
|
+
@argument_values ||= {}
|
36
|
+
end
|
37
|
+
|
38
|
+
def empty?
|
39
|
+
@empty
|
40
|
+
end
|
26
41
|
|
27
|
-
def_delegators
|
28
|
-
def_delegators
|
42
|
+
def_delegators :keyword_arguments, :key?, :[], :fetch, :keys, :each, :values
|
43
|
+
def_delegators :argument_values, :each_value
|
29
44
|
|
30
45
|
def inspect
|
31
46
|
"#<#{self.class} @keyword_arguments=#{keyword_arguments.inspect}>"
|
@@ -29,11 +29,16 @@ module GraphQL
|
|
29
29
|
|
30
30
|
private
|
31
31
|
|
32
|
+
NO_ARGUMENTS = {}.freeze
|
33
|
+
|
32
34
|
NO_VALUE_GIVEN = Object.new
|
33
35
|
|
34
36
|
def prepare_args_hash(ast_arg_or_hash_or_value)
|
35
37
|
case ast_arg_or_hash_or_value
|
36
38
|
when Hash
|
39
|
+
if ast_arg_or_hash_or_value.empty?
|
40
|
+
return NO_ARGUMENTS
|
41
|
+
end
|
37
42
|
args_hash = {}
|
38
43
|
ast_arg_or_hash_or_value.each do |k, v|
|
39
44
|
args_hash[k] = prepare_args_hash(v)
|
@@ -42,6 +47,9 @@ module GraphQL
|
|
42
47
|
when Array
|
43
48
|
ast_arg_or_hash_or_value.map { |v| prepare_args_hash(v) }
|
44
49
|
when GraphQL::Language::Nodes::Field, GraphQL::Language::Nodes::InputObject, GraphQL::Language::Nodes::Directive
|
50
|
+
if ast_arg_or_hash_or_value.arguments.empty?
|
51
|
+
return NO_ARGUMENTS
|
52
|
+
end
|
45
53
|
args_hash = {}
|
46
54
|
ast_arg_or_hash_or_value.arguments.each do |arg|
|
47
55
|
v = prepare_args_hash(arg.value)
|
@@ -47,8 +47,7 @@ module GraphQL
|
|
47
47
|
root_op_type = root_operation.operation_type || "query"
|
48
48
|
root_type = schema.root_type_for_operation(root_op_type)
|
49
49
|
path = []
|
50
|
-
|
51
|
-
set_interpreter_context(:current_path, path)
|
50
|
+
set_all_interpreter_context(query.root_value, nil, nil, path)
|
52
51
|
object_proxy = authorized_new(root_type, query.root_value, context, path)
|
53
52
|
object_proxy = schema.sync_lazy(object_proxy)
|
54
53
|
if object_proxy.nil?
|
@@ -118,9 +117,10 @@ module GraphQL
|
|
118
117
|
end
|
119
118
|
end
|
120
119
|
|
120
|
+
NO_ARGS = {}.freeze
|
121
|
+
|
121
122
|
def evaluate_selections(path, scoped_context, owner_object, owner_type, selections, root_operation_type: nil)
|
122
|
-
|
123
|
-
set_interpreter_context(:current_path, path)
|
123
|
+
set_all_interpreter_context(owner_object, nil, nil, path)
|
124
124
|
selections_by_name = {}
|
125
125
|
gather_selections(owner_object, owner_type, selections, selections_by_name)
|
126
126
|
selections_by_name.each do |result_name, field_ast_nodes_or_ast_node|
|
@@ -159,8 +159,7 @@ module GraphQL
|
|
159
159
|
# to propagate `null`
|
160
160
|
set_type_at_path(next_path, return_type)
|
161
161
|
# Set this before calling `run_with_directives`, so that the directive can have the latest path
|
162
|
-
|
163
|
-
set_interpreter_context(:current_field, field_defn)
|
162
|
+
set_all_interpreter_context(nil, field_defn, nil, next_path)
|
164
163
|
|
165
164
|
context.scoped_context = scoped_context
|
166
165
|
object = owner_object
|
@@ -171,44 +170,50 @@ module GraphQL
|
|
171
170
|
|
172
171
|
begin
|
173
172
|
kwarg_arguments = arguments(object, field_defn, ast_node)
|
174
|
-
rescue GraphQL::ExecutionError => e
|
173
|
+
rescue GraphQL::ExecutionError, GraphQL::UnauthorizedError => e
|
175
174
|
continue_value(next_path, e, owner_type, field_defn, return_type.non_null?, ast_node)
|
176
175
|
next
|
177
176
|
end
|
178
177
|
|
179
178
|
after_lazy(kwarg_arguments, owner: owner_type, field: field_defn, path: next_path, scoped_context: context.scoped_context, owner_object: object, arguments: kwarg_arguments) do |resolved_arguments|
|
180
|
-
|
179
|
+
case resolved_arguments
|
180
|
+
when GraphQL::ExecutionError, GraphQL::UnauthorizedError
|
181
181
|
continue_value(next_path, resolved_arguments, owner_type, field_defn, return_type.non_null?, ast_node)
|
182
182
|
next
|
183
183
|
end
|
184
184
|
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
185
|
+
if resolved_arguments.empty? && field_defn.extras.empty?
|
186
|
+
# We can avoid allocating the `{ Symbol => Object }` hash in this case
|
187
|
+
kwarg_arguments = NO_ARGS
|
188
|
+
else
|
189
|
+
kwarg_arguments = resolved_arguments.keyword_arguments
|
190
|
+
|
191
|
+
field_defn.extras.each do |extra|
|
192
|
+
case extra
|
193
|
+
when :ast_node
|
194
|
+
kwarg_arguments[:ast_node] = ast_node
|
195
|
+
when :execution_errors
|
196
|
+
kwarg_arguments[:execution_errors] = ExecutionErrors.new(context, ast_node, next_path)
|
197
|
+
when :path
|
198
|
+
kwarg_arguments[:path] = next_path
|
199
|
+
when :lookahead
|
200
|
+
if !field_ast_nodes
|
201
|
+
field_ast_nodes = [ast_node]
|
202
|
+
end
|
203
|
+
kwarg_arguments[:lookahead] = Execution::Lookahead.new(
|
204
|
+
query: query,
|
205
|
+
ast_nodes: field_ast_nodes,
|
206
|
+
field: field_defn,
|
207
|
+
)
|
208
|
+
when :argument_details
|
209
|
+
kwarg_arguments[:argument_details] = resolved_arguments
|
210
|
+
else
|
211
|
+
kwarg_arguments[extra] = field_defn.fetch_extra(extra, context)
|
198
212
|
end
|
199
|
-
kwarg_arguments[:lookahead] = Execution::Lookahead.new(
|
200
|
-
query: query,
|
201
|
-
ast_nodes: field_ast_nodes,
|
202
|
-
field: field_defn,
|
203
|
-
)
|
204
|
-
when :argument_details
|
205
|
-
kwarg_arguments[:argument_details] = resolved_arguments
|
206
|
-
else
|
207
|
-
kwarg_arguments[extra] = field_defn.fetch_extra(extra, context)
|
208
213
|
end
|
209
214
|
end
|
210
215
|
|
211
|
-
|
216
|
+
set_all_interpreter_context(nil, nil, kwarg_arguments, nil)
|
212
217
|
|
213
218
|
# Optimize for the case that field is selected only once
|
214
219
|
if field_ast_nodes.nil? || field_ast_nodes.size == 1
|
@@ -414,6 +419,21 @@ module GraphQL
|
|
414
419
|
true
|
415
420
|
end
|
416
421
|
|
422
|
+
def set_all_interpreter_context(object, field, arguments, path)
|
423
|
+
if object
|
424
|
+
@context[:current_object] = @interpreter_context[:current_object] = object
|
425
|
+
end
|
426
|
+
if field
|
427
|
+
@context[:current_field] = @interpreter_context[:current_field] = field
|
428
|
+
end
|
429
|
+
if arguments
|
430
|
+
@context[:current_arguments] = @interpreter_context[:current_arguments] = arguments
|
431
|
+
end
|
432
|
+
if path
|
433
|
+
@context[:current_path] = @interpreter_context[:current_path] = path
|
434
|
+
end
|
435
|
+
end
|
436
|
+
|
417
437
|
# @param obj [Object] Some user-returned value that may want to be batched
|
418
438
|
# @param path [Array<String>]
|
419
439
|
# @param field [GraphQL::Schema::Field]
|
@@ -421,16 +441,10 @@ module GraphQL
|
|
421
441
|
# @param trace [Boolean] If `false`, don't wrap this with field tracing
|
422
442
|
# @return [GraphQL::Execution::Lazy, Object] If loading `object` will be deferred, it's a wrapper over it.
|
423
443
|
def after_lazy(lazy_obj, owner:, field:, path:, scoped_context:, owner_object:, arguments:, eager: false, trace: true, &block)
|
424
|
-
|
425
|
-
set_interpreter_context(:current_arguments, arguments)
|
426
|
-
set_interpreter_context(:current_path, path)
|
427
|
-
set_interpreter_context(:current_field, field)
|
444
|
+
set_all_interpreter_context(owner_object, field, arguments, path)
|
428
445
|
if schema.lazy?(lazy_obj)
|
429
446
|
lazy = GraphQL::Execution::Lazy.new(path: path, field: field) do
|
430
|
-
|
431
|
-
set_interpreter_context(:current_field, field)
|
432
|
-
set_interpreter_context(:current_object, owner_object)
|
433
|
-
set_interpreter_context(:current_arguments, arguments)
|
447
|
+
set_all_interpreter_context(owner_object, field, arguments, path)
|
434
448
|
context.scoped_context = scoped_context
|
435
449
|
# Wrap the execution of _this_ method with tracing,
|
436
450
|
# but don't wrap the continuation below
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module GraphQL
|
3
|
+
# This error is raised when `Types::Int` is given an input value outside of 32-bit integer range.
|
4
|
+
#
|
5
|
+
# For really big integer values, consider `GraphQL::Types::BigInt`
|
6
|
+
#
|
7
|
+
# @see GraphQL::Types::Int which raises this error
|
8
|
+
class IntegerDecodingError < GraphQL::RuntimeTypeError
|
9
|
+
# The value which couldn't be decoded
|
10
|
+
attr_reader :integer_value
|
11
|
+
|
12
|
+
def initialize(value)
|
13
|
+
@integer_value = value
|
14
|
+
super("Integer out of bounds: #{value}. \nConsider using GraphQL::Types::BigInt instead.")
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -39,7 +39,7 @@ module GraphQL
|
|
39
39
|
end
|
40
40
|
|
41
41
|
def inspect
|
42
|
-
if name.nil? && parent_class.respond_to?(:mutation) && (mutation = parent_class.mutation)
|
42
|
+
if (name.nil? || parent_class.name.nil?) && parent_class.respond_to?(:mutation) && (mutation = parent_class.mutation)
|
43
43
|
"#{mutation.inspect}::#{parent_class.graphql_name}::InvalidNullError"
|
44
44
|
else
|
45
45
|
super
|
@@ -63,11 +63,7 @@ module GraphQL
|
|
63
63
|
all_wrappers
|
64
64
|
end
|
65
65
|
|
66
|
-
|
67
|
-
# @api Private
|
68
|
-
def wrap(field, parent, items, arguments, context, wrappers: all_wrappers)
|
69
|
-
return items if GraphQL::Execution::Interpreter::RawValue === items
|
70
|
-
|
66
|
+
def wrapper_for(items, wrappers: all_wrappers)
|
71
67
|
impl = nil
|
72
68
|
|
73
69
|
items.class.ancestors.each { |cls|
|
@@ -75,6 +71,16 @@ module GraphQL
|
|
75
71
|
break if impl
|
76
72
|
}
|
77
73
|
|
74
|
+
impl
|
75
|
+
end
|
76
|
+
|
77
|
+
# Used by the runtime to wrap values in connection wrappers.
|
78
|
+
# @api Private
|
79
|
+
def wrap(field, parent, items, arguments, context, wrappers: all_wrappers)
|
80
|
+
return items if GraphQL::Execution::Interpreter::RawValue === items
|
81
|
+
|
82
|
+
impl = wrapper_for(items, wrappers: wrappers)
|
83
|
+
|
78
84
|
if impl.nil?
|
79
85
|
raise ImplementationMissingError, "Couldn't find a connection wrapper for #{items.class} during #{field.path} (#{items.inspect})"
|
80
86
|
end
|
@@ -167,7 +167,10 @@ module GraphQL
|
|
167
167
|
# @api private
|
168
168
|
attr_accessor :scoped_context
|
169
169
|
|
170
|
-
|
170
|
+
def []=(key, value)
|
171
|
+
@provided_values[key] = value
|
172
|
+
end
|
173
|
+
|
171
174
|
def_delegators :@query, :trace, :interpreter?
|
172
175
|
|
173
176
|
# @!method []=(key, value)
|
@@ -72,7 +72,7 @@ module GraphQL
|
|
72
72
|
elsif @operation_name_error
|
73
73
|
@validation_errors << @operation_name_error
|
74
74
|
else
|
75
|
-
validation_result = @schema.static_validator.validate(@query, validate: @validate)
|
75
|
+
validation_result = @schema.static_validator.validate(@query, validate: @validate, timeout: @schema.validate_timeout)
|
76
76
|
@validation_errors.concat(validation_result[:errors])
|
77
77
|
@internal_representation = validation_result[:irep]
|
78
78
|
|
data/lib/graphql/query.rb
CHANGED
@@ -88,6 +88,7 @@ module GraphQL
|
|
88
88
|
schema = schema.graphql_definition
|
89
89
|
end
|
90
90
|
@schema = schema
|
91
|
+
@interpreter = @schema.interpreter?
|
91
92
|
@filter = schema.default_filter.merge(except: except, only: only)
|
92
93
|
@context = schema.context_class.new(query: self, object: root_value, values: context)
|
93
94
|
@warden = warden
|
@@ -148,7 +149,9 @@ module GraphQL
|
|
148
149
|
@query_string ||= (document ? document.to_query_string : nil)
|
149
150
|
end
|
150
151
|
|
151
|
-
|
152
|
+
def interpreter?
|
153
|
+
@interpreter
|
154
|
+
end
|
152
155
|
|
153
156
|
def subscription_update?
|
154
157
|
@subscription_topic && subscription?
|
@@ -31,8 +31,6 @@ module GraphQL
|
|
31
31
|
end
|
32
32
|
end
|
33
33
|
|
34
|
-
private
|
35
|
-
|
36
34
|
def first
|
37
35
|
@first ||= begin
|
38
36
|
capped = limit_pagination_argument(arguments[:first], max_page_size)
|
@@ -47,6 +45,8 @@ module GraphQL
|
|
47
45
|
@last ||= limit_pagination_argument(arguments[:last], max_page_size)
|
48
46
|
end
|
49
47
|
|
48
|
+
private
|
49
|
+
|
50
50
|
# apply first / last limit results
|
51
51
|
def paged_nodes
|
52
52
|
@paged_nodes ||= begin
|
@@ -33,12 +33,21 @@ module GraphQL
|
|
33
33
|
# @param item [Object] The newly-added item (will be wrapped in `edge_class`)
|
34
34
|
# @param parent [Object] The owner of `collection`, will be passed to the connection if provided
|
35
35
|
# @param context [GraphQL::Query::Context] The surrounding `ctx`, will be passed to the connection if provided (this is required for cursor encoders)
|
36
|
-
# @param edge_class [Class] The class to wrap `item` with
|
37
|
-
def initialize(collection:, item:, parent: nil, context: nil, edge_class:
|
38
|
-
|
36
|
+
# @param edge_class [Class] The class to wrap `item` with (defaults to the connection's edge class)
|
37
|
+
def initialize(collection:, item:, parent: nil, context: nil, edge_class: nil)
|
38
|
+
if context && context.schema.new_connections?
|
39
|
+
conn_class = context.schema.connections.wrapper_for(collection)
|
40
|
+
# The rest will be added by ConnectionExtension
|
41
|
+
@connection = conn_class.new(collection, parent: parent, context: context, edge_class: edge_class)
|
42
|
+
@edge = @connection.edge_class.new(item, @connection)
|
43
|
+
else
|
44
|
+
connection_class = BaseConnection.connection_for_nodes(collection)
|
45
|
+
@connection = connection_class.new(collection, {}, parent: parent, context: context)
|
46
|
+
edge_class ||= Relay::Edge
|
47
|
+
@edge = edge_class.new(item, @connection)
|
48
|
+
end
|
49
|
+
|
39
50
|
@parent = parent
|
40
|
-
@connection = connection_class.new(collection, {}, parent: parent, context: context)
|
41
|
-
@edge = edge_class.new(item, @connection)
|
42
51
|
end
|
43
52
|
end
|
44
53
|
end
|
@@ -197,23 +197,27 @@ module GraphQL
|
|
197
197
|
end
|
198
198
|
|
199
199
|
def build_scalar_type(scalar_type_definition, type_resolver, default_resolve:)
|
200
|
+
builder = self
|
200
201
|
Class.new(GraphQL::Schema::Scalar) do
|
201
202
|
graphql_name(scalar_type_definition.name)
|
202
203
|
description(scalar_type_definition.description)
|
203
204
|
ast_node(scalar_type_definition)
|
204
205
|
|
205
206
|
if default_resolve.respond_to?(:coerce_input)
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
def self.coerce_result(val, ctx)
|
211
|
-
ctx.schema.definition_default_resolve.coerce_result(self, val, ctx)
|
212
|
-
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)
|
213
211
|
end
|
214
212
|
end
|
215
213
|
end
|
216
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
|
+
|
217
221
|
def build_union_type(union_type_definition, type_resolver)
|
218
222
|
Class.new(GraphQL::Schema::Union) do
|
219
223
|
graphql_name(union_type_definition.name)
|
@@ -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,
|
data/lib/graphql/schema/field.rb
CHANGED
@@ -725,32 +725,42 @@ module GraphQL
|
|
725
725
|
if @extensions.empty?
|
726
726
|
yield(obj, args)
|
727
727
|
else
|
728
|
-
#
|
729
|
-
|
730
|
-
|
731
|
-
|
732
|
-
|
733
|
-
|
734
|
-
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)
|
735
734
|
end
|
736
735
|
|
736
|
+
extended_obj = extended[:obj]
|
737
|
+
extended_args = extended[:args]
|
738
|
+
memos = extended[:memos] || EMPTY_HASH
|
739
|
+
|
737
740
|
ctx.schema.after_lazy(value) do |resolved_value|
|
738
|
-
|
741
|
+
idx = 0
|
742
|
+
@extensions.each do |ext|
|
739
743
|
memo = memos[idx]
|
740
744
|
# TODO after_lazy?
|
741
|
-
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
|
742
747
|
end
|
743
748
|
resolved_value
|
744
749
|
end
|
745
750
|
end
|
746
751
|
end
|
747
752
|
|
748
|
-
def run_extensions_before_resolve(
|
753
|
+
def run_extensions_before_resolve(obj, args, ctx, extended, idx: 0)
|
749
754
|
extension = @extensions[idx]
|
750
755
|
if extension
|
751
756
|
extension.resolve(object: obj, arguments: args, context: ctx) do |extended_obj, extended_args, memo|
|
752
|
-
|
753
|
-
|
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) }
|
754
764
|
end
|
755
765
|
else
|
756
766
|
yield(obj, args)
|