graphql 2.0.21 → 2.0.23
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/graphql/backtrace.rb +0 -4
- data/lib/graphql/execution/interpreter/arguments_cache.rb +31 -30
- data/lib/graphql/execution/interpreter/runtime.rb +101 -83
- data/lib/graphql/execution/interpreter.rb +1 -2
- data/lib/graphql/execution/lookahead.rb +1 -1
- data/lib/graphql/filter.rb +2 -1
- data/lib/graphql/language/document_from_schema_definition.rb +16 -9
- data/lib/graphql/language/lexer.rb +5 -3
- data/lib/graphql/language/printer.rb +28 -14
- data/lib/graphql/query/context.rb +16 -7
- data/lib/graphql/query/null_context.rb +8 -18
- data/lib/graphql/query.rb +21 -11
- data/lib/graphql/schema/always_visible.rb +10 -0
- data/lib/graphql/schema/argument.rb +5 -5
- data/lib/graphql/schema/enum_value.rb +1 -1
- data/lib/graphql/schema/field/connection_extension.rb +1 -1
- data/lib/graphql/schema/field.rb +23 -12
- data/lib/graphql/schema/input_object.rb +1 -1
- data/lib/graphql/schema/member/has_arguments.rb +9 -7
- data/lib/graphql/schema/object.rb +1 -1
- data/lib/graphql/schema/printer.rb +3 -1
- data/lib/graphql/schema/relay_classic_mutation.rb +1 -1
- data/lib/graphql/schema/resolver.rb +4 -4
- data/lib/graphql/schema/timeout.rb +1 -1
- data/lib/graphql/schema/warden.rb +37 -4
- data/lib/graphql/schema.rb +29 -14
- data/lib/graphql/tracing/legacy_trace.rb +5 -1
- data/lib/graphql/tracing/notifications_trace.rb +3 -0
- data/lib/graphql/tracing.rb +1 -0
- data/lib/graphql/version.rb +1 -1
- data/readme.md +1 -1
- metadata +4 -3
@@ -95,12 +95,14 @@ module GraphQL
|
|
95
95
|
previous_token: nil,
|
96
96
|
}
|
97
97
|
|
98
|
-
|
99
|
-
|
98
|
+
value = string.dup.force_encoding(Encoding::UTF_8)
|
99
|
+
|
100
|
+
unless value.valid_encoding?
|
101
|
+
emit(:BAD_UNICODE_ESCAPE, 0, 0, meta, value)
|
100
102
|
return meta[:tokens]
|
101
103
|
end
|
102
104
|
|
103
|
-
scan = StringScanner.new
|
105
|
+
scan = StringScanner.new value
|
104
106
|
|
105
107
|
while !scan.eos?
|
106
108
|
pos = scan.pos
|
@@ -131,7 +131,7 @@ module GraphQL
|
|
131
131
|
"$#{variable_identifier.name}".dup
|
132
132
|
end
|
133
133
|
|
134
|
-
def print_schema_definition(schema)
|
134
|
+
def print_schema_definition(schema, extension: false)
|
135
135
|
has_conventional_names = (schema.query.nil? || schema.query == 'Query') &&
|
136
136
|
(schema.mutation.nil? || schema.mutation == 'Mutation') &&
|
137
137
|
(schema.subscription.nil? || schema.subscription == 'Subscription')
|
@@ -140,7 +140,7 @@ module GraphQL
|
|
140
140
|
return
|
141
141
|
end
|
142
142
|
|
143
|
-
out = "schema".dup
|
143
|
+
out = extension ? "extend schema".dup : "schema".dup
|
144
144
|
if schema.directives.any?
|
145
145
|
schema.directives.each do |dir|
|
146
146
|
out << "\n "
|
@@ -164,14 +164,14 @@ module GraphQL
|
|
164
164
|
out
|
165
165
|
end
|
166
166
|
|
167
|
-
def print_scalar_type_definition(scalar_type)
|
168
|
-
out = print_description(scalar_type)
|
167
|
+
def print_scalar_type_definition(scalar_type, extension: false)
|
168
|
+
out = extension ? "extend ".dup : print_description(scalar_type)
|
169
169
|
out << "scalar #{scalar_type.name}"
|
170
170
|
out << print_directives(scalar_type.directives)
|
171
171
|
end
|
172
172
|
|
173
|
-
def print_object_type_definition(object_type)
|
174
|
-
out = print_description(object_type)
|
173
|
+
def print_object_type_definition(object_type, extension: false)
|
174
|
+
out = extension ? "extend ".dup : print_description(object_type)
|
175
175
|
out << "type #{object_type.name}"
|
176
176
|
out << print_implements(object_type) unless object_type.interfaces.empty?
|
177
177
|
out << print_directives(object_type.directives)
|
@@ -210,23 +210,23 @@ module GraphQL
|
|
210
210
|
out << print_directives(field.directives)
|
211
211
|
end
|
212
212
|
|
213
|
-
def print_interface_type_definition(interface_type)
|
214
|
-
out = print_description(interface_type)
|
213
|
+
def print_interface_type_definition(interface_type, extension: false)
|
214
|
+
out = extension ? "extend ".dup : print_description(interface_type)
|
215
215
|
out << "interface #{interface_type.name}"
|
216
216
|
out << print_implements(interface_type) if interface_type.interfaces.any?
|
217
217
|
out << print_directives(interface_type.directives)
|
218
218
|
out << print_field_definitions(interface_type.fields)
|
219
219
|
end
|
220
220
|
|
221
|
-
def print_union_type_definition(union_type)
|
222
|
-
out = print_description(union_type)
|
221
|
+
def print_union_type_definition(union_type, extension: false)
|
222
|
+
out = extension ? "extend ".dup : print_description(union_type)
|
223
223
|
out << "union #{union_type.name}"
|
224
224
|
out << print_directives(union_type.directives)
|
225
225
|
out << " = " + union_type.types.map(&:name).join(" | ")
|
226
226
|
end
|
227
227
|
|
228
|
-
def print_enum_type_definition(enum_type)
|
229
|
-
out = print_description(enum_type)
|
228
|
+
def print_enum_type_definition(enum_type, extension: false)
|
229
|
+
out = extension ? "extend ".dup : print_description(enum_type)
|
230
230
|
out << "enum #{enum_type.name}#{print_directives(enum_type.directives)} {\n"
|
231
231
|
enum_type.values.each.with_index do |value, i|
|
232
232
|
out << print_description(value, indent: ' ', first_in_block: i == 0)
|
@@ -241,8 +241,8 @@ module GraphQL
|
|
241
241
|
out << "\n"
|
242
242
|
end
|
243
243
|
|
244
|
-
def print_input_object_type_definition(input_object_type)
|
245
|
-
out = print_description(input_object_type)
|
244
|
+
def print_input_object_type_definition(input_object_type, extension: false)
|
245
|
+
out = extension ? "extend ".dup : print_description(input_object_type)
|
246
246
|
out << "input #{input_object_type.name}"
|
247
247
|
out << print_directives(input_object_type.directives)
|
248
248
|
if !input_object_type.fields.empty?
|
@@ -347,24 +347,38 @@ module GraphQL
|
|
347
347
|
print_variable_identifier(node)
|
348
348
|
when Nodes::SchemaDefinition
|
349
349
|
print_schema_definition(node)
|
350
|
+
when Nodes::SchemaExtension
|
351
|
+
print_schema_definition(node, extension: true)
|
350
352
|
when Nodes::ScalarTypeDefinition
|
351
353
|
print_scalar_type_definition(node)
|
354
|
+
when Nodes::ScalarTypeExtension
|
355
|
+
print_scalar_type_definition(node, extension: true)
|
352
356
|
when Nodes::ObjectTypeDefinition
|
353
357
|
print_object_type_definition(node)
|
358
|
+
when Nodes::ObjectTypeExtension
|
359
|
+
print_object_type_definition(node, extension: true)
|
354
360
|
when Nodes::InputValueDefinition
|
355
361
|
print_input_value_definition(node)
|
356
362
|
when Nodes::FieldDefinition
|
357
363
|
print_field_definition(node)
|
358
364
|
when Nodes::InterfaceTypeDefinition
|
359
365
|
print_interface_type_definition(node)
|
366
|
+
when Nodes::InterfaceTypeExtension
|
367
|
+
print_interface_type_definition(node, extension: true)
|
360
368
|
when Nodes::UnionTypeDefinition
|
361
369
|
print_union_type_definition(node)
|
370
|
+
when Nodes::UnionTypeExtension
|
371
|
+
print_union_type_definition(node, extension: true)
|
362
372
|
when Nodes::EnumTypeDefinition
|
363
373
|
print_enum_type_definition(node)
|
374
|
+
when Nodes::EnumTypeExtension
|
375
|
+
print_enum_type_definition(node, extension: true)
|
364
376
|
when Nodes::EnumValueDefinition
|
365
377
|
print_enum_value_definition(node)
|
366
378
|
when Nodes::InputObjectTypeDefinition
|
367
379
|
print_input_object_type_definition(node)
|
380
|
+
when Nodes::InputObjectTypeExtension
|
381
|
+
print_input_object_type_definition(node, extension: true)
|
368
382
|
when Nodes::DirectiveDefinition
|
369
383
|
print_directive_definition(node)
|
370
384
|
when FalseClass, Float, Integer, NilClass, String, TrueClass, Symbol
|
@@ -227,7 +227,8 @@ module GraphQL
|
|
227
227
|
current_path
|
228
228
|
else
|
229
229
|
(current_runtime_state = Thread.current[:__graphql_runtime_info]) &&
|
230
|
-
(current_runtime_state
|
230
|
+
(query_runtime_state = current_runtime_state[@query]) &&
|
231
|
+
(query_runtime_state.public_send(key))
|
231
232
|
end
|
232
233
|
else
|
233
234
|
# not found
|
@@ -237,10 +238,12 @@ module GraphQL
|
|
237
238
|
|
238
239
|
def current_path
|
239
240
|
current_runtime_state = Thread.current[:__graphql_runtime_info]
|
240
|
-
|
241
|
-
|
241
|
+
query_runtime_state = current_runtime_state && current_runtime_state[@query]
|
242
|
+
|
243
|
+
path = query_runtime_state &&
|
244
|
+
(result = query_runtime_state.current_result) &&
|
242
245
|
(result.path)
|
243
|
-
if path && (rn =
|
246
|
+
if path && (rn = query_runtime_state.current_result_name)
|
244
247
|
path = path.dup
|
245
248
|
path.push(rn)
|
246
249
|
end
|
@@ -260,7 +263,8 @@ module GraphQL
|
|
260
263
|
def fetch(key, default = UNSPECIFIED_FETCH_DEFAULT)
|
261
264
|
if RUNTIME_METADATA_KEYS.include?(key)
|
262
265
|
(runtime = Thread.current[:__graphql_runtime_info]) &&
|
263
|
-
(runtime
|
266
|
+
(query_runtime_state = runtime[@query]) &&
|
267
|
+
(query_runtime_state.public_send(key))
|
264
268
|
elsif @scoped_context.key?(key)
|
265
269
|
scoped_context[key]
|
266
270
|
elsif @provided_values.key?(key)
|
@@ -277,8 +281,13 @@ module GraphQL
|
|
277
281
|
def dig(key, *other_keys)
|
278
282
|
if RUNTIME_METADATA_KEYS.include?(key)
|
279
283
|
(current_runtime_state = Thread.current[:__graphql_runtime_info]) &&
|
280
|
-
(
|
281
|
-
obj.
|
284
|
+
(query_runtime_state = current_runtime_state[@query]) &&
|
285
|
+
(obj = query_runtime_state.public_send(key)) &&
|
286
|
+
if other_keys.empty?
|
287
|
+
obj
|
288
|
+
else
|
289
|
+
obj.dig(*other_keys)
|
290
|
+
end
|
282
291
|
elsif @scoped_context.key?(key)
|
283
292
|
@scoped_context.dig(key, *other_keys)
|
284
293
|
else
|
@@ -3,35 +3,27 @@ module GraphQL
|
|
3
3
|
class Query
|
4
4
|
# This object can be `ctx` in places where there is no query
|
5
5
|
class NullContext
|
6
|
-
class NullWarden < GraphQL::Schema::Warden
|
7
|
-
def visible_field?(field, ctx); true; end
|
8
|
-
def visible_argument?(arg, ctx); true; end
|
9
|
-
def visible_type?(type, ctx); true; end
|
10
|
-
def visible_enum_value?(ev, ctx); true; end
|
11
|
-
def visible_type_membership?(tm, ctx); true; end
|
12
|
-
end
|
13
|
-
|
14
6
|
class NullQuery
|
7
|
+
def after_lazy(value)
|
8
|
+
yield(value)
|
9
|
+
end
|
15
10
|
end
|
16
11
|
|
17
12
|
class NullSchema < GraphQL::Schema
|
18
13
|
end
|
19
14
|
|
15
|
+
extend Forwardable
|
16
|
+
|
20
17
|
attr_reader :schema, :query, :warden, :dataloader
|
18
|
+
def_delegators GraphQL::EmptyObjects::EMPTY_HASH, :[], :fetch, :dig, :key?
|
21
19
|
|
22
20
|
def initialize
|
23
21
|
@query = NullQuery.new
|
24
22
|
@dataloader = GraphQL::Dataloader::NullDataloader.new
|
25
23
|
@schema = NullSchema
|
26
|
-
@warden = NullWarden.new(
|
27
|
-
GraphQL::Filter.new(silence_deprecation_warning: true),
|
28
|
-
context: self,
|
29
|
-
schema: @schema,
|
30
|
-
)
|
24
|
+
@warden = Schema::Warden::NullWarden.new(context: self, schema: @schema)
|
31
25
|
end
|
32
26
|
|
33
|
-
def [](key); end
|
34
|
-
|
35
27
|
def interpreter?
|
36
28
|
true
|
37
29
|
end
|
@@ -39,13 +31,11 @@ module GraphQL
|
|
39
31
|
class << self
|
40
32
|
extend Forwardable
|
41
33
|
|
42
|
-
def [](key); end
|
43
|
-
|
44
34
|
def instance
|
45
35
|
@instance ||= self.new
|
46
36
|
end
|
47
37
|
|
48
|
-
def_delegators :instance, :query, :warden, :schema, :interpreter?, :dataloader
|
38
|
+
def_delegators :instance, :query, :warden, :schema, :interpreter?, :dataloader, :[], :fetch, :dig, :key?
|
49
39
|
end
|
50
40
|
end
|
51
41
|
end
|
data/lib/graphql/query.rb
CHANGED
@@ -87,7 +87,9 @@ module GraphQL
|
|
87
87
|
# Even if `variables: nil` is passed, use an empty hash for simpler logic
|
88
88
|
variables ||= {}
|
89
89
|
@schema = schema
|
90
|
-
|
90
|
+
if only || except
|
91
|
+
merge_filters(except: except, only: only)
|
92
|
+
end
|
91
93
|
@context = schema.context_class.new(query: self, object: root_value, values: context)
|
92
94
|
@warden = warden
|
93
95
|
@subscription_topic = subscription_topic
|
@@ -100,7 +102,7 @@ module GraphQL
|
|
100
102
|
|
101
103
|
# Support `ctx[:backtrace] = true` for wrapping backtraces
|
102
104
|
if context && context[:backtrace] && !@tracers.include?(GraphQL::Backtrace::Tracer)
|
103
|
-
if schema.trace_class <= GraphQL::Tracing::
|
105
|
+
if schema.trace_class <= GraphQL::Tracing::CallLegacyTracers
|
104
106
|
context_tracers += [GraphQL::Backtrace::Tracer]
|
105
107
|
@tracers << GraphQL::Backtrace::Tracer
|
106
108
|
elsif !(current_trace.class <= GraphQL::Backtrace::Trace)
|
@@ -108,8 +110,8 @@ module GraphQL
|
|
108
110
|
end
|
109
111
|
end
|
110
112
|
|
111
|
-
if context_tracers.any? && !(schema.trace_class <= GraphQL::Tracing::
|
112
|
-
raise ArgumentError, "context[:tracers] are not supported without `
|
113
|
+
if context_tracers.any? && !(schema.trace_class <= GraphQL::Tracing::CallLegacyTracers)
|
114
|
+
raise ArgumentError, "context[:tracers] are not supported without `trace_with(GraphQL::Tracing::CallLegacyTracers)` in the schema configuration, please add it."
|
113
115
|
end
|
114
116
|
|
115
117
|
|
@@ -151,11 +153,6 @@ module GraphQL
|
|
151
153
|
|
152
154
|
@result_values = nil
|
153
155
|
@executed = false
|
154
|
-
|
155
|
-
# TODO add a general way to define schema-level filters
|
156
|
-
if @schema.respond_to?(:visible?)
|
157
|
-
merge_filters(only: @schema.method(:visible?))
|
158
|
-
end
|
159
156
|
end
|
160
157
|
|
161
158
|
# If a document was provided to `GraphQL::Schema#execute` instead of the raw query string, we will need to get it from the document
|
@@ -171,7 +168,7 @@ module GraphQL
|
|
171
168
|
|
172
169
|
# @return [GraphQL::Tracing::Trace]
|
173
170
|
def current_trace
|
174
|
-
@current_trace ||= multiplex ? multiplex.current_trace : schema.new_trace(multiplex: multiplex, query: self)
|
171
|
+
@current_trace ||= context[:trace] || (multiplex ? multiplex.current_trace : schema.new_trace(multiplex: multiplex, query: self))
|
175
172
|
end
|
176
173
|
|
177
174
|
def subscription_update?
|
@@ -347,6 +344,7 @@ module GraphQL
|
|
347
344
|
if @prepared_ast
|
348
345
|
raise "Can't add filters after preparing the query"
|
349
346
|
else
|
347
|
+
@filter ||= @schema.default_filter
|
350
348
|
@filter = @filter.merge(only: only, except: except)
|
351
349
|
end
|
352
350
|
nil
|
@@ -361,6 +359,18 @@ module GraphQL
|
|
361
359
|
schema.handle_or_reraise(context, err)
|
362
360
|
end
|
363
361
|
|
362
|
+
def after_lazy(value, &block)
|
363
|
+
if !defined?(@runtime_instance)
|
364
|
+
@runtime_instance = context.namespace(:interpreter_runtime)[:runtime]
|
365
|
+
end
|
366
|
+
|
367
|
+
if @runtime_instance
|
368
|
+
@runtime_instance.minimal_after_lazy(value, &block)
|
369
|
+
else
|
370
|
+
@schema.after_lazy(value, &block)
|
371
|
+
end
|
372
|
+
end
|
373
|
+
|
364
374
|
private
|
365
375
|
|
366
376
|
def find_operation(operations, operation_name)
|
@@ -375,7 +385,7 @@ module GraphQL
|
|
375
385
|
|
376
386
|
def prepare_ast
|
377
387
|
@prepared_ast = true
|
378
|
-
@warden ||=
|
388
|
+
@warden ||= @schema.warden_class.new(@filter, schema: @schema, context: @context)
|
379
389
|
parse_error = nil
|
380
390
|
@document ||= begin
|
381
391
|
if query_string
|
@@ -198,8 +198,8 @@ module GraphQL
|
|
198
198
|
|
199
199
|
def statically_coercible?
|
200
200
|
return @statically_coercible if defined?(@statically_coercible)
|
201
|
-
|
202
|
-
@statically_coercible =
|
201
|
+
requires_parent_object = @prepare.is_a?(String) || @prepare.is_a?(Symbol) || @own_validators
|
202
|
+
@statically_coercible = !requires_parent_object
|
203
203
|
end
|
204
204
|
|
205
205
|
# Apply the {prepare} configuration to `value`, using methods from `obj`.
|
@@ -264,7 +264,7 @@ module GraphQL
|
|
264
264
|
|
265
265
|
# If this isn't lazy, then the block returns eagerly and assigns the result here
|
266
266
|
# If it _is_ lazy, then we write the lazy to the hash, then update it later
|
267
|
-
argument_values[arg_key] = context.
|
267
|
+
argument_values[arg_key] = context.query.after_lazy(coerced_value) do |resolved_coerced_value|
|
268
268
|
owner.validate_directive_argument(self, resolved_coerced_value)
|
269
269
|
prepared_value = begin
|
270
270
|
prepare_value(parent_object, resolved_coerced_value, context: context)
|
@@ -281,7 +281,7 @@ module GraphQL
|
|
281
281
|
end
|
282
282
|
|
283
283
|
maybe_loaded_value = loaded_value || prepared_value
|
284
|
-
context.
|
284
|
+
context.query.after_lazy(maybe_loaded_value) do |resolved_loaded_value|
|
285
285
|
# TODO code smell to access such a deeply-nested constant in a distant module
|
286
286
|
argument_values[arg_key] = GraphQL::Execution::Interpreter::ArgumentValue.new(
|
287
287
|
value: resolved_loaded_value,
|
@@ -303,7 +303,7 @@ module GraphQL
|
|
303
303
|
else
|
304
304
|
load_method_owner.public_send(arg_load_method, coerced_value)
|
305
305
|
end
|
306
|
-
context.
|
306
|
+
context.query.after_lazy(custom_loaded_value) do |custom_value|
|
307
307
|
if loads
|
308
308
|
if type.list?
|
309
309
|
loaded_values = custom_value.each_with_index.map { |custom_val, idx|
|
@@ -34,7 +34,7 @@ module GraphQL
|
|
34
34
|
@graphql_name = graphql_name.to_s
|
35
35
|
GraphQL::NameValidator.validate!(@graphql_name)
|
36
36
|
@description = desc || description
|
37
|
-
@value = value
|
37
|
+
@value = value == NOT_CONFIGURED ? @graphql_name : value
|
38
38
|
if deprecation_reason
|
39
39
|
self.deprecation_reason = deprecation_reason
|
40
40
|
end
|
@@ -26,7 +26,7 @@ module GraphQL
|
|
26
26
|
# rename some inputs to avoid conflicts inside the block
|
27
27
|
maybe_lazy = value
|
28
28
|
value = nil
|
29
|
-
context.
|
29
|
+
context.query.after_lazy(maybe_lazy) do |resolved_value|
|
30
30
|
value = resolved_value
|
31
31
|
if value.is_a? GraphQL::ExecutionError
|
32
32
|
# This isn't even going to work because context doesn't have ast_node anymore
|
data/lib/graphql/schema/field.rb
CHANGED
@@ -235,7 +235,7 @@ module GraphQL
|
|
235
235
|
@name = -(camelize ? Member::BuildType.camelize(name_s) : name_s)
|
236
236
|
|
237
237
|
@description = description
|
238
|
-
@type = @owner_type = @own_validators = @own_directives = @own_arguments = nil # these will be prepared later if necessary
|
238
|
+
@type = @owner_type = @own_validators = @own_directives = @own_arguments = @arguments_statically_coercible = nil # these will be prepared later if necessary
|
239
239
|
|
240
240
|
self.deprecation_reason = deprecation_reason
|
241
241
|
|
@@ -661,7 +661,7 @@ module GraphQL
|
|
661
661
|
|
662
662
|
Schema::Validator.validate!(validators, application_object, query_ctx, args)
|
663
663
|
|
664
|
-
query_ctx.
|
664
|
+
query_ctx.query.after_lazy(self.authorized?(application_object, args, query_ctx)) do |is_authorized|
|
665
665
|
if is_authorized
|
666
666
|
with_extensions(object, args, query_ctx) do |obj, ruby_kwargs|
|
667
667
|
method_args = ruby_kwargs
|
@@ -810,6 +810,17 @@ ERR
|
|
810
810
|
end
|
811
811
|
end
|
812
812
|
|
813
|
+
class ExtendedState
|
814
|
+
def initialize(args, object)
|
815
|
+
@arguments = args
|
816
|
+
@object = object
|
817
|
+
@memos = nil
|
818
|
+
@added_extras = nil
|
819
|
+
end
|
820
|
+
|
821
|
+
attr_accessor :arguments, :object, :memos, :added_extras
|
822
|
+
end
|
823
|
+
|
813
824
|
# Wrap execution with hooks.
|
814
825
|
# Written iteratively to avoid big stack traces.
|
815
826
|
# @return [Object] Whatever the
|
@@ -820,20 +831,20 @@ ERR
|
|
820
831
|
# This is a hack to get the _last_ value for extended obj and args,
|
821
832
|
# in case one of the extensions doesn't `yield`.
|
822
833
|
# (There's another implementation that uses multiple-return, but I'm wary of the perf cost of the extra arrays)
|
823
|
-
extended =
|
834
|
+
extended = ExtendedState.new(args, obj)
|
824
835
|
value = run_extensions_before_resolve(obj, args, ctx, extended) do |obj, args|
|
825
|
-
if (added_extras = extended
|
836
|
+
if (added_extras = extended.added_extras)
|
826
837
|
args = args.dup
|
827
838
|
added_extras.each { |e| args.delete(e) }
|
828
839
|
end
|
829
840
|
yield(obj, args)
|
830
841
|
end
|
831
842
|
|
832
|
-
extended_obj = extended
|
833
|
-
extended_args = extended
|
834
|
-
memos = extended
|
843
|
+
extended_obj = extended.object
|
844
|
+
extended_args = extended.arguments # rubocop:disable Development/ContextIsPassedCop
|
845
|
+
memos = extended.memos || EMPTY_HASH
|
835
846
|
|
836
|
-
ctx.
|
847
|
+
ctx.query.after_lazy(value) do |resolved_value|
|
837
848
|
idx = 0
|
838
849
|
@extensions.each do |ext|
|
839
850
|
memo = memos[idx]
|
@@ -851,17 +862,17 @@ ERR
|
|
851
862
|
if extension
|
852
863
|
extension.resolve(object: obj, arguments: args, context: ctx) do |extended_obj, extended_args, memo|
|
853
864
|
if memo
|
854
|
-
memos = extended
|
865
|
+
memos = extended.memos ||= {}
|
855
866
|
memos[idx] = memo
|
856
867
|
end
|
857
868
|
|
858
869
|
if (extras = extension.added_extras)
|
859
|
-
ae = extended
|
870
|
+
ae = extended.added_extras ||= []
|
860
871
|
ae.concat(extras)
|
861
872
|
end
|
862
873
|
|
863
|
-
extended
|
864
|
-
extended
|
874
|
+
extended.object = extended_obj
|
875
|
+
extended.arguments = extended_args
|
865
876
|
run_extensions_before_resolve(extended_obj, extended_args, ctx, extended, idx: idx + 1) { |o, a| yield(o, a) }
|
866
877
|
end
|
867
878
|
else
|
@@ -211,7 +211,7 @@ module GraphQL
|
|
211
211
|
|
212
212
|
arguments = coerce_arguments(nil, value, ctx)
|
213
213
|
|
214
|
-
ctx.
|
214
|
+
ctx.query.after_lazy(arguments) do |resolved_arguments|
|
215
215
|
if resolved_arguments.is_a?(GraphQL::Error)
|
216
216
|
raise resolved_arguments
|
217
217
|
else
|
@@ -51,7 +51,7 @@ module GraphQL
|
|
51
51
|
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
52
52
|
def #{method_owner}load_#{arg_defn.keyword}(values, context = nil)
|
53
53
|
argument = get_argument("#{arg_defn.graphql_name}")
|
54
|
-
(context || self.context).
|
54
|
+
(context || self.context).query.after_lazy(values) do |values2|
|
55
55
|
GraphQL::Execution::Lazy.all(values2.map { |value| load_application_object(argument, value, context || self.context) })
|
56
56
|
end
|
57
57
|
end
|
@@ -320,9 +320,11 @@ module GraphQL
|
|
320
320
|
end
|
321
321
|
|
322
322
|
def arguments_statically_coercible?
|
323
|
-
|
324
|
-
|
325
|
-
|
323
|
+
if defined?(@arguments_statically_coercible) && !@arguments_statically_coercible.nil?
|
324
|
+
@arguments_statically_coercible
|
325
|
+
else
|
326
|
+
@arguments_statically_coercible = all_argument_definitions.all?(&:statically_coercible?)
|
327
|
+
end
|
326
328
|
end
|
327
329
|
|
328
330
|
module ArgumentClassAccessor
|
@@ -363,7 +365,7 @@ module GraphQL
|
|
363
365
|
end
|
364
366
|
|
365
367
|
def authorize_application_object(argument, id, context, loaded_application_object)
|
366
|
-
context.
|
368
|
+
context.query.after_lazy(loaded_application_object) do |application_object|
|
367
369
|
if application_object.nil?
|
368
370
|
err = GraphQL::LoadApplicationObjectFailedError.new(argument: argument, id: id, object: application_object)
|
369
371
|
load_application_object_failed(err)
|
@@ -371,7 +373,7 @@ module GraphQL
|
|
371
373
|
# Double-check that the located object is actually of this type
|
372
374
|
# (Don't want to allow arbitrary access to objects this way)
|
373
375
|
maybe_lazy_resolve_type = context.schema.resolve_type(argument.loads, application_object, context)
|
374
|
-
context.
|
376
|
+
context.query.after_lazy(maybe_lazy_resolve_type) do |resolve_type_result|
|
375
377
|
if resolve_type_result.is_a?(Array) && resolve_type_result.size == 2
|
376
378
|
application_object_type, application_object = resolve_type_result
|
377
379
|
else
|
@@ -386,7 +388,7 @@ module GraphQL
|
|
386
388
|
# This object was loaded successfully
|
387
389
|
# and resolved to the right type,
|
388
390
|
# now apply the `.authorized?` class method if there is one
|
389
|
-
context.
|
391
|
+
context.query.after_lazy(application_object_type.authorized?(application_object, context)) do |authed|
|
390
392
|
if authed
|
391
393
|
application_object
|
392
394
|
else
|
@@ -57,12 +57,14 @@ module GraphQL
|
|
57
57
|
query_root = Class.new(GraphQL::Schema::Object) do
|
58
58
|
graphql_name "Root"
|
59
59
|
field :throwaway_field, String
|
60
|
+
def self.visible?(ctx)
|
61
|
+
false
|
62
|
+
end
|
60
63
|
end
|
61
64
|
schema = Class.new(GraphQL::Schema) { query(query_root) }
|
62
65
|
|
63
66
|
introspection_schema_ast = GraphQL::Language::DocumentFromSchemaDefinition.new(
|
64
67
|
schema,
|
65
|
-
except: ->(member, _) { member.graphql_name == "Root" },
|
66
68
|
include_introspection_types: true,
|
67
69
|
include_built_in_directives: true,
|
68
70
|
).document
|
@@ -60,7 +60,7 @@ module GraphQL
|
|
60
60
|
super()
|
61
61
|
end
|
62
62
|
|
63
|
-
context.
|
63
|
+
context.query.after_lazy(return_value) do |return_hash|
|
64
64
|
# It might be an error
|
65
65
|
if return_hash.is_a?(Hash)
|
66
66
|
return_hash[:client_mutation_id] = client_mutation_id
|
@@ -70,7 +70,7 @@ module GraphQL
|
|
70
70
|
else
|
71
71
|
ready?
|
72
72
|
end
|
73
|
-
context.
|
73
|
+
context.query.after_lazy(ready_val) do |is_ready, ready_early_return|
|
74
74
|
if ready_early_return
|
75
75
|
if is_ready != false
|
76
76
|
raise "Unexpected result from #ready? (expected `true`, `false` or `[false, {...}]`): [#{is_ready.inspect}, #{ready_early_return.inspect}]"
|
@@ -81,7 +81,7 @@ module GraphQL
|
|
81
81
|
# Then call each prepare hook, which may return a different value
|
82
82
|
# for that argument, or may return a lazy object
|
83
83
|
load_arguments_val = load_arguments(args)
|
84
|
-
context.
|
84
|
+
context.query.after_lazy(load_arguments_val) do |loaded_args|
|
85
85
|
@prepared_arguments = loaded_args
|
86
86
|
Schema::Validator.validate!(self.class.validators, object, context, loaded_args, as: @field)
|
87
87
|
# Then call `authorized?`, which may raise or may return a lazy object
|
@@ -90,7 +90,7 @@ module GraphQL
|
|
90
90
|
else
|
91
91
|
authorized?
|
92
92
|
end
|
93
|
-
context.
|
93
|
+
context.query.after_lazy(authorized_val) do |(authorized_result, early_return)|
|
94
94
|
# If the `authorized?` returned two values, `false, early_return`,
|
95
95
|
# then use the early return value instead of continuing
|
96
96
|
if early_return
|
@@ -185,7 +185,7 @@ module GraphQL
|
|
185
185
|
if arg_defn
|
186
186
|
prepped_value = prepared_args[key] = arg_defn.load_and_authorize_value(self, value, context)
|
187
187
|
if context.schema.lazy?(prepped_value)
|
188
|
-
prepare_lazies << context.
|
188
|
+
prepare_lazies << context.query.after_lazy(prepped_value) do |finished_prepped_value|
|
189
189
|
prepared_args[key] = finished_prepped_value
|
190
190
|
end
|
191
191
|
end
|
@@ -90,7 +90,7 @@ module GraphQL
|
|
90
90
|
# The default implementation returns the `max_seconds:` value from installing this plugin.
|
91
91
|
#
|
92
92
|
# @param query [GraphQL::Query] The query that's about to run
|
93
|
-
# @return [
|
93
|
+
# @return [Numeric, false] The number of seconds after which to interrupt query execution and call {#handle_error}, or `false` to bypass the timeout.
|
94
94
|
def max_seconds(query)
|
95
95
|
@max_seconds
|
96
96
|
end
|