graphql 1.12.3 → 1.12.4
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/install_generator.rb +3 -1
- data/lib/generators/graphql/relay.rb +55 -0
- data/lib/generators/graphql/relay_generator.rb +3 -46
- data/lib/graphql.rb +1 -1
- data/lib/graphql/backtrace/inspect_result.rb +0 -1
- data/lib/graphql/backtrace/table.rb +0 -1
- data/lib/graphql/backtrace/traced_error.rb +0 -1
- data/lib/graphql/backtrace/tracer.rb +2 -6
- data/lib/graphql/dataloader.rb +102 -92
- data/lib/graphql/dataloader/null_dataloader.rb +5 -5
- data/lib/graphql/dataloader/request.rb +1 -6
- data/lib/graphql/dataloader/request_all.rb +1 -4
- data/lib/graphql/dataloader/source.rb +20 -6
- data/lib/graphql/execution/interpreter.rb +1 -1
- data/lib/graphql/execution/interpreter/arguments_cache.rb +37 -14
- data/lib/graphql/execution/interpreter/resolve.rb +33 -25
- data/lib/graphql/execution/interpreter/runtime.rb +36 -74
- data/lib/graphql/execution/multiplex.rb +21 -22
- data/lib/graphql/object_type.rb +0 -2
- data/lib/graphql/parse_error.rb +0 -1
- data/lib/graphql/query.rb +8 -2
- data/lib/graphql/query/arguments_cache.rb +0 -1
- data/lib/graphql/query/context.rb +1 -3
- data/lib/graphql/query/executor.rb +0 -1
- data/lib/graphql/query/null_context.rb +3 -2
- data/lib/graphql/query/variable_validation_error.rb +1 -1
- data/lib/graphql/schema/argument.rb +61 -0
- data/lib/graphql/schema/field.rb +10 -5
- data/lib/graphql/schema/find_inherited_value.rb +3 -1
- data/lib/graphql/schema/input_object.rb +6 -2
- data/lib/graphql/schema/member/has_arguments.rb +43 -56
- data/lib/graphql/schema/member/has_fields.rb +1 -4
- data/lib/graphql/schema/member/instrumentation.rb +0 -1
- data/lib/graphql/subscriptions/event.rb +0 -1
- data/lib/graphql/subscriptions/instrumentation.rb +0 -1
- data/lib/graphql/subscriptions/serialize.rb +0 -1
- data/lib/graphql/version.rb +1 -1
- metadata +7 -90
@@ -35,7 +35,7 @@ module GraphQL
|
|
35
35
|
@queries = queries
|
36
36
|
@queries.each { |q| q.multiplex = self }
|
37
37
|
@context = context
|
38
|
-
@context[:dataloader] = @dataloader = @schema.dataloader_class.new
|
38
|
+
@context[:dataloader] = @dataloader = @schema.dataloader_class.new
|
39
39
|
@tracers = schema.tracers + (context[:tracers] || [])
|
40
40
|
# Support `context: {backtrace: true}`
|
41
41
|
if context[:backtrace] && !@tracers.include?(GraphQL::Backtrace::Tracer)
|
@@ -74,6 +74,24 @@ module GraphQL
|
|
74
74
|
end
|
75
75
|
end
|
76
76
|
|
77
|
+
# @param query [GraphQL::Query]
|
78
|
+
def begin_query(results, idx, query, multiplex)
|
79
|
+
operation = query.selected_operation
|
80
|
+
result = if operation.nil? || !query.valid? || query.context.errors.any?
|
81
|
+
NO_OPERATION
|
82
|
+
else
|
83
|
+
begin
|
84
|
+
# These were checked to be the same in `#supports_multiplexing?`
|
85
|
+
query.schema.query_execution_strategy.begin_query(query, multiplex)
|
86
|
+
rescue GraphQL::ExecutionError => err
|
87
|
+
query.context.errors << err
|
88
|
+
NO_OPERATION
|
89
|
+
end
|
90
|
+
end
|
91
|
+
results[idx] = result
|
92
|
+
nil
|
93
|
+
end
|
94
|
+
|
77
95
|
private
|
78
96
|
|
79
97
|
def run_as_multiplex(multiplex)
|
@@ -83,15 +101,13 @@ module GraphQL
|
|
83
101
|
# Do as much eager evaluation of the query as possible
|
84
102
|
results = []
|
85
103
|
queries.each_with_index do |query, idx|
|
86
|
-
multiplex.dataloader.
|
87
|
-
results[idx] = begin_query(query, multiplex)
|
88
|
-
}
|
104
|
+
multiplex.dataloader.append_job { begin_query(results, idx, query, multiplex) }
|
89
105
|
end
|
90
106
|
|
91
107
|
multiplex.dataloader.run
|
92
108
|
|
93
109
|
# Then, work through lazy results in a breadth-first way
|
94
|
-
multiplex.dataloader.
|
110
|
+
multiplex.dataloader.append_job {
|
95
111
|
multiplex.schema.query_execution_strategy.finish_multiplex(results, multiplex)
|
96
112
|
}
|
97
113
|
multiplex.dataloader.run
|
@@ -112,23 +128,6 @@ module GraphQL
|
|
112
128
|
raise
|
113
129
|
end
|
114
130
|
|
115
|
-
# @param query [GraphQL::Query]
|
116
|
-
# @return [Hash] The initial result (may not be finished if there are lazy values)
|
117
|
-
def begin_query(query, multiplex)
|
118
|
-
operation = query.selected_operation
|
119
|
-
if operation.nil? || !query.valid? || query.context.errors.any?
|
120
|
-
NO_OPERATION
|
121
|
-
else
|
122
|
-
begin
|
123
|
-
# These were checked to be the same in `#supports_multiplexing?`
|
124
|
-
query.schema.query_execution_strategy.begin_query(query, multiplex)
|
125
|
-
rescue GraphQL::ExecutionError => err
|
126
|
-
query.context.errors << err
|
127
|
-
NO_OPERATION
|
128
|
-
end
|
129
|
-
end
|
130
|
-
end
|
131
|
-
|
132
131
|
# @param data_result [Hash] The result for the "data" key, if any
|
133
132
|
# @param query [GraphQL::Query] The query which was run
|
134
133
|
# @return [Hash] final result of this query, including all values and errors
|
data/lib/graphql/object_type.rb
CHANGED
@@ -121,8 +121,6 @@ module GraphQL
|
|
121
121
|
iface = GraphQL::BaseType.resolve_related_type(type_membership.abstract_type)
|
122
122
|
if iface.is_a?(GraphQL::InterfaceType)
|
123
123
|
@clean_inherited_fields.merge!(iface.fields)
|
124
|
-
else
|
125
|
-
pp iface
|
126
124
|
end
|
127
125
|
end
|
128
126
|
@clean_inherited_fields
|
data/lib/graphql/parse_error.rb
CHANGED
data/lib/graphql/query.rb
CHANGED
@@ -251,12 +251,18 @@ module GraphQL
|
|
251
251
|
# @param parent_object [GraphQL::Schema::Object]
|
252
252
|
# @return Hash{Symbol => Object}
|
253
253
|
def arguments_for(ast_node, definition, parent_object: nil)
|
254
|
+
if interpreter?
|
255
|
+
arguments_cache.fetch(ast_node, definition, parent_object)
|
256
|
+
else
|
257
|
+
arguments_cache[ast_node][definition]
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
261
|
+
def arguments_cache
|
254
262
|
if interpreter?
|
255
263
|
@arguments_cache ||= Execution::Interpreter::ArgumentsCache.new(self)
|
256
|
-
@arguments_cache.fetch(ast_node, definition, parent_object)
|
257
264
|
else
|
258
265
|
@arguments_cache ||= ArgumentsCache.build(self)
|
259
|
-
@arguments_cache[ast_node][definition]
|
260
266
|
end
|
261
267
|
end
|
262
268
|
|
@@ -1,6 +1,4 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
# test_via: ../execution/execute.rb
|
3
|
-
# test_via: ../execution/lazy.rb
|
4
2
|
module GraphQL
|
5
3
|
class Query
|
6
4
|
# Expose some query-specific info to field resolve functions.
|
@@ -159,7 +157,7 @@ module GraphQL
|
|
159
157
|
end
|
160
158
|
|
161
159
|
def dataloader
|
162
|
-
@dataloader ||= query.multiplex.dataloader
|
160
|
+
@dataloader ||= query.multiplex ? query.multiplex.dataloader : schema.dataloader_class.new
|
163
161
|
end
|
164
162
|
|
165
163
|
# @api private
|
@@ -9,10 +9,11 @@ module GraphQL
|
|
9
9
|
def visible_type?(t); true; end
|
10
10
|
end
|
11
11
|
|
12
|
-
attr_reader :schema, :query, :warden
|
12
|
+
attr_reader :schema, :query, :warden, :dataloader
|
13
13
|
|
14
14
|
def initialize
|
15
15
|
@query = nil
|
16
|
+
@dataloader = GraphQL::Dataloader::NullDataloader.new
|
16
17
|
@schema = GraphQL::Schema.new
|
17
18
|
@warden = NullWarden.new(
|
18
19
|
GraphQL::Filter.new,
|
@@ -36,7 +37,7 @@ module GraphQL
|
|
36
37
|
@instance = self.new
|
37
38
|
end
|
38
39
|
|
39
|
-
def_delegators :instance, :query, :schema, :warden, :interpreter
|
40
|
+
def_delegators :instance, :query, :schema, :warden, :interpreter?, :dataloader
|
40
41
|
end
|
41
42
|
end
|
42
43
|
end
|
@@ -23,7 +23,7 @@ module GraphQL
|
|
23
23
|
# a one level deep merge explicitly. However beyond that only show the
|
24
24
|
# latest value and problems.
|
25
25
|
super.merge({ "extensions" => { "value" => value, "problems" => validation_result.problems }}) do |key, oldValue, newValue|
|
26
|
-
if oldValue.respond_to?
|
26
|
+
if oldValue.respond_to?(:merge)
|
27
27
|
oldValue.merge(newValue)
|
28
28
|
else
|
29
29
|
newValue
|
@@ -236,6 +236,67 @@ module GraphQL
|
|
236
236
|
end
|
237
237
|
end
|
238
238
|
|
239
|
+
# @api private
|
240
|
+
def coerce_into_values(parent_object, values, context, argument_values)
|
241
|
+
arg_name = graphql_name
|
242
|
+
arg_key = keyword
|
243
|
+
has_value = false
|
244
|
+
default_used = false
|
245
|
+
if values.key?(arg_name)
|
246
|
+
has_value = true
|
247
|
+
value = values[arg_name]
|
248
|
+
elsif values.key?(arg_key)
|
249
|
+
has_value = true
|
250
|
+
value = values[arg_key]
|
251
|
+
elsif default_value?
|
252
|
+
has_value = true
|
253
|
+
value = default_value
|
254
|
+
default_used = true
|
255
|
+
end
|
256
|
+
|
257
|
+
if has_value
|
258
|
+
loaded_value = nil
|
259
|
+
coerced_value = context.schema.error_handler.with_error_handling(context) do
|
260
|
+
type.coerce_input(value, context)
|
261
|
+
end
|
262
|
+
|
263
|
+
# TODO this should probably be inside after_lazy
|
264
|
+
if loads && !from_resolver?
|
265
|
+
loaded_value = if type.list?
|
266
|
+
loaded_values = coerced_value.map { |val| owner.load_application_object(self, loads, val, context) }
|
267
|
+
context.schema.after_any_lazies(loaded_values) { |result| result }
|
268
|
+
else
|
269
|
+
owner.load_application_object(self, loads, coerced_value, context)
|
270
|
+
end
|
271
|
+
end
|
272
|
+
|
273
|
+
coerced_value = if loaded_value
|
274
|
+
loaded_value
|
275
|
+
else
|
276
|
+
coerced_value
|
277
|
+
end
|
278
|
+
|
279
|
+
# If this isn't lazy, then the block returns eagerly and assigns the result here
|
280
|
+
# If it _is_ lazy, then we write the lazy to the hash, then update it later
|
281
|
+
argument_values[arg_key] = context.schema.after_lazy(coerced_value) do |coerced_value|
|
282
|
+
owner.validate_directive_argument(self, coerced_value)
|
283
|
+
prepared_value = context.schema.error_handler.with_error_handling(context) do
|
284
|
+
prepare_value(parent_object, coerced_value, context: context)
|
285
|
+
end
|
286
|
+
|
287
|
+
# TODO code smell to access such a deeply-nested constant in a distant module
|
288
|
+
argument_values[arg_key] = GraphQL::Execution::Interpreter::ArgumentValue.new(
|
289
|
+
value: prepared_value,
|
290
|
+
definition: self,
|
291
|
+
default_used: default_used,
|
292
|
+
)
|
293
|
+
end
|
294
|
+
else
|
295
|
+
# has_value is false
|
296
|
+
owner.validate_directive_argument(self, nil)
|
297
|
+
end
|
298
|
+
end
|
299
|
+
|
239
300
|
private
|
240
301
|
|
241
302
|
def validate_input_type(input_type)
|
data/lib/graphql/schema/field.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
# test_via: ../object.rb
|
3
2
|
require "graphql/schema/field/connection_extension"
|
4
3
|
require "graphql/schema/field/scope_extension"
|
5
4
|
|
@@ -61,6 +60,10 @@ module GraphQL
|
|
61
60
|
@introspection
|
62
61
|
end
|
63
62
|
|
63
|
+
def inspect
|
64
|
+
"#<#{self.class} #{path}#{arguments.any? ? "(...)" : ""}: #{type.to_type_signature}>"
|
65
|
+
end
|
66
|
+
|
64
67
|
alias :mutation :resolver
|
65
68
|
|
66
69
|
# @return [Boolean] Apply tracing to this field? (Default: skip scalars, this is the override value)
|
@@ -285,22 +288,24 @@ module GraphQL
|
|
285
288
|
@owner = owner
|
286
289
|
@subscription_scope = subscription_scope
|
287
290
|
|
288
|
-
# Do this last so we have as much context as possible when initializing them:
|
289
291
|
@extensions = EMPTY_ARRAY
|
290
|
-
if extensions.any?
|
291
|
-
self.extensions(extensions)
|
292
|
-
end
|
293
292
|
# This should run before connection extension,
|
294
293
|
# but should it run after the definition block?
|
295
294
|
if scoped?
|
296
295
|
self.extension(ScopeExtension)
|
297
296
|
end
|
297
|
+
|
298
298
|
# The problem with putting this after the definition_block
|
299
299
|
# is that it would override arguments
|
300
300
|
if connection? && connection_extension
|
301
301
|
self.extension(connection_extension)
|
302
302
|
end
|
303
303
|
|
304
|
+
# Do this last so we have as much context as possible when initializing them:
|
305
|
+
if extensions.any?
|
306
|
+
self.extensions(extensions)
|
307
|
+
end
|
308
|
+
|
304
309
|
if directives.any?
|
305
310
|
directives.each do |(dir_class, options)|
|
306
311
|
self.directive(dir_class, **options)
|
@@ -20,7 +20,9 @@ module GraphQL
|
|
20
20
|
if self.is_a?(Class)
|
21
21
|
superclass.respond_to?(method_name, true) ? superclass.send(method_name) : default_value
|
22
22
|
else
|
23
|
-
|
23
|
+
ancestors_except_self = ancestors
|
24
|
+
ancestors_except_self.delete(self)
|
25
|
+
ancestors_except_self.each do |ancestor|
|
24
26
|
if ancestor.respond_to?(method_name, true)
|
25
27
|
return ancestor.send(method_name)
|
26
28
|
end
|
@@ -214,8 +214,12 @@ module GraphQL
|
|
214
214
|
arguments = coerce_arguments(nil, value, ctx)
|
215
215
|
|
216
216
|
ctx.schema.after_lazy(arguments) do |resolved_arguments|
|
217
|
-
|
218
|
-
|
217
|
+
if resolved_arguments.is_a?(GraphQL::Error)
|
218
|
+
raise resolved_arguments
|
219
|
+
else
|
220
|
+
input_obj_instance = self.new(resolved_arguments, ruby_kwargs: resolved_arguments.keyword_arguments, context: ctx, defaults_used: nil)
|
221
|
+
input_obj_instance.prepare
|
222
|
+
end
|
219
223
|
end
|
220
224
|
end
|
221
225
|
|
@@ -81,79 +81,66 @@ module GraphQL
|
|
81
81
|
end
|
82
82
|
|
83
83
|
# @api private
|
84
|
+
# If given a block, it will eventually yield the loaded args to the block.
|
85
|
+
#
|
86
|
+
# If no block is given, it will immediately dataload (but might return a Lazy).
|
87
|
+
#
|
84
88
|
# @param values [Hash<String, Object>]
|
85
89
|
# @param context [GraphQL::Query::Context]
|
86
|
-
# @
|
87
|
-
|
90
|
+
# @yield [Interpreter::Arguments, Execution::Lazy<Interpeter::Arguments>]
|
91
|
+
# @return [Interpreter::Arguments, Execution::Lazy<Interpeter::Arguments>]
|
92
|
+
def coerce_arguments(parent_object, values, context, &block)
|
88
93
|
# Cache this hash to avoid re-merging it
|
89
94
|
arg_defns = self.arguments
|
95
|
+
total_args_count = arg_defns.size
|
90
96
|
|
91
|
-
if
|
92
|
-
GraphQL::Execution::Interpreter::Arguments::EMPTY
|
97
|
+
if total_args_count == 0
|
98
|
+
final_args = GraphQL::Execution::Interpreter::Arguments::EMPTY
|
99
|
+
if block_given?
|
100
|
+
block.call(final_args)
|
101
|
+
nil
|
102
|
+
else
|
103
|
+
final_args
|
104
|
+
end
|
93
105
|
else
|
106
|
+
finished_args = nil
|
94
107
|
argument_values = {}
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
elsif arg_defn.default_value?
|
106
|
-
has_value = true
|
107
|
-
value = arg_defn.default_value
|
108
|
-
default_used = true
|
109
|
-
end
|
110
|
-
|
111
|
-
if has_value
|
112
|
-
loads = arg_defn.loads
|
113
|
-
loaded_value = nil
|
114
|
-
coerced_value = context.schema.error_handler.with_error_handling(context) do
|
115
|
-
arg_defn.type.coerce_input(value, context)
|
116
|
-
end
|
117
|
-
|
118
|
-
# TODO this should probably be inside after_lazy
|
119
|
-
if loads && !arg_defn.from_resolver?
|
120
|
-
loaded_value = if arg_defn.type.list?
|
121
|
-
loaded_values = coerced_value.map { |val| load_application_object(arg_defn, loads, val, context) }
|
122
|
-
context.schema.after_any_lazies(loaded_values) { |result| result }
|
108
|
+
resolved_args_count = 0
|
109
|
+
raised_error = false
|
110
|
+
arg_defns.each do |arg_name, arg_defn|
|
111
|
+
context.dataloader.append_job do
|
112
|
+
begin
|
113
|
+
arg_defn.coerce_into_values(parent_object, values, context, argument_values)
|
114
|
+
rescue GraphQL::ExecutionError, GraphQL::UnauthorizedError => err
|
115
|
+
raised_error = true
|
116
|
+
if block_given?
|
117
|
+
block.call(err)
|
123
118
|
else
|
124
|
-
|
119
|
+
finished_args = err
|
125
120
|
end
|
126
121
|
end
|
127
122
|
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
123
|
+
resolved_args_count += 1
|
124
|
+
if resolved_args_count == total_args_count && !raised_error
|
125
|
+
finished_args = context.schema.after_any_lazies(argument_values.values) {
|
126
|
+
GraphQL::Execution::Interpreter::Arguments.new(
|
127
|
+
argument_values: argument_values,
|
128
|
+
)
|
129
|
+
}
|
133
130
|
|
134
|
-
|
135
|
-
|
136
|
-
prepared_value = context.schema.error_handler.with_error_handling(context) do
|
137
|
-
arg_defn.prepare_value(parent_object, coerced_value, context: context)
|
131
|
+
if block_given?
|
132
|
+
block.call(finished_args)
|
138
133
|
end
|
139
|
-
|
140
|
-
# TODO code smell to access such a deeply-nested constant in a distant module
|
141
|
-
argument_values[arg_key] = GraphQL::Execution::Interpreter::ArgumentValue.new(
|
142
|
-
value: prepared_value,
|
143
|
-
definition: arg_defn,
|
144
|
-
default_used: default_used,
|
145
|
-
)
|
146
134
|
end
|
147
|
-
else
|
148
|
-
# has_value is false
|
149
|
-
validate_directive_argument(arg_defn, nil)
|
150
135
|
end
|
151
136
|
end
|
152
137
|
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
138
|
+
if block_given?
|
139
|
+
nil
|
140
|
+
else
|
141
|
+
# This API returns eagerly, gotta run it now
|
142
|
+
context.dataloader.run
|
143
|
+
finished_args
|
157
144
|
end
|
158
145
|
end
|
159
146
|
end
|
@@ -74,11 +74,8 @@ module GraphQL
|
|
74
74
|
@field_class = new_field_class
|
75
75
|
elsif defined?(@field_class) && @field_class
|
76
76
|
@field_class
|
77
|
-
elsif self.is_a?(Class)
|
78
|
-
superclass.respond_to?(:field_class) ? superclass.field_class : GraphQL::Schema::Field
|
79
77
|
else
|
80
|
-
|
81
|
-
ancestor ? ancestor.field_class : GraphQL::Schema::Field
|
78
|
+
find_inherited_value(:field_class, GraphQL::Schema::Field)
|
82
79
|
end
|
83
80
|
end
|
84
81
|
|