graphql 2.4.3 → 2.4.13
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.
- checksums.yaml +4 -4
- data/lib/graphql/analysis/analyzer.rb +2 -1
- data/lib/graphql/analysis/visitor.rb +38 -41
- data/lib/graphql/analysis.rb +15 -12
- data/lib/graphql/autoload.rb +38 -0
- data/lib/graphql/backtrace/table.rb +95 -55
- data/lib/graphql/backtrace.rb +1 -19
- data/lib/graphql/current.rb +6 -1
- data/lib/graphql/dashboard/statics/bootstrap-5.3.3.min.css +6 -0
- data/lib/graphql/dashboard/statics/bootstrap-5.3.3.min.js +7 -0
- data/lib/graphql/dashboard/statics/dashboard.css +3 -0
- data/lib/graphql/dashboard/statics/dashboard.js +78 -0
- data/lib/graphql/dashboard/statics/header-icon.png +0 -0
- data/lib/graphql/dashboard/statics/icon.png +0 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/landings/show.html.erb +18 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/traces/index.html.erb +63 -0
- data/lib/graphql/dashboard/views/layouts/graphql/dashboard/application.html.erb +60 -0
- data/lib/graphql/dashboard.rb +142 -0
- data/lib/graphql/dataloader/active_record_association_source.rb +64 -0
- data/lib/graphql/dataloader/active_record_source.rb +26 -0
- data/lib/graphql/dataloader/async_dataloader.rb +21 -9
- data/lib/graphql/dataloader/null_dataloader.rb +1 -1
- data/lib/graphql/dataloader/source.rb +3 -3
- data/lib/graphql/dataloader.rb +43 -14
- data/lib/graphql/execution/interpreter/resolve.rb +3 -3
- data/lib/graphql/execution/interpreter/runtime/graphql_result.rb +11 -4
- data/lib/graphql/execution/interpreter/runtime.rb +67 -40
- data/lib/graphql/execution/interpreter.rb +16 -6
- data/lib/graphql/execution/multiplex.rb +0 -4
- data/lib/graphql/introspection/directive_location_enum.rb +1 -1
- data/lib/graphql/invalid_name_error.rb +1 -1
- data/lib/graphql/invalid_null_error.rb +5 -15
- data/lib/graphql/language/cache.rb +13 -0
- data/lib/graphql/language/document_from_schema_definition.rb +8 -7
- data/lib/graphql/language/lexer.rb +11 -4
- data/lib/graphql/language/nodes.rb +3 -0
- data/lib/graphql/language/parser.rb +2 -2
- data/lib/graphql/language/printer.rb +8 -8
- data/lib/graphql/language/static_visitor.rb +37 -33
- data/lib/graphql/language/visitor.rb +59 -55
- data/lib/graphql/pagination/connection.rb +1 -1
- data/lib/graphql/query/context/scoped_context.rb +1 -1
- data/lib/graphql/query/context.rb +6 -5
- data/lib/graphql/query/variable_validation_error.rb +1 -1
- data/lib/graphql/query.rb +20 -22
- data/lib/graphql/railtie.rb +7 -0
- data/lib/graphql/schema/addition.rb +1 -1
- data/lib/graphql/schema/argument.rb +3 -5
- data/lib/graphql/schema/build_from_definition.rb +8 -7
- data/lib/graphql/schema/directive/flagged.rb +1 -1
- data/lib/graphql/schema/directive.rb +2 -2
- data/lib/graphql/schema/enum.rb +36 -1
- data/lib/graphql/schema/enum_value.rb +1 -1
- data/lib/graphql/schema/field/scope_extension.rb +1 -1
- data/lib/graphql/schema/field.rb +12 -12
- data/lib/graphql/schema/field_extension.rb +1 -1
- data/lib/graphql/schema/has_single_input_argument.rb +3 -1
- data/lib/graphql/schema/input_object.rb +70 -34
- data/lib/graphql/schema/interface.rb +3 -2
- data/lib/graphql/schema/loader.rb +1 -1
- data/lib/graphql/schema/member/has_arguments.rb +25 -17
- data/lib/graphql/schema/member/has_dataloader.rb +60 -0
- data/lib/graphql/schema/member/has_directives.rb +4 -4
- data/lib/graphql/schema/member/has_fields.rb +19 -1
- data/lib/graphql/schema/member/has_interfaces.rb +5 -5
- data/lib/graphql/schema/member/has_validators.rb +1 -1
- data/lib/graphql/schema/member/scoped.rb +1 -1
- data/lib/graphql/schema/member/type_system_helpers.rb +1 -1
- data/lib/graphql/schema/member.rb +1 -0
- data/lib/graphql/schema/object.rb +25 -8
- data/lib/graphql/schema/relay_classic_mutation.rb +0 -1
- data/lib/graphql/schema/resolver.rb +11 -10
- data/lib/graphql/schema/subscription.rb +52 -6
- data/lib/graphql/schema/union.rb +1 -1
- data/lib/graphql/schema/validator/required_validator.rb +23 -6
- data/lib/graphql/schema/validator.rb +1 -1
- data/lib/graphql/schema/visibility/migration.rb +1 -0
- data/lib/graphql/schema/visibility/profile.rb +69 -237
- data/lib/graphql/schema/visibility/visit.rb +190 -0
- data/lib/graphql/schema/visibility.rb +169 -28
- data/lib/graphql/schema/warden.rb +18 -5
- data/lib/graphql/schema.rb +90 -43
- data/lib/graphql/static_validation/rules/argument_names_are_unique.rb +1 -1
- data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +1 -1
- data/lib/graphql/static_validation/rules/fields_will_merge.rb +1 -1
- data/lib/graphql/static_validation/rules/no_definitions_are_present.rb +1 -1
- data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +1 -1
- data/lib/graphql/static_validation/rules/unique_directives_per_location.rb +1 -1
- data/lib/graphql/static_validation/rules/variable_names_are_unique.rb +1 -1
- data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +1 -1
- data/lib/graphql/static_validation/validation_context.rb +1 -0
- data/lib/graphql/static_validation/validator.rb +6 -1
- data/lib/graphql/subscriptions/action_cable_subscriptions.rb +1 -1
- data/lib/graphql/subscriptions/default_subscription_resolve_extension.rb +12 -10
- data/lib/graphql/subscriptions/event.rb +12 -1
- data/lib/graphql/subscriptions/serialize.rb +1 -1
- data/lib/graphql/subscriptions.rb +1 -1
- data/lib/graphql/testing/helpers.rb +2 -2
- data/lib/graphql/tracing/active_support_notifications_trace.rb +7 -3
- data/lib/graphql/tracing/active_support_notifications_tracing.rb +1 -1
- data/lib/graphql/tracing/appoptics_trace.rb +9 -1
- data/lib/graphql/tracing/appoptics_tracing.rb +2 -0
- data/lib/graphql/tracing/appsignal_trace.rb +12 -0
- data/lib/graphql/tracing/appsignal_tracing.rb +2 -0
- data/lib/graphql/tracing/call_legacy_tracers.rb +66 -0
- data/lib/graphql/tracing/data_dog_trace.rb +11 -0
- data/lib/graphql/tracing/data_dog_tracing.rb +2 -0
- data/lib/graphql/tracing/detailed_trace/memory_backend.rb +60 -0
- data/lib/graphql/tracing/detailed_trace/redis_backend.rb +72 -0
- data/lib/graphql/tracing/detailed_trace.rb +93 -0
- data/lib/graphql/tracing/legacy_hooks_trace.rb +1 -0
- data/lib/graphql/tracing/legacy_trace.rb +4 -61
- data/lib/graphql/tracing/new_relic_trace.rb +164 -41
- data/lib/graphql/tracing/new_relic_tracing.rb +2 -0
- data/lib/graphql/tracing/notifications_trace.rb +4 -0
- data/lib/graphql/tracing/notifications_tracing.rb +2 -0
- data/lib/graphql/tracing/null_trace.rb +9 -0
- data/lib/graphql/tracing/perfetto_trace/trace.proto +141 -0
- data/lib/graphql/tracing/perfetto_trace/trace_pb.rb +33 -0
- data/lib/graphql/tracing/perfetto_trace.rb +737 -0
- data/lib/graphql/tracing/platform_trace.rb +5 -0
- data/lib/graphql/tracing/prometheus_trace/graphql_collector.rb +2 -0
- data/lib/graphql/tracing/prometheus_trace.rb +31 -0
- data/lib/graphql/tracing/prometheus_tracing.rb +2 -0
- data/lib/graphql/tracing/scout_trace.rb +11 -0
- data/lib/graphql/tracing/scout_tracing.rb +2 -0
- data/lib/graphql/tracing/sentry_trace.rb +11 -0
- data/lib/graphql/tracing/statsd_trace.rb +15 -0
- data/lib/graphql/tracing/statsd_tracing.rb +2 -0
- data/lib/graphql/tracing/trace.rb +128 -1
- data/lib/graphql/tracing.rb +30 -30
- data/lib/graphql/types/relay/connection_behaviors.rb +3 -3
- data/lib/graphql/types/relay/edge_behaviors.rb +2 -2
- data/lib/graphql/types.rb +18 -11
- data/lib/graphql/version.rb +1 -1
- data/lib/graphql.rb +55 -47
- metadata +152 -10
- data/lib/graphql/backtrace/inspect_result.rb +0 -38
- data/lib/graphql/backtrace/trace.rb +0 -93
- data/lib/graphql/backtrace/tracer.rb +0 -80
- data/lib/graphql/schema/null_mask.rb +0 -11
@@ -74,7 +74,7 @@ module GraphQL
|
|
74
74
|
runtime_object = root_type.wrap(query.root_value, context)
|
75
75
|
runtime_object = schema.sync_lazy(runtime_object)
|
76
76
|
is_eager = root_op_type == "mutation"
|
77
|
-
@response = GraphQLResultHash.new(nil, root_type, runtime_object, nil, false, root_operation.selections, is_eager)
|
77
|
+
@response = GraphQLResultHash.new(nil, root_type, runtime_object, nil, false, root_operation.selections, is_eager, root_operation, nil, nil)
|
78
78
|
st = get_current_runtime_state
|
79
79
|
st.current_result = @response
|
80
80
|
|
@@ -85,7 +85,7 @@ module GraphQL
|
|
85
85
|
call_method_on_directives(:resolve, runtime_object, root_operation.directives) do # execute query level directives
|
86
86
|
each_gathered_selections(@response) do |selections, is_selection_array|
|
87
87
|
if is_selection_array
|
88
|
-
selection_response = GraphQLResultHash.new(nil, root_type, runtime_object, nil, false, selections, is_eager)
|
88
|
+
selection_response = GraphQLResultHash.new(nil, root_type, runtime_object, nil, false, selections, is_eager, root_operation, nil, nil)
|
89
89
|
final_response = @response
|
90
90
|
else
|
91
91
|
selection_response = @response
|
@@ -142,7 +142,7 @@ module GraphQL
|
|
142
142
|
end
|
143
143
|
else
|
144
144
|
# This is an InlineFragment or a FragmentSpread
|
145
|
-
if
|
145
|
+
if !@runtime_directive_names.empty? && node.directives.any? { |d| @runtime_directive_names.include?(d.name) }
|
146
146
|
next_selections = {}
|
147
147
|
next_selections[:graphql_directives] = node.directives
|
148
148
|
if selections_to_run
|
@@ -218,8 +218,10 @@ module GraphQL
|
|
218
218
|
result_name, field_ast_nodes_or_ast_node, selections_result
|
219
219
|
)
|
220
220
|
finished_jobs += 1
|
221
|
-
if
|
222
|
-
|
221
|
+
if finished_jobs == enqueued_jobs
|
222
|
+
if target_result
|
223
|
+
selections_result.merge_into(target_result)
|
224
|
+
end
|
223
225
|
end
|
224
226
|
@dataloader.clear_cache
|
225
227
|
}
|
@@ -229,8 +231,10 @@ module GraphQL
|
|
229
231
|
result_name, field_ast_nodes_or_ast_node, selections_result
|
230
232
|
)
|
231
233
|
finished_jobs += 1
|
232
|
-
if
|
233
|
-
|
234
|
+
if finished_jobs == enqueued_jobs
|
235
|
+
if target_result
|
236
|
+
selections_result.merge_into(target_result)
|
237
|
+
end
|
234
238
|
end
|
235
239
|
}
|
236
240
|
end
|
@@ -332,7 +336,7 @@ module GraphQL
|
|
332
336
|
extra_args[extra] = field_defn.fetch_extra(extra, context)
|
333
337
|
end
|
334
338
|
end
|
335
|
-
if extra_args.
|
339
|
+
if !extra_args.empty?
|
336
340
|
resolved_arguments = resolved_arguments.merge_extras(extra_args)
|
337
341
|
end
|
338
342
|
resolved_arguments.keyword_arguments
|
@@ -361,7 +365,7 @@ module GraphQL
|
|
361
365
|
end
|
362
366
|
|
363
367
|
field_result = call_method_on_directives(:resolve, object, directives) do
|
364
|
-
if directives.
|
368
|
+
if !directives.empty?
|
365
369
|
# This might be executed in a different context; reset this info
|
366
370
|
runtime_state = get_current_runtime_state
|
367
371
|
runtime_state.current_field = field_defn
|
@@ -371,6 +375,7 @@ module GraphQL
|
|
371
375
|
end
|
372
376
|
# Actually call the field resolver and capture the result
|
373
377
|
app_result = begin
|
378
|
+
@current_trace.begin_execute_field(field_defn, object, kwarg_arguments, query)
|
374
379
|
@current_trace.execute_field(field: field_defn, ast_node: ast_node, query: query, object: object, arguments: kwarg_arguments) do
|
375
380
|
field_defn.resolve(object, kwarg_arguments, context)
|
376
381
|
end
|
@@ -383,6 +388,7 @@ module GraphQL
|
|
383
388
|
ex_err
|
384
389
|
end
|
385
390
|
end
|
391
|
+
@current_trace.end_execute_field(field_defn, object, kwarg_arguments, query, app_result)
|
386
392
|
after_lazy(app_result, field: field_defn, ast_node: ast_node, owner_object: object, arguments: resolved_arguments, result_name: result_name, result: selection_result, runtime_state: runtime_state) do |inner_result, runtime_state|
|
387
393
|
owner_type = selection_result.graphql_result_type
|
388
394
|
return_type = field_defn.type
|
@@ -391,6 +397,8 @@ module GraphQL
|
|
391
397
|
was_scoped = runtime_state.was_authorized_by_scope_items
|
392
398
|
runtime_state.was_authorized_by_scope_items = nil
|
393
399
|
continue_field(continue_value, owner_type, field_defn, return_type, ast_node, next_selections, false, object, resolved_arguments, result_name, selection_result, was_scoped, runtime_state)
|
400
|
+
else
|
401
|
+
nil
|
394
402
|
end
|
395
403
|
end
|
396
404
|
end
|
@@ -465,7 +473,7 @@ module GraphQL
|
|
465
473
|
# When this comes from a list item, use the parent object:
|
466
474
|
parent_type = selection_result.is_a?(GraphQLResultArray) ? selection_result.graphql_parent.graphql_result_type : selection_result.graphql_result_type
|
467
475
|
# This block is called if `result_name` is not dead. (Maybe a previous invalid nil caused it be marked dead.)
|
468
|
-
err = parent_type::InvalidNullError.new(parent_type, field,
|
476
|
+
err = parent_type::InvalidNullError.new(parent_type, field, ast_node)
|
469
477
|
schema.type_error(err, context)
|
470
478
|
end
|
471
479
|
else
|
@@ -525,7 +533,7 @@ module GraphQL
|
|
525
533
|
end
|
526
534
|
when Array
|
527
535
|
# It's an array full of execution errors; add them all.
|
528
|
-
if value.
|
536
|
+
if !value.empty? && value.all?(GraphQL::ExecutionError)
|
529
537
|
list_type_at_all = (field && (field.type.list?))
|
530
538
|
if selection_result.nil? || !selection_result.graphql_dead
|
531
539
|
value.each_with_index do |error, index|
|
@@ -574,7 +582,7 @@ module GraphQL
|
|
574
582
|
r = begin
|
575
583
|
current_type.coerce_result(value, context)
|
576
584
|
rescue StandardError => err
|
577
|
-
|
585
|
+
query.handle_or_reraise(err)
|
578
586
|
end
|
579
587
|
set_result(selection_result, result_name, r, false, is_non_null)
|
580
588
|
r
|
@@ -609,11 +617,11 @@ module GraphQL
|
|
609
617
|
after_lazy(object_proxy, ast_node: ast_node, field: field, owner_object: owner_object, arguments: arguments, trace: false, result_name: result_name, result: selection_result, runtime_state: runtime_state) do |inner_object, runtime_state|
|
610
618
|
continue_value = continue_value(inner_object, field, is_non_null, ast_node, result_name, selection_result)
|
611
619
|
if HALT != continue_value
|
612
|
-
response_hash = GraphQLResultHash.new(result_name, current_type, continue_value, selection_result, is_non_null, next_selections, false)
|
620
|
+
response_hash = GraphQLResultHash.new(result_name, current_type, continue_value, selection_result, is_non_null, next_selections, false, ast_node, arguments, field)
|
613
621
|
set_result(selection_result, result_name, response_hash, true, is_non_null)
|
614
622
|
each_gathered_selections(response_hash) do |selections, is_selection_array|
|
615
623
|
if is_selection_array
|
616
|
-
this_result = GraphQLResultHash.new(result_name, current_type, continue_value, selection_result, is_non_null, selections, false)
|
624
|
+
this_result = GraphQLResultHash.new(result_name, current_type, continue_value, selection_result, is_non_null, selections, false, ast_node, arguments, field)
|
617
625
|
final_result = response_hash
|
618
626
|
else
|
619
627
|
this_result = response_hash
|
@@ -634,35 +642,43 @@ module GraphQL
|
|
634
642
|
# This is true for objects, unions, and interfaces
|
635
643
|
use_dataloader_job = !inner_type.unwrap.kind.input?
|
636
644
|
inner_type_non_null = inner_type.non_null?
|
637
|
-
response_list = GraphQLResultArray.new(result_name, current_type, owner_object, selection_result, is_non_null, next_selections, false)
|
645
|
+
response_list = GraphQLResultArray.new(result_name, current_type, owner_object, selection_result, is_non_null, next_selections, false, ast_node, arguments, field)
|
638
646
|
set_result(selection_result, result_name, response_list, true, is_non_null)
|
639
647
|
idx = nil
|
640
648
|
list_value = begin
|
641
|
-
|
642
|
-
|
643
|
-
|
644
|
-
|
645
|
-
|
646
|
-
|
649
|
+
begin
|
650
|
+
value.each do |inner_value|
|
651
|
+
idx ||= 0
|
652
|
+
this_idx = idx
|
653
|
+
idx += 1
|
654
|
+
if use_dataloader_job
|
655
|
+
@dataloader.append_job do
|
656
|
+
resolve_list_item(inner_value, inner_type, inner_type_non_null, ast_node, field, owner_object, arguments, this_idx, response_list, owner_type, was_scoped, runtime_state)
|
657
|
+
end
|
658
|
+
else
|
647
659
|
resolve_list_item(inner_value, inner_type, inner_type_non_null, ast_node, field, owner_object, arguments, this_idx, response_list, owner_type, was_scoped, runtime_state)
|
648
660
|
end
|
649
|
-
else
|
650
|
-
resolve_list_item(inner_value, inner_type, inner_type_non_null, ast_node, field, owner_object, arguments, this_idx, response_list, owner_type, was_scoped, runtime_state)
|
651
661
|
end
|
652
|
-
end
|
653
662
|
|
654
|
-
|
655
|
-
|
656
|
-
|
657
|
-
|
658
|
-
|
659
|
-
|
660
|
-
|
661
|
-
|
662
|
-
|
663
|
+
response_list
|
664
|
+
rescue NoMethodError => err
|
665
|
+
# Ruby 2.2 doesn't have NoMethodError#receiver, can't check that one in this case. (It's been EOL since 2017.)
|
666
|
+
if err.name == :each && (err.respond_to?(:receiver) ? err.receiver == value : true)
|
667
|
+
# This happens when the GraphQL schema doesn't match the implementation. Help the dev debug.
|
668
|
+
raise ListResultFailedError.new(value: value, field: field, path: current_path)
|
669
|
+
else
|
670
|
+
# This was some other NoMethodError -- let it bubble to reveal the real error.
|
671
|
+
raise
|
672
|
+
end
|
673
|
+
rescue GraphQL::ExecutionError, GraphQL::UnauthorizedError => ex_err
|
674
|
+
ex_err
|
675
|
+
rescue StandardError => err
|
676
|
+
begin
|
677
|
+
query.handle_or_reraise(err)
|
678
|
+
rescue GraphQL::ExecutionError => ex_err
|
679
|
+
ex_err
|
680
|
+
end
|
663
681
|
end
|
664
|
-
rescue GraphQL::ExecutionError, GraphQL::UnauthorizedError => ex_err
|
665
|
-
ex_err
|
666
682
|
rescue StandardError => err
|
667
683
|
begin
|
668
684
|
query.handle_or_reraise(err)
|
@@ -736,7 +752,7 @@ module GraphQL
|
|
736
752
|
end
|
737
753
|
|
738
754
|
def get_current_runtime_state
|
739
|
-
current_state =
|
755
|
+
current_state = Fiber[:__graphql_runtime_info] ||= {}.compare_by_identity
|
740
756
|
current_state[@query] ||= CurrentState.new
|
741
757
|
end
|
742
758
|
|
@@ -773,8 +789,10 @@ module GraphQL
|
|
773
789
|
runtime_state.was_authorized_by_scope_items = was_authorized_by_scope_items
|
774
790
|
# Wrap the execution of _this_ method with tracing,
|
775
791
|
# but don't wrap the continuation below
|
792
|
+
result = nil
|
776
793
|
inner_obj = begin
|
777
|
-
if trace
|
794
|
+
result = if trace
|
795
|
+
@current_trace.begin_execute_field(field, owner_object, arguments, query)
|
778
796
|
@current_trace.execute_field_lazy(field: field, query: query, object: owner_object, arguments: arguments, ast_node: ast_node) do
|
779
797
|
schema.sync_lazy(lazy_obj)
|
780
798
|
end
|
@@ -789,6 +807,10 @@ module GraphQL
|
|
789
807
|
rescue GraphQL::ExecutionError => ex_err
|
790
808
|
ex_err
|
791
809
|
end
|
810
|
+
ensure
|
811
|
+
if trace
|
812
|
+
@current_trace.end_execute_field(field, owner_object, arguments, query, result)
|
813
|
+
end
|
792
814
|
end
|
793
815
|
yield(inner_obj, runtime_state)
|
794
816
|
end
|
@@ -821,25 +843,30 @@ module GraphQL
|
|
821
843
|
end
|
822
844
|
|
823
845
|
def delete_all_interpreter_context
|
824
|
-
per_query_state =
|
846
|
+
per_query_state = Fiber[:__graphql_runtime_info]
|
825
847
|
if per_query_state
|
826
848
|
per_query_state.delete(@query)
|
827
849
|
if per_query_state.size == 0
|
828
|
-
|
850
|
+
Fiber[:__graphql_runtime_info] = nil
|
829
851
|
end
|
830
852
|
end
|
831
853
|
nil
|
832
854
|
end
|
833
855
|
|
834
856
|
def resolve_type(type, value)
|
857
|
+
@current_trace.begin_resolve_type(type, value, context)
|
835
858
|
resolved_type, resolved_value = @current_trace.resolve_type(query: query, type: type, object: value) do
|
836
859
|
query.resolve_type(type, value)
|
837
860
|
end
|
861
|
+
@current_trace.end_resolve_type(type, value, context, resolved_type)
|
838
862
|
|
839
863
|
if lazy?(resolved_type)
|
840
864
|
GraphQL::Execution::Lazy.new do
|
865
|
+
@current_trace.begin_resolve_type(type, value, context)
|
841
866
|
@current_trace.resolve_type_lazy(query: query, type: type, object: value) do
|
842
|
-
schema.sync_lazy(resolved_type)
|
867
|
+
rt = schema.sync_lazy(resolved_type)
|
868
|
+
@current_trace.end_resolve_type(type, value, context, rt)
|
869
|
+
rt
|
843
870
|
end
|
844
871
|
end
|
845
872
|
else
|
@@ -33,9 +33,12 @@ module GraphQL
|
|
33
33
|
end
|
34
34
|
end
|
35
35
|
|
36
|
+
|
36
37
|
multiplex = Execution::Multiplex.new(schema: schema, queries: queries, context: context, max_complexity: max_complexity)
|
37
38
|
Fiber[:__graphql_current_multiplex] = multiplex
|
38
|
-
multiplex.current_trace
|
39
|
+
trace = multiplex.current_trace
|
40
|
+
trace.begin_execute_multiplex(multiplex)
|
41
|
+
trace.execute_multiplex(multiplex: multiplex) do
|
39
42
|
schema = multiplex.schema
|
40
43
|
queries = multiplex.queries
|
41
44
|
lazies_at_depth = Hash.new { |h, k| h[k] = [] }
|
@@ -44,7 +47,10 @@ module GraphQL
|
|
44
47
|
multiplex_analyzers += [GraphQL::Analysis::MaxQueryComplexity]
|
45
48
|
end
|
46
49
|
|
50
|
+
trace.begin_analyze_multiplex(multiplex, multiplex_analyzers)
|
47
51
|
schema.analysis_engine.analyze_multiplex(multiplex, multiplex_analyzers)
|
52
|
+
trace.end_analyze_multiplex(multiplex, multiplex_analyzers)
|
53
|
+
|
48
54
|
begin
|
49
55
|
# Since this is basically the batching context,
|
50
56
|
# share it for a whole multiplex
|
@@ -53,11 +59,13 @@ module GraphQL
|
|
53
59
|
results = []
|
54
60
|
queries.each_with_index do |query, idx|
|
55
61
|
if query.subscription? && !query.subscription_update?
|
56
|
-
query.context.namespace(:subscriptions)
|
62
|
+
subs_namespace = query.context.namespace(:subscriptions)
|
63
|
+
subs_namespace[:events] = []
|
64
|
+
subs_namespace[:subscriptions] = {}
|
57
65
|
end
|
58
66
|
multiplex.dataloader.append_job {
|
59
67
|
operation = query.selected_operation
|
60
|
-
result = if operation.nil? || !query.valid? || query.context.errors.
|
68
|
+
result = if operation.nil? || !query.valid? || !query.context.errors.empty?
|
61
69
|
NO_OPERATION
|
62
70
|
else
|
63
71
|
begin
|
@@ -100,12 +108,12 @@ module GraphQL
|
|
100
108
|
# Then, find all errors and assign the result to the query object
|
101
109
|
results.each_with_index do |data_result, idx|
|
102
110
|
query = queries[idx]
|
103
|
-
if (events = query.context.namespace(:subscriptions)[:events]) && events.
|
111
|
+
if (events = query.context.namespace(:subscriptions)[:events]) && !events.empty?
|
104
112
|
schema.subscriptions.write_subscription(query, events)
|
105
113
|
end
|
106
114
|
# Assign the result so that it can be accessed in instrumentation
|
107
115
|
query.result_values = if data_result.equal?(NO_OPERATION)
|
108
|
-
if !query.valid? || query.context.errors.
|
116
|
+
if !query.valid? || !query.context.errors.empty?
|
109
117
|
# A bit weird, but `Query#static_errors` _includes_ `query.context.errors`
|
110
118
|
{ "errors" => query.static_errors.map(&:to_h) }
|
111
119
|
else
|
@@ -114,7 +122,7 @@ module GraphQL
|
|
114
122
|
else
|
115
123
|
result = {}
|
116
124
|
|
117
|
-
if query.context.errors.
|
125
|
+
if !query.context.errors.empty?
|
118
126
|
error_result = query.context.errors.map(&:to_h)
|
119
127
|
result["errors"] = error_result
|
120
128
|
end
|
@@ -146,6 +154,8 @@ module GraphQL
|
|
146
154
|
}
|
147
155
|
end
|
148
156
|
end
|
157
|
+
ensure
|
158
|
+
trace&.end_execute_multiplex(multiplex)
|
149
159
|
end
|
150
160
|
end
|
151
161
|
|
@@ -35,10 +35,6 @@ module GraphQL
|
|
35
35
|
@current_trace = @context[:trace] || schema.new_trace(multiplex: self)
|
36
36
|
@dataloader = @context[:dataloader] ||= @schema.dataloader_class.new
|
37
37
|
@tracers = schema.tracers + (context[:tracers] || [])
|
38
|
-
# Support `context: {backtrace: true}`
|
39
|
-
if context[:backtrace] && !@tracers.include?(GraphQL::Backtrace::Tracer)
|
40
|
-
@tracers << GraphQL::Backtrace::Tracer
|
41
|
-
end
|
42
38
|
@max_complexity = max_complexity
|
43
39
|
end
|
44
40
|
end
|
@@ -7,7 +7,7 @@ module GraphQL
|
|
7
7
|
"a __DirectiveLocation describes one such possible adjacencies."
|
8
8
|
|
9
9
|
GraphQL::Schema::Directive::LOCATIONS.each do |location|
|
10
|
-
value(location.to_s, GraphQL::Schema::Directive::LOCATION_DESCRIPTIONS[location], value: location)
|
10
|
+
value(location.to_s, GraphQL::Schema::Directive::LOCATION_DESCRIPTIONS[location], value: location, value_method: false)
|
11
11
|
end
|
12
12
|
introspection true
|
13
13
|
end
|
@@ -2,33 +2,23 @@
|
|
2
2
|
module GraphQL
|
3
3
|
# Raised automatically when a field's resolve function returns `nil`
|
4
4
|
# for a non-null field.
|
5
|
-
class InvalidNullError < GraphQL::
|
5
|
+
class InvalidNullError < GraphQL::Error
|
6
6
|
# @return [GraphQL::BaseType] The owner of {#field}
|
7
7
|
attr_reader :parent_type
|
8
8
|
|
9
9
|
# @return [GraphQL::Field] The field which failed to return a value
|
10
10
|
attr_reader :field
|
11
11
|
|
12
|
-
# @return [
|
13
|
-
attr_reader :
|
12
|
+
# @return [GraphQL::Language::Nodes::Field] the field where the error occurred
|
13
|
+
attr_reader :ast_node
|
14
14
|
|
15
|
-
def initialize(parent_type, field,
|
15
|
+
def initialize(parent_type, field, ast_node)
|
16
16
|
@parent_type = parent_type
|
17
17
|
@field = field
|
18
|
-
@
|
18
|
+
@ast_node = ast_node
|
19
19
|
super("Cannot return null for non-nullable field #{@parent_type.graphql_name}.#{@field.graphql_name}")
|
20
20
|
end
|
21
21
|
|
22
|
-
# @return [Hash] An entry for the response's "errors" key
|
23
|
-
def to_h
|
24
|
-
{ "message" => message }
|
25
|
-
end
|
26
|
-
|
27
|
-
# @deprecated always false
|
28
|
-
def parent_error?
|
29
|
-
false
|
30
|
-
end
|
31
|
-
|
32
22
|
class << self
|
33
23
|
attr_accessor :parent_class
|
34
24
|
|
@@ -5,12 +5,25 @@ require 'digest/sha2'
|
|
5
5
|
|
6
6
|
module GraphQL
|
7
7
|
module Language
|
8
|
+
# This cache is used by {GraphQL::Language::Parser.parse_file} when it's enabled.
|
9
|
+
#
|
10
|
+
# With Rails, parser caching may enabled by setting `config.graphql.parser_cache = true` in your Rails application.
|
11
|
+
#
|
12
|
+
# The cache may be manually built by assigning `GraphQL::Language::Parser.cache = GraphQL::Language::Cache.new("some_dir")`.
|
13
|
+
# This will create a directory (`tmp/cache/graphql` by default) that stores a cache of parsed files.
|
14
|
+
#
|
15
|
+
# Much like [bootsnap](https://github.com/Shopify/bootsnap), the parser cache needs to be cleaned up manually.
|
16
|
+
# You will need to clear the cache directory for each new deployment of your application.
|
17
|
+
# Also note that the parser cache will grow as your schema is loaded, so the cache directory must be writable.
|
18
|
+
#
|
19
|
+
# @see GraphQL::Railtie for simple Rails integration
|
8
20
|
class Cache
|
9
21
|
def initialize(path)
|
10
22
|
@path = path
|
11
23
|
end
|
12
24
|
|
13
25
|
DIGEST = Digest::SHA256.new << GraphQL::VERSION
|
26
|
+
|
14
27
|
def fetch(filename)
|
15
28
|
hash = DIGEST.dup << filename
|
16
29
|
begin
|
@@ -52,7 +52,7 @@ module GraphQL
|
|
52
52
|
|
53
53
|
def build_object_type_node(object_type)
|
54
54
|
ints = @types.interfaces(object_type)
|
55
|
-
if ints.
|
55
|
+
if !ints.empty?
|
56
56
|
ints.sort_by!(&:graphql_name)
|
57
57
|
ints.map! { |iface| build_type_name_node(iface) }
|
58
58
|
end
|
@@ -247,7 +247,7 @@ module GraphQL
|
|
247
247
|
end
|
248
248
|
|
249
249
|
def build_argument_nodes(arguments)
|
250
|
-
if arguments.
|
250
|
+
if !arguments.empty?
|
251
251
|
nodes = arguments.map { |arg| build_argument_node(arg) }
|
252
252
|
nodes.sort_by!(&:name)
|
253
253
|
nodes
|
@@ -271,7 +271,7 @@ module GraphQL
|
|
271
271
|
all_types = @types.all_types
|
272
272
|
type_nodes = build_type_definition_nodes(all_types)
|
273
273
|
|
274
|
-
if (ex_t = schema.extra_types).
|
274
|
+
if !(ex_t = schema.extra_types).empty?
|
275
275
|
dummy_query = Class.new(GraphQL::Schema::Object) do
|
276
276
|
graphql_name "DummyQuery"
|
277
277
|
(all_types + ex_t).each_with_index do |type, idx|
|
@@ -346,10 +346,11 @@ module GraphQL
|
|
346
346
|
end
|
347
347
|
|
348
348
|
def definition_directives(member, directives_method)
|
349
|
-
|
349
|
+
if !member.respond_to?(directives_method) || member.directives.empty?
|
350
350
|
EmptyObjects::EMPTY_ARRAY
|
351
351
|
else
|
352
|
-
member.public_send(directives_method).
|
352
|
+
visible_directives = member.public_send(directives_method).select { |dir| @types.directive_exists?(dir.graphql_name) }
|
353
|
+
visible_directives.map! do |dir|
|
353
354
|
args = []
|
354
355
|
dir.arguments.argument_values.each_value do |arg_value| # rubocop:disable Development/ContextIsPassedCop -- directive instance method
|
355
356
|
arg_defn = arg_value.definition
|
@@ -373,9 +374,9 @@ module GraphQL
|
|
373
374
|
arguments: args
|
374
375
|
)
|
375
376
|
end
|
376
|
-
end
|
377
377
|
|
378
|
-
|
378
|
+
visible_directives
|
379
|
+
end
|
379
380
|
end
|
380
381
|
|
381
382
|
attr_reader :schema, :always_include_schema,
|
@@ -13,17 +13,21 @@ module GraphQL
|
|
13
13
|
@pos = nil
|
14
14
|
@max_tokens = max_tokens || Float::INFINITY
|
15
15
|
@tokens_count = 0
|
16
|
+
@finished = false
|
16
17
|
end
|
17
18
|
|
18
|
-
def
|
19
|
-
@
|
19
|
+
def finished?
|
20
|
+
@finished
|
20
21
|
end
|
21
22
|
|
22
23
|
attr_reader :pos, :tokens_count
|
23
24
|
|
24
25
|
def advance
|
25
26
|
@scanner.skip(IGNORE_REGEXP)
|
26
|
-
|
27
|
+
if @scanner.eos?
|
28
|
+
@finished = true
|
29
|
+
return false
|
30
|
+
end
|
27
31
|
@tokens_count += 1
|
28
32
|
if @tokens_count > @max_tokens
|
29
33
|
raise_parse_error("This query is too large to execute.")
|
@@ -72,7 +76,10 @@ module GraphQL
|
|
72
76
|
# Check for a matched decimal:
|
73
77
|
@scanner[1] ? :FLOAT : :INT
|
74
78
|
else
|
75
|
-
|
79
|
+
# Attempt to find the part after the `-`
|
80
|
+
value = @scanner.scan(/-\s?[a-z0-9]*/i)
|
81
|
+
invalid_byte_for_number_error_message = "Expected type 'number', but it was malformed#{value.nil? ? "" : ": #{value.inspect}"}."
|
82
|
+
raise_parse_error(invalid_byte_for_number_error_message)
|
76
83
|
end
|
77
84
|
when ByteFor::ELLIPSIS
|
78
85
|
if @string.getbyte(@pos + 1) != 46 || @string.getbyte(@pos + 2) != 46
|
@@ -141,6 +141,8 @@ module GraphQL
|
|
141
141
|
end
|
142
142
|
|
143
143
|
class << self
|
144
|
+
# rubocop:disable Development/NoEvalCop This eval takes static inputs at load-time
|
145
|
+
|
144
146
|
# Add a default `#visit_method` and `#children_method_name` using the class name
|
145
147
|
def inherited(child_class)
|
146
148
|
super
|
@@ -343,6 +345,7 @@ module GraphQL
|
|
343
345
|
RUBY
|
344
346
|
end
|
345
347
|
end
|
348
|
+
# rubocop:enable Development/NoEvalCop
|
346
349
|
end
|
347
350
|
end
|
348
351
|
|
@@ -110,7 +110,7 @@ module GraphQL
|
|
110
110
|
# Only ignored characters is not a valid document
|
111
111
|
raise GraphQL::ParseError.new("Unexpected end of document", nil, nil, @graphql_str)
|
112
112
|
end
|
113
|
-
while !@lexer.
|
113
|
+
while !@lexer.finished?
|
114
114
|
defns << definition
|
115
115
|
end
|
116
116
|
Document.new(pos: 0, definitions: defns, filename: @filename, source: self)
|
@@ -161,7 +161,7 @@ module GraphQL
|
|
161
161
|
expect_token(:VAR_SIGN)
|
162
162
|
var_name = parse_name
|
163
163
|
expect_token(:COLON)
|
164
|
-
var_type = self.type
|
164
|
+
var_type = self.type || raise_parse_error("Missing type definition for variable: $#{var_name}")
|
165
165
|
default_value = if at?(:EQUALS)
|
166
166
|
advance_token
|
167
167
|
value
|
@@ -92,7 +92,7 @@ module GraphQL
|
|
92
92
|
print_string("@")
|
93
93
|
print_string(directive.name)
|
94
94
|
|
95
|
-
if directive.arguments.
|
95
|
+
if !directive.arguments.empty?
|
96
96
|
print_string("(")
|
97
97
|
directive.arguments.each_with_index do |a, i|
|
98
98
|
print_argument(a)
|
@@ -117,7 +117,7 @@ module GraphQL
|
|
117
117
|
print_string(": ")
|
118
118
|
end
|
119
119
|
print_string(field.name)
|
120
|
-
if field.arguments.
|
120
|
+
if !field.arguments.empty?
|
121
121
|
print_string("(")
|
122
122
|
field.arguments.each_with_index do |a, i|
|
123
123
|
print_argument(a)
|
@@ -182,7 +182,7 @@ module GraphQL
|
|
182
182
|
print_string(operation_definition.name)
|
183
183
|
end
|
184
184
|
|
185
|
-
if operation_definition.variables.
|
185
|
+
if !operation_definition.variables.empty?
|
186
186
|
print_string("(")
|
187
187
|
operation_definition.variables.each_with_index do |v, i|
|
188
188
|
print_variable_definition(v)
|
@@ -230,7 +230,7 @@ module GraphQL
|
|
230
230
|
|
231
231
|
extension ? print_string("extend schema") : print_string("schema")
|
232
232
|
|
233
|
-
if schema.directives.
|
233
|
+
if !schema.directives.empty?
|
234
234
|
schema.directives.each do |dir|
|
235
235
|
print_string("\n ")
|
236
236
|
print_node(dir)
|
@@ -332,7 +332,7 @@ module GraphQL
|
|
332
332
|
extension ? print_string("extend ") : print_description_and_comment(interface_type)
|
333
333
|
print_string("interface ")
|
334
334
|
print_string(interface_type.name)
|
335
|
-
print_implements(interface_type) if interface_type.interfaces.
|
335
|
+
print_implements(interface_type) if !interface_type.interfaces.empty?
|
336
336
|
print_directives(interface_type.directives)
|
337
337
|
print_field_definitions(interface_type.fields)
|
338
338
|
end
|
@@ -342,7 +342,7 @@ module GraphQL
|
|
342
342
|
print_string("union ")
|
343
343
|
print_string(union_type.name)
|
344
344
|
print_directives(union_type.directives)
|
345
|
-
if union_type.types.
|
345
|
+
if !union_type.types.empty?
|
346
346
|
print_string(" = ")
|
347
347
|
i = 0
|
348
348
|
union_type.types.each do |t|
|
@@ -360,7 +360,7 @@ module GraphQL
|
|
360
360
|
print_string("enum ")
|
361
361
|
print_string(enum_type.name)
|
362
362
|
print_directives(enum_type.directives)
|
363
|
-
if enum_type.values.
|
363
|
+
if !enum_type.values.empty?
|
364
364
|
print_string(" {\n")
|
365
365
|
enum_type.values.each.with_index do |value, i|
|
366
366
|
print_description(value, indent: " ", first_in_block: i == 0)
|
@@ -401,7 +401,7 @@ module GraphQL
|
|
401
401
|
print_string("directive @")
|
402
402
|
print_string(directive.name)
|
403
403
|
|
404
|
-
if directive.arguments.
|
404
|
+
if !directive.arguments.empty?
|
405
405
|
print_arguments(directive.arguments)
|
406
406
|
end
|
407
407
|
|