graphql 1.11.5 → 1.11.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.
Potentially problematic release.
This version of graphql might be problematic. Click here for more details.
- 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)
|