graphql 2.0.17 → 2.0.18
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/graphql/analysis/ast.rb +2 -2
- data/lib/graphql/backtrace/tracer.rb +1 -1
- data/lib/graphql/execution/interpreter/resolve.rb +19 -0
- data/lib/graphql/execution/interpreter/runtime.rb +96 -88
- data/lib/graphql/execution/interpreter.rb +8 -13
- data/lib/graphql/execution/lazy.rb +2 -4
- data/lib/graphql/execution/multiplex.rb +2 -1
- data/lib/graphql/graphql_ext.bundle +0 -0
- data/lib/graphql/language/lexer.rb +216 -1505
- data/lib/graphql/language/lexer.ri +744 -0
- data/lib/graphql/language/parser.rb +9 -9
- data/lib/graphql/language/parser.y +9 -9
- data/lib/graphql/pagination/active_record_relation_connection.rb +0 -8
- data/lib/graphql/query/context.rb +45 -11
- data/lib/graphql/query.rb +15 -2
- data/lib/graphql/schema/field.rb +31 -19
- data/lib/graphql/schema/member/has_deprecation_reason.rb +3 -4
- data/lib/graphql/schema/member/has_fields.rb +6 -1
- data/lib/graphql/schema/object.rb +2 -4
- data/lib/graphql/schema/resolver/has_payload_type.rb +9 -9
- data/lib/graphql/schema/timeout.rb +23 -27
- data/lib/graphql/schema/warden.rb +8 -1
- data/lib/graphql/schema.rb +34 -0
- data/lib/graphql/static_validation/validator.rb +1 -1
- data/lib/graphql/tracing/active_support_notifications_trace.rb +16 -0
- data/lib/graphql/tracing/appoptics_trace.rb +231 -0
- data/lib/graphql/tracing/appsignal_trace.rb +66 -0
- data/lib/graphql/tracing/data_dog_trace.rb +148 -0
- data/lib/graphql/tracing/new_relic_trace.rb +75 -0
- data/lib/graphql/tracing/notifications_trace.rb +41 -0
- data/lib/graphql/tracing/platform_trace.rb +107 -0
- data/lib/graphql/tracing/platform_tracing.rb +15 -3
- data/lib/graphql/tracing/prometheus_trace.rb +89 -0
- data/lib/graphql/tracing/prometheus_tracing.rb +3 -3
- data/lib/graphql/tracing/scout_trace.rb +72 -0
- data/lib/graphql/tracing/statsd_trace.rb +56 -0
- data/lib/graphql/tracing.rb +136 -39
- data/lib/graphql/type_kinds.rb +6 -3
- data/lib/graphql/version.rb +1 -1
- data/lib/graphql.rb +7 -8
- metadata +14 -3
- data/lib/graphql/language/lexer.rl +0 -280
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7f43155bcb78f5842e409f8c001b7d031578604d2e7d962457cc7fd92e1d68d4
|
4
|
+
data.tar.gz: e86aa4c3071f63d605f9e2e3833ba967282f906c3ff0e1252db71b063fe69cd9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 79c16409d45a11f1bba6623e1d97877984bfe10577ab5241ecd3ebe515fefb6cd42940f336640c60cf19f94c61d902692f26b0497699e4ca9e912f2532fa6168
|
7
|
+
data.tar.gz: a9f5e954d7988a440c083cd0afbb6f5ff72ab77d30d4fab708f9f501d2ce8af49b13fde571e50788c9ba79fd943d38e4c207e4ac9ddccd93c80d2c0f9ef8f997
|
data/lib/graphql/analysis/ast.rb
CHANGED
@@ -21,7 +21,7 @@ module GraphQL
|
|
21
21
|
def analyze_multiplex(multiplex, analyzers)
|
22
22
|
multiplex_analyzers = analyzers.map { |analyzer| analyzer.new(multiplex) }
|
23
23
|
|
24
|
-
multiplex.
|
24
|
+
multiplex.current_trace.analyze_multiplex(multiplex: multiplex) do
|
25
25
|
query_results = multiplex.queries.map do |query|
|
26
26
|
if query.valid?
|
27
27
|
analyze_query(
|
@@ -48,7 +48,7 @@ module GraphQL
|
|
48
48
|
# @param analyzers [Array<GraphQL::Analysis::AST::Analyzer>]
|
49
49
|
# @return [Array<Any>] Results from those analyzers
|
50
50
|
def analyze_query(query, analyzers, multiplex_analyzers: [])
|
51
|
-
query.
|
51
|
+
query.current_trace.analyze_query(query: query) do
|
52
52
|
query_analyzers = analyzers
|
53
53
|
.map { |analyzer| analyzer.new(query) }
|
54
54
|
.select { |analyzer| analyzer.analyze? }
|
@@ -25,7 +25,7 @@ module GraphQL
|
|
25
25
|
when "execute_field", "execute_field_lazy"
|
26
26
|
query = metadata[:query]
|
27
27
|
multiplex = query.multiplex
|
28
|
-
push_key =
|
28
|
+
push_key = query.context[:current_path]
|
29
29
|
parent_frame = multiplex.context[:graphql_backtrace_contexts][push_key[0..-2]]
|
30
30
|
|
31
31
|
if parent_frame.is_a?(GraphQL::Query)
|
@@ -11,6 +11,25 @@ module GraphQL
|
|
11
11
|
nil
|
12
12
|
end
|
13
13
|
|
14
|
+
def self.resolve_each_depth(lazies_at_depth, dataloader)
|
15
|
+
depths = lazies_at_depth.keys
|
16
|
+
depths.sort!
|
17
|
+
next_depth = depths.first
|
18
|
+
if next_depth
|
19
|
+
lazies = lazies_at_depth[next_depth]
|
20
|
+
lazies_at_depth.delete(next_depth)
|
21
|
+
if lazies.any?
|
22
|
+
dataloader.append_job {
|
23
|
+
lazies.each(&:value) # resolve these Lazy instances
|
24
|
+
}
|
25
|
+
# Run lazies _and_ dataloader, see if more are enqueued
|
26
|
+
dataloader.run
|
27
|
+
resolve_each_depth(lazies_at_depth, dataloader)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
nil
|
31
|
+
end
|
32
|
+
|
14
33
|
# After getting `results` back from an interpreter evaluation,
|
15
34
|
# continue it until you get a response-ready Ruby value.
|
16
35
|
#
|
@@ -20,6 +20,15 @@ module GraphQL
|
|
20
20
|
@graphql_metadata = nil
|
21
21
|
end
|
22
22
|
|
23
|
+
def path
|
24
|
+
@path ||= build_path([])
|
25
|
+
end
|
26
|
+
|
27
|
+
def build_path(path_array)
|
28
|
+
graphql_result_name && path_array.unshift(graphql_result_name)
|
29
|
+
@graphql_parent ? @graphql_parent.build_path(path_array) : path_array
|
30
|
+
end
|
31
|
+
|
23
32
|
attr_accessor :graphql_dead
|
24
33
|
attr_reader :graphql_parent, :graphql_result_name
|
25
34
|
|
@@ -157,9 +166,10 @@ module GraphQL
|
|
157
166
|
info
|
158
167
|
end
|
159
168
|
|
160
|
-
def initialize(query:)
|
169
|
+
def initialize(query:, lazies_at_depth:)
|
161
170
|
@query = query
|
162
171
|
@dataloader = query.multiplex.dataloader
|
172
|
+
@lazies_at_depth = lazies_at_depth
|
163
173
|
@schema = query.schema
|
164
174
|
@context = query.context
|
165
175
|
@multiplex_context = query.multiplex.context
|
@@ -208,8 +218,7 @@ module GraphQL
|
|
208
218
|
root_operation = query.selected_operation
|
209
219
|
root_op_type = root_operation.operation_type || "query"
|
210
220
|
root_type = schema.root_type_for_operation(root_op_type)
|
211
|
-
|
212
|
-
set_all_interpreter_context(query.root_value, nil, nil, path)
|
221
|
+
set_all_interpreter_context(query.root_value, nil, nil, nil, @response)
|
213
222
|
object_proxy = authorized_new(root_type, query.root_value, context)
|
214
223
|
object_proxy = schema.sync_lazy(object_proxy)
|
215
224
|
|
@@ -236,10 +245,9 @@ module GraphQL
|
|
236
245
|
end
|
237
246
|
|
238
247
|
@dataloader.append_job {
|
239
|
-
set_all_interpreter_context(query.root_value, nil, nil,
|
248
|
+
set_all_interpreter_context(query.root_value, nil, nil, nil, selection_response)
|
240
249
|
call_method_on_directives(:resolve, object_proxy, selections.graphql_directives) do
|
241
250
|
evaluate_selections(
|
242
|
-
path,
|
243
251
|
object_proxy,
|
244
252
|
root_type,
|
245
253
|
root_op_type == "mutation",
|
@@ -253,10 +261,7 @@ module GraphQL
|
|
253
261
|
end
|
254
262
|
end
|
255
263
|
end
|
256
|
-
|
257
|
-
delete_interpreter_context(:current_field)
|
258
|
-
delete_interpreter_context(:current_object)
|
259
|
-
delete_interpreter_context(:current_arguments)
|
264
|
+
delete_all_interpreter_context
|
260
265
|
nil
|
261
266
|
end
|
262
267
|
|
@@ -358,15 +363,15 @@ module GraphQL
|
|
358
363
|
NO_ARGS = {}.freeze
|
359
364
|
|
360
365
|
# @return [void]
|
361
|
-
def evaluate_selections(
|
362
|
-
set_all_interpreter_context(owner_object, nil, nil,
|
366
|
+
def evaluate_selections(owner_object, owner_type, is_eager_selection, gathered_selections, selections_result, target_result, parent_object) # rubocop:disable Metrics/ParameterLists
|
367
|
+
set_all_interpreter_context(owner_object, nil, nil, nil, selections_result)
|
363
368
|
|
364
369
|
finished_jobs = 0
|
365
370
|
enqueued_jobs = gathered_selections.size
|
366
371
|
gathered_selections.each do |result_name, field_ast_nodes_or_ast_node|
|
367
372
|
@dataloader.append_job {
|
368
373
|
evaluate_selection(
|
369
|
-
|
374
|
+
result_name, field_ast_nodes_or_ast_node, owner_object, owner_type, is_eager_selection, selections_result, parent_object
|
370
375
|
)
|
371
376
|
finished_jobs += 1
|
372
377
|
if target_result && finished_jobs == enqueued_jobs
|
@@ -378,10 +383,8 @@ module GraphQL
|
|
378
383
|
selections_result
|
379
384
|
end
|
380
385
|
|
381
|
-
attr_reader :progress_path
|
382
|
-
|
383
386
|
# @return [void]
|
384
|
-
def evaluate_selection(
|
387
|
+
def evaluate_selection(result_name, field_ast_nodes_or_ast_node, owner_object, owner_type, is_eager_field, selections_result, parent_object) # rubocop:disable Metrics/ParameterLists
|
385
388
|
return if dead_result?(selections_result)
|
386
389
|
# As a performance optimization, the hash key will be a `Node` if
|
387
390
|
# there's only one selection of the field. But if there are multiple
|
@@ -412,9 +415,6 @@ module GraphQL
|
|
412
415
|
|
413
416
|
return_type = field_defn.type
|
414
417
|
|
415
|
-
next_path = path + [result_name]
|
416
|
-
next_path.freeze
|
417
|
-
|
418
418
|
# This seems janky, but we need to know
|
419
419
|
# the field's return type at this path in order
|
420
420
|
# to propagate `null`
|
@@ -422,7 +422,7 @@ module GraphQL
|
|
422
422
|
(selections_result.graphql_non_null_field_names ||= []).push(result_name)
|
423
423
|
end
|
424
424
|
# Set this before calling `run_with_directives`, so that the directive can have the latest path
|
425
|
-
set_all_interpreter_context(nil, field_defn, nil,
|
425
|
+
set_all_interpreter_context(nil, field_defn, nil, result_name, selections_result)
|
426
426
|
object = owner_object
|
427
427
|
|
428
428
|
if is_introspection
|
@@ -432,19 +432,19 @@ module GraphQL
|
|
432
432
|
total_args_count = field_defn.arguments(context).size
|
433
433
|
if total_args_count == 0
|
434
434
|
resolved_arguments = GraphQL::Execution::Interpreter::Arguments::EMPTY
|
435
|
-
evaluate_selection_with_args(resolved_arguments, field_defn,
|
435
|
+
evaluate_selection_with_args(resolved_arguments, field_defn, ast_node, field_ast_nodes, owner_type, object, is_eager_field, result_name, selections_result, parent_object, return_type)
|
436
436
|
else
|
437
437
|
# TODO remove all arguments(...) usages?
|
438
438
|
@query.arguments_cache.dataload_for(ast_node, field_defn, object) do |resolved_arguments|
|
439
|
-
evaluate_selection_with_args(resolved_arguments, field_defn,
|
439
|
+
evaluate_selection_with_args(resolved_arguments, field_defn, ast_node, field_ast_nodes, owner_type, object, is_eager_field, result_name, selections_result, parent_object, return_type)
|
440
440
|
end
|
441
441
|
end
|
442
442
|
end
|
443
443
|
|
444
|
-
def evaluate_selection_with_args(arguments, field_defn,
|
445
|
-
after_lazy(arguments, owner: owner_type, field: field_defn,
|
444
|
+
def evaluate_selection_with_args(arguments, field_defn, ast_node, field_ast_nodes, owner_type, object, is_eager_field, result_name, selection_result, parent_object, return_type) # rubocop:disable Metrics/ParameterLists
|
445
|
+
after_lazy(arguments, owner: owner_type, field: field_defn, ast_node: ast_node, owner_object: object, arguments: arguments, result_name: result_name, result: selection_result) do |resolved_arguments|
|
446
446
|
if resolved_arguments.is_a?(GraphQL::ExecutionError) || resolved_arguments.is_a?(GraphQL::UnauthorizedError)
|
447
|
-
continue_value(
|
447
|
+
continue_value(resolved_arguments, owner_type, field_defn, return_type.non_null?, ast_node, result_name, selection_result)
|
448
448
|
next
|
449
449
|
end
|
450
450
|
|
@@ -460,9 +460,9 @@ module GraphQL
|
|
460
460
|
when :ast_node
|
461
461
|
extra_args[:ast_node] = ast_node
|
462
462
|
when :execution_errors
|
463
|
-
extra_args[:execution_errors] = ExecutionErrors.new(context, ast_node,
|
463
|
+
extra_args[:execution_errors] = ExecutionErrors.new(context, ast_node, current_path)
|
464
464
|
when :path
|
465
|
-
extra_args[:path] =
|
465
|
+
extra_args[:path] = current_path
|
466
466
|
when :lookahead
|
467
467
|
if !field_ast_nodes
|
468
468
|
field_ast_nodes = [ast_node]
|
@@ -489,7 +489,7 @@ module GraphQL
|
|
489
489
|
resolved_arguments.keyword_arguments
|
490
490
|
end
|
491
491
|
|
492
|
-
set_all_interpreter_context(nil, nil, resolved_arguments,
|
492
|
+
set_all_interpreter_context(nil, nil, resolved_arguments, result_name, selection_result)
|
493
493
|
|
494
494
|
# Optimize for the case that field is selected only once
|
495
495
|
if field_ast_nodes.nil? || field_ast_nodes.size == 1
|
@@ -507,7 +507,7 @@ module GraphQL
|
|
507
507
|
field_result = call_method_on_directives(:resolve, object, directives) do
|
508
508
|
# Actually call the field resolver and capture the result
|
509
509
|
app_result = begin
|
510
|
-
query.
|
510
|
+
query.current_trace.execute_field(field: field_defn, ast_node: ast_node, query: query, object: object, arguments: kwarg_arguments) do
|
511
511
|
field_defn.resolve(object, kwarg_arguments, context)
|
512
512
|
end
|
513
513
|
rescue GraphQL::ExecutionError => err
|
@@ -519,10 +519,10 @@ module GraphQL
|
|
519
519
|
ex_err
|
520
520
|
end
|
521
521
|
end
|
522
|
-
after_lazy(app_result, owner: owner_type, field: field_defn,
|
523
|
-
continue_value = continue_value(
|
522
|
+
after_lazy(app_result, owner: owner_type, field: field_defn, ast_node: ast_node, owner_object: object, arguments: resolved_arguments, result_name: result_name, result: selection_result) do |inner_result|
|
523
|
+
continue_value = continue_value(inner_result, owner_type, field_defn, return_type.non_null?, ast_node, result_name, selection_result)
|
524
524
|
if HALT != continue_value
|
525
|
-
continue_field(
|
525
|
+
continue_field(continue_value, owner_type, field_defn, return_type, ast_node, next_selections, false, object, resolved_arguments, result_name, selection_result)
|
526
526
|
end
|
527
527
|
end
|
528
528
|
end
|
@@ -587,8 +587,30 @@ module GraphQL
|
|
587
587
|
end
|
588
588
|
end
|
589
589
|
|
590
|
+
def current_path
|
591
|
+
ti = thread_info
|
592
|
+
path = ti &&
|
593
|
+
(result = ti[:current_result]) &&
|
594
|
+
(result.path)
|
595
|
+
if path && (rn = ti[:current_result_name])
|
596
|
+
path = path.dup
|
597
|
+
path.push(rn)
|
598
|
+
end
|
599
|
+
path
|
600
|
+
end
|
601
|
+
|
602
|
+
def current_depth
|
603
|
+
ti = thread_info
|
604
|
+
depth = 1
|
605
|
+
result = ti[:current_result]
|
606
|
+
while (result = result.graphql_parent)
|
607
|
+
depth += 1
|
608
|
+
end
|
609
|
+
depth
|
610
|
+
end
|
611
|
+
|
590
612
|
HALT = Object.new
|
591
|
-
def continue_value(
|
613
|
+
def continue_value(value, parent_type, field, is_non_null, ast_node, result_name, selection_result) # rubocop:disable Metrics/ParameterLists
|
592
614
|
case value
|
593
615
|
when nil
|
594
616
|
if is_non_null
|
@@ -607,7 +629,7 @@ module GraphQL
|
|
607
629
|
# every time.
|
608
630
|
if value.is_a?(GraphQL::ExecutionError)
|
609
631
|
if selection_result.nil? || !dead_result?(selection_result)
|
610
|
-
value.path ||=
|
632
|
+
value.path ||= current_path
|
611
633
|
value.ast_node ||= ast_node
|
612
634
|
context.errors << value
|
613
635
|
if selection_result
|
@@ -624,7 +646,7 @@ module GraphQL
|
|
624
646
|
rescue GraphQL::ExecutionError => err
|
625
647
|
err
|
626
648
|
end
|
627
|
-
continue_value(
|
649
|
+
continue_value(next_value, parent_type, field, is_non_null, ast_node, result_name, selection_result)
|
628
650
|
elsif value.is_a?(GraphQL::UnauthorizedError)
|
629
651
|
# this hook might raise & crash, or it might return
|
630
652
|
# a replacement value
|
@@ -633,7 +655,7 @@ module GraphQL
|
|
633
655
|
rescue GraphQL::ExecutionError => err
|
634
656
|
err
|
635
657
|
end
|
636
|
-
continue_value(
|
658
|
+
continue_value(next_value, parent_type, field, is_non_null, ast_node, result_name, selection_result)
|
637
659
|
elsif GraphQL::Execution::SKIP == value
|
638
660
|
# It's possible a lazy was already written here
|
639
661
|
case selection_result
|
@@ -659,7 +681,7 @@ module GraphQL
|
|
659
681
|
if selection_result.nil? || !dead_result?(selection_result)
|
660
682
|
value.each_with_index do |error, index|
|
661
683
|
error.ast_node ||= ast_node
|
662
|
-
error.path ||=
|
684
|
+
error.path ||= current_path + (list_type_at_all ? [index] : [])
|
663
685
|
context.errors << error
|
664
686
|
end
|
665
687
|
if selection_result
|
@@ -692,7 +714,7 @@ module GraphQL
|
|
692
714
|
# Location information from `path` and `ast_node`.
|
693
715
|
#
|
694
716
|
# @return [Lazy, Array, Hash, Object] Lazy, Array, and Hash are all traversed to resolve lazy values later
|
695
|
-
def continue_field(
|
717
|
+
def continue_field(value, owner_type, field, current_type, ast_node, next_selections, is_non_null, owner_object, arguments, result_name, selection_result) # rubocop:disable Metrics/ParameterLists
|
696
718
|
if current_type.non_null?
|
697
719
|
current_type = current_type.of_type
|
698
720
|
is_non_null = true
|
@@ -708,8 +730,8 @@ module GraphQL
|
|
708
730
|
set_result(selection_result, result_name, r)
|
709
731
|
r
|
710
732
|
when "UNION", "INTERFACE"
|
711
|
-
resolved_type_or_lazy = resolve_type(current_type, value
|
712
|
-
after_lazy(resolved_type_or_lazy, owner: current_type,
|
733
|
+
resolved_type_or_lazy = resolve_type(current_type, value)
|
734
|
+
after_lazy(resolved_type_or_lazy, owner: current_type, ast_node: ast_node, field: field, owner_object: owner_object, arguments: arguments, trace: false, result_name: result_name, result: selection_result) do |resolved_type_result|
|
713
735
|
if resolved_type_result.is_a?(Array) && resolved_type_result.length == 2
|
714
736
|
resolved_type, resolved_value = resolved_type_result
|
715
737
|
else
|
@@ -726,7 +748,7 @@ module GraphQL
|
|
726
748
|
set_result(selection_result, result_name, nil)
|
727
749
|
nil
|
728
750
|
else
|
729
|
-
continue_field(
|
751
|
+
continue_field(resolved_value, owner_type, field, resolved_type, ast_node, next_selections, is_non_null, owner_object, arguments, result_name, selection_result)
|
730
752
|
end
|
731
753
|
end
|
732
754
|
when "OBJECT"
|
@@ -735,8 +757,8 @@ module GraphQL
|
|
735
757
|
rescue GraphQL::ExecutionError => err
|
736
758
|
err
|
737
759
|
end
|
738
|
-
after_lazy(object_proxy, owner: current_type,
|
739
|
-
continue_value = continue_value(
|
760
|
+
after_lazy(object_proxy, owner: current_type, ast_node: ast_node, field: field, owner_object: owner_object, arguments: arguments, trace: false, result_name: result_name, result: selection_result) do |inner_object|
|
761
|
+
continue_value = continue_value(inner_object, owner_type, field, is_non_null, ast_node, result_name, selection_result)
|
740
762
|
if HALT != continue_value
|
741
763
|
response_hash = GraphQLResultHash.new(result_name, selection_result)
|
742
764
|
set_result(selection_result, result_name, response_hash)
|
@@ -757,10 +779,10 @@ module GraphQL
|
|
757
779
|
this_result = response_hash
|
758
780
|
final_result = nil
|
759
781
|
end
|
760
|
-
|
782
|
+
# Don't pass `result_name` here because it's already included in the new response hash
|
783
|
+
set_all_interpreter_context(continue_value, nil, nil, nil, this_result) # reset this mutable state
|
761
784
|
call_method_on_directives(:resolve, continue_value, selections.graphql_directives) do
|
762
785
|
evaluate_selections(
|
763
|
-
path,
|
764
786
|
continue_value,
|
765
787
|
current_type,
|
766
788
|
false,
|
@@ -781,40 +803,27 @@ module GraphQL
|
|
781
803
|
response_list = GraphQLResultArray.new(result_name, selection_result)
|
782
804
|
response_list.graphql_non_null_list_items = inner_type.non_null?
|
783
805
|
set_result(selection_result, result_name, response_list)
|
784
|
-
result_was_set = false
|
785
806
|
idx = 0
|
786
807
|
list_value = begin
|
787
808
|
value.each do |inner_value|
|
788
809
|
break if dead_result?(response_list)
|
789
|
-
if !result_was_set
|
790
|
-
# Don't set the result unless `.each` is successful
|
791
|
-
set_result(selection_result, result_name, response_list)
|
792
|
-
result_was_set = true
|
793
|
-
end
|
794
|
-
next_path = path + [idx]
|
795
810
|
this_idx = idx
|
796
|
-
next_path.freeze
|
797
811
|
idx += 1
|
798
812
|
if use_dataloader_job
|
799
813
|
@dataloader.append_job do
|
800
|
-
resolve_list_item(inner_value, inner_type,
|
814
|
+
resolve_list_item(inner_value, inner_type, ast_node, field, owner_object, arguments, this_idx, response_list, next_selections, owner_type)
|
801
815
|
end
|
802
816
|
else
|
803
|
-
resolve_list_item(inner_value, inner_type,
|
817
|
+
resolve_list_item(inner_value, inner_type, ast_node, field, owner_object, arguments, this_idx, response_list, next_selections, owner_type)
|
804
818
|
end
|
805
819
|
end
|
806
|
-
# Maybe the list was empty and the block was never called.
|
807
|
-
if !result_was_set
|
808
|
-
set_result(selection_result, result_name, response_list)
|
809
|
-
result_was_set = true
|
810
|
-
end
|
811
820
|
|
812
821
|
response_list
|
813
822
|
rescue NoMethodError => err
|
814
823
|
# Ruby 2.2 doesn't have NoMethodError#receiver, can't check that one in this case. (It's been EOL since 2017.)
|
815
824
|
if err.name == :each && (err.respond_to?(:receiver) ? err.receiver == value : true)
|
816
825
|
# This happens when the GraphQL schema doesn't match the implementation. Help the dev debug.
|
817
|
-
raise ListResultFailedError.new(value: value, field: field, path:
|
826
|
+
raise ListResultFailedError.new(value: value, field: field, path: current_path)
|
818
827
|
else
|
819
828
|
# This was some other NoMethodError -- let it bubble to reveal the real error.
|
820
829
|
raise
|
@@ -829,20 +838,20 @@ module GraphQL
|
|
829
838
|
end
|
830
839
|
end
|
831
840
|
|
832
|
-
continue_value(
|
841
|
+
continue_value(list_value, owner_type, field, inner_type.non_null?, ast_node, result_name, selection_result)
|
833
842
|
else
|
834
843
|
raise "Invariant: Unhandled type kind #{current_type.kind} (#{current_type})"
|
835
844
|
end
|
836
845
|
end
|
837
846
|
|
838
|
-
def resolve_list_item(inner_value, inner_type,
|
839
|
-
set_all_interpreter_context(nil, nil, nil,
|
847
|
+
def resolve_list_item(inner_value, inner_type, ast_node, field, owner_object, arguments, this_idx, response_list, next_selections, owner_type) # rubocop:disable Metrics/ParameterLists
|
848
|
+
set_all_interpreter_context(nil, nil, nil, this_idx, response_list)
|
840
849
|
call_method_on_directives(:resolve_each, owner_object, ast_node.directives) do
|
841
850
|
# This will update `response_list` with the lazy
|
842
|
-
after_lazy(inner_value, owner: inner_type,
|
843
|
-
continue_value = continue_value(
|
851
|
+
after_lazy(inner_value, owner: inner_type, ast_node: ast_node, field: field, owner_object: owner_object, arguments: arguments, result_name: this_idx, result: response_list) do |inner_inner_value|
|
852
|
+
continue_value = continue_value(inner_inner_value, owner_type, field, inner_type.non_null?, ast_node, this_idx, response_list)
|
844
853
|
if HALT != continue_value
|
845
|
-
continue_field(
|
854
|
+
continue_field(continue_value, owner_type, field, inner_type, ast_node, next_selections, false, owner_object, arguments, this_idx, response_list)
|
846
855
|
end
|
847
856
|
end
|
848
857
|
end
|
@@ -861,7 +870,6 @@ module GraphQL
|
|
861
870
|
dir_defn = @schema_directives.fetch(dir_node.name)
|
862
871
|
raw_dir_args = arguments(nil, dir_defn, dir_node)
|
863
872
|
dir_args = continue_value(
|
864
|
-
@context[:current_path], # path
|
865
873
|
raw_dir_args, # value
|
866
874
|
dir_defn, # parent_type
|
867
875
|
nil, # field
|
@@ -893,7 +901,7 @@ module GraphQL
|
|
893
901
|
true
|
894
902
|
end
|
895
903
|
|
896
|
-
def set_all_interpreter_context(object, field, arguments,
|
904
|
+
def set_all_interpreter_context(object, field, arguments, result_name, result)
|
897
905
|
ti = thread_info
|
898
906
|
if object
|
899
907
|
ti[:current_object] = object
|
@@ -904,26 +912,26 @@ module GraphQL
|
|
904
912
|
if arguments
|
905
913
|
ti[:current_arguments] = arguments
|
906
914
|
end
|
907
|
-
|
908
|
-
|
915
|
+
ti[:current_result_name] = result_name
|
916
|
+
if result
|
917
|
+
ti[:current_result] = result
|
909
918
|
end
|
910
919
|
end
|
911
920
|
|
912
921
|
# @param obj [Object] Some user-returned value that may want to be batched
|
913
|
-
# @param path [Array<String>]
|
914
922
|
# @param field [GraphQL::Schema::Field]
|
915
923
|
# @param eager [Boolean] Set to `true` for mutation root fields only
|
916
924
|
# @param trace [Boolean] If `false`, don't wrap this with field tracing
|
917
925
|
# @return [GraphQL::Execution::Lazy, Object] If loading `object` will be deferred, it's a wrapper over it.
|
918
|
-
def after_lazy(lazy_obj, owner:, field:,
|
926
|
+
def after_lazy(lazy_obj, owner:, field:, owner_object:, arguments:, ast_node:, result:, result_name:, eager: false, trace: true, &block)
|
919
927
|
if lazy?(lazy_obj)
|
920
|
-
lazy = GraphQL::Execution::Lazy.new(
|
921
|
-
set_all_interpreter_context(owner_object, field, arguments,
|
928
|
+
lazy = GraphQL::Execution::Lazy.new(field: field) do
|
929
|
+
set_all_interpreter_context(owner_object, field, arguments, result_name, result)
|
922
930
|
# Wrap the execution of _this_ method with tracing,
|
923
931
|
# but don't wrap the continuation below
|
924
932
|
inner_obj = begin
|
925
933
|
if trace
|
926
|
-
query.
|
934
|
+
query.current_trace.execute_field_lazy(field: field, query: query, object: owner_object, arguments: arguments, ast_node: ast_node) do
|
927
935
|
schema.sync_lazy(lazy_obj)
|
928
936
|
end
|
929
937
|
else
|
@@ -945,10 +953,11 @@ module GraphQL
|
|
945
953
|
lazy.value
|
946
954
|
else
|
947
955
|
set_result(result, result_name, lazy)
|
956
|
+
@lazies_at_depth[current_depth] << lazy
|
948
957
|
lazy
|
949
958
|
end
|
950
959
|
else
|
951
|
-
set_all_interpreter_context(owner_object, field, arguments,
|
960
|
+
set_all_interpreter_context(owner_object, field, arguments, result_name, result)
|
952
961
|
yield(lazy_obj)
|
953
962
|
end
|
954
963
|
end
|
@@ -962,25 +971,24 @@ module GraphQL
|
|
962
971
|
end
|
963
972
|
end
|
964
973
|
|
965
|
-
|
966
|
-
|
967
|
-
|
968
|
-
|
969
|
-
|
970
|
-
|
971
|
-
|
972
|
-
|
974
|
+
def delete_all_interpreter_context
|
975
|
+
if (ti = thread_info)
|
976
|
+
ti.delete(:current_result)
|
977
|
+
ti.delete(:current_result_name)
|
978
|
+
ti.delete(:current_field)
|
979
|
+
ti.delete(:current_object)
|
980
|
+
ti.delete(:current_arguments)
|
981
|
+
end
|
973
982
|
end
|
974
983
|
|
975
|
-
def resolve_type(type, value
|
976
|
-
|
977
|
-
resolved_type, resolved_value = query.trace("resolve_type", trace_payload) do
|
984
|
+
def resolve_type(type, value)
|
985
|
+
resolved_type, resolved_value = query.current_trace.resolve_type(query: query, type: type, object: value) do
|
978
986
|
query.resolve_type(type, value)
|
979
987
|
end
|
980
988
|
|
981
989
|
if lazy?(resolved_type)
|
982
990
|
GraphQL::Execution::Lazy.new do
|
983
|
-
query.
|
991
|
+
query.current_trace.resolve_type_lazy(query: query, type: type, object: value) do
|
984
992
|
schema.sync_lazy(resolved_type)
|
985
993
|
end
|
986
994
|
end
|
@@ -34,11 +34,12 @@ module GraphQL
|
|
34
34
|
end
|
35
35
|
|
36
36
|
multiplex = Execution::Multiplex.new(schema: schema, queries: queries, context: context, max_complexity: max_complexity)
|
37
|
-
multiplex.
|
37
|
+
multiplex.current_trace.execute_multiplex(multiplex: multiplex) do
|
38
38
|
schema = multiplex.schema
|
39
39
|
queries = multiplex.queries
|
40
40
|
query_instrumenters = schema.instrumenters[:query]
|
41
41
|
multiplex_instrumenters = schema.instrumenters[:multiplex]
|
42
|
+
lazies_at_depth = Hash.new { |h, k| h[k] = [] }
|
42
43
|
|
43
44
|
# First, run multiplex instrumentation, then query instrumentation for each query
|
44
45
|
call_hooks(multiplex_instrumenters, multiplex, :before_multiplex, :after_multiplex) do
|
@@ -67,10 +68,10 @@ module GraphQL
|
|
67
68
|
# Although queries in a multiplex _share_ an Interpreter instance,
|
68
69
|
# they also have another item of state, which is private to that query
|
69
70
|
# in particular, assign it here:
|
70
|
-
runtime = Runtime.new(query: query)
|
71
|
+
runtime = Runtime.new(query: query, lazies_at_depth: lazies_at_depth)
|
71
72
|
query.context.namespace(:interpreter_runtime)[:runtime] = runtime
|
72
73
|
|
73
|
-
query.
|
74
|
+
query.current_trace.execute_query(query: query) do
|
74
75
|
runtime.run_eager
|
75
76
|
end
|
76
77
|
rescue GraphQL::ExecutionError => err
|
@@ -95,16 +96,13 @@ module GraphQL
|
|
95
96
|
runtime ? runtime.final_result : nil
|
96
97
|
end
|
97
98
|
final_values.compact!
|
98
|
-
tracer.
|
99
|
-
Interpreter::Resolve.
|
99
|
+
tracer.current_trace.execute_query_lazy(multiplex: multiplex, query: query) do
|
100
|
+
Interpreter::Resolve.resolve_each_depth(lazies_at_depth, multiplex.dataloader)
|
100
101
|
end
|
101
102
|
queries.each do |query|
|
102
103
|
runtime = query.context.namespace(:interpreter_runtime)[:runtime]
|
103
104
|
if runtime
|
104
|
-
runtime.
|
105
|
-
runtime.delete_interpreter_context(:current_field)
|
106
|
-
runtime.delete_interpreter_context(:current_object)
|
107
|
-
runtime.delete_interpreter_context(:current_arguments)
|
105
|
+
runtime.delete_all_interpreter_context
|
108
106
|
end
|
109
107
|
end
|
110
108
|
}
|
@@ -150,10 +148,7 @@ module GraphQL
|
|
150
148
|
queries.map { |query|
|
151
149
|
runtime = query.context.namespace(:interpreter_runtime)[:runtime]
|
152
150
|
if runtime
|
153
|
-
runtime.
|
154
|
-
runtime.delete_interpreter_context(:current_field)
|
155
|
-
runtime.delete_interpreter_context(:current_object)
|
156
|
-
runtime.delete_interpreter_context(:current_arguments)
|
151
|
+
runtime.delete_all_interpreter_context
|
157
152
|
end
|
158
153
|
}
|
159
154
|
end
|
@@ -12,16 +12,14 @@ module GraphQL
|
|
12
12
|
# - It has no error-catching functionality
|
13
13
|
# @api private
|
14
14
|
class Lazy
|
15
|
-
attr_reader :
|
15
|
+
attr_reader :field
|
16
16
|
|
17
17
|
# Create a {Lazy} which will get its inner value by calling the block
|
18
|
-
# @param path [Array<String, Integer>]
|
19
18
|
# @param field [GraphQL::Schema::Field]
|
20
19
|
# @param get_value_func [Proc] a block to get the inner value (later)
|
21
|
-
def initialize(
|
20
|
+
def initialize(field: nil, &get_value_func)
|
22
21
|
@get_value_func = get_value_func
|
23
22
|
@resolved = false
|
24
|
-
@path = path
|
25
23
|
@field = field
|
26
24
|
end
|
27
25
|
|
@@ -25,13 +25,14 @@ module GraphQL
|
|
25
25
|
class Multiplex
|
26
26
|
include Tracing::Traceable
|
27
27
|
|
28
|
-
attr_reader :context, :queries, :schema, :max_complexity, :dataloader
|
28
|
+
attr_reader :context, :queries, :schema, :max_complexity, :dataloader, :current_trace
|
29
29
|
|
30
30
|
def initialize(schema:, queries:, context:, max_complexity:)
|
31
31
|
@schema = schema
|
32
32
|
@queries = queries
|
33
33
|
@queries.each { |q| q.multiplex = self }
|
34
34
|
@context = context
|
35
|
+
@current_trace = @context[:trace] || schema.new_trace(multiplex: self)
|
35
36
|
@dataloader = @context[:dataloader] ||= @schema.dataloader_class.new
|
36
37
|
@tracers = schema.tracers + (context[:tracers] || [])
|
37
38
|
# Support `context: {backtrace: true}`
|
Binary file
|