graphql 2.0.32 → 2.5.22
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/generators/graphql/detailed_trace_generator.rb +77 -0
- data/lib/generators/graphql/install/mutation_root_generator.rb +2 -2
- data/lib/generators/graphql/install/templates/base_mutation.erb +2 -0
- data/lib/generators/graphql/install/templates/mutation_type.erb +2 -0
- data/lib/generators/graphql/install_generator.rb +49 -0
- data/lib/generators/graphql/orm_mutations_base.rb +1 -1
- data/lib/generators/graphql/templates/base_argument.erb +2 -0
- data/lib/generators/graphql/templates/base_connection.erb +2 -0
- data/lib/generators/graphql/templates/base_edge.erb +2 -0
- data/lib/generators/graphql/templates/base_enum.erb +2 -0
- data/lib/generators/graphql/templates/base_field.erb +2 -0
- data/lib/generators/graphql/templates/base_input_object.erb +2 -0
- data/lib/generators/graphql/templates/base_interface.erb +2 -0
- data/lib/generators/graphql/templates/base_object.erb +2 -0
- data/lib/generators/graphql/templates/base_resolver.erb +8 -0
- data/lib/generators/graphql/templates/base_scalar.erb +2 -0
- data/lib/generators/graphql/templates/base_union.erb +2 -0
- data/lib/generators/graphql/templates/create_graphql_detailed_traces.erb +10 -0
- data/lib/generators/graphql/templates/graphql_controller.erb +2 -0
- data/lib/generators/graphql/templates/loader.erb +2 -0
- data/lib/generators/graphql/templates/mutation.erb +2 -0
- data/lib/generators/graphql/templates/node_type.erb +2 -0
- data/lib/generators/graphql/templates/query_type.erb +2 -0
- data/lib/generators/graphql/templates/schema.erb +5 -0
- data/lib/generators/graphql/type_generator.rb +1 -1
- data/lib/graphql/analysis/analyzer.rb +90 -0
- data/lib/graphql/analysis/field_usage.rb +82 -0
- data/lib/graphql/analysis/max_query_complexity.rb +20 -0
- data/lib/graphql/analysis/max_query_depth.rb +20 -0
- data/lib/graphql/analysis/query_complexity.rb +263 -0
- data/lib/graphql/analysis/query_depth.rb +58 -0
- data/lib/graphql/analysis/visitor.rb +280 -0
- data/lib/graphql/analysis.rb +95 -1
- data/lib/graphql/autoload.rb +38 -0
- data/lib/graphql/backtrace/table.rb +118 -55
- data/lib/graphql/backtrace.rb +1 -19
- data/lib/graphql/coercion_error.rb +1 -9
- data/lib/graphql/current.rb +57 -0
- data/lib/graphql/dashboard/application_controller.rb +41 -0
- data/lib/graphql/dashboard/detailed_traces.rb +47 -0
- data/lib/graphql/dashboard/installable.rb +22 -0
- data/lib/graphql/dashboard/landings_controller.rb +9 -0
- data/lib/graphql/dashboard/limiters.rb +93 -0
- data/lib/graphql/dashboard/operation_store.rb +199 -0
- 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/charts.min.css +1 -0
- data/lib/graphql/dashboard/statics/dashboard.css +30 -0
- data/lib/graphql/dashboard/statics/dashboard.js +143 -0
- data/lib/graphql/dashboard/statics/header-icon.png +0 -0
- data/lib/graphql/dashboard/statics/icon.png +0 -0
- data/lib/graphql/dashboard/statics_controller.rb +31 -0
- data/lib/graphql/dashboard/subscriptions.rb +97 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/detailed_traces/traces/index.html.erb +45 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/landings/show.html.erb +18 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/limiters/limiters/show.html.erb +62 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/not_installed.html.erb +18 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/_form.html.erb +24 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/edit.html.erb +21 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/index.html.erb +69 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/new.html.erb +7 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/index_entries/index.html.erb +39 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/index_entries/show.html.erb +32 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/operations/index.html.erb +81 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/operations/show.html.erb +71 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/subscriptions/subscriptions/show.html.erb +41 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/subscriptions/topics/index.html.erb +55 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/subscriptions/topics/show.html.erb +40 -0
- data/lib/graphql/dashboard/views/layouts/graphql/dashboard/application.html.erb +108 -0
- data/lib/graphql/dashboard.rb +96 -0
- data/lib/graphql/dataloader/active_record_association_source.rb +84 -0
- data/lib/graphql/dataloader/active_record_source.rb +47 -0
- data/lib/graphql/dataloader/async_dataloader.rb +112 -0
- data/lib/graphql/dataloader/null_dataloader.rb +55 -10
- data/lib/graphql/dataloader/request.rb +5 -0
- data/lib/graphql/dataloader/source.rb +35 -12
- data/lib/graphql/dataloader.rb +224 -149
- data/lib/graphql/date_encoding_error.rb +1 -1
- data/lib/graphql/dig.rb +2 -1
- data/lib/graphql/duration_encoding_error.rb +16 -0
- data/lib/graphql/execution/interpreter/argument_value.rb +5 -1
- data/lib/graphql/execution/interpreter/arguments_cache.rb +5 -10
- data/lib/graphql/execution/interpreter/resolve.rb +23 -25
- data/lib/graphql/execution/interpreter/runtime/graphql_result.rb +228 -0
- data/lib/graphql/execution/interpreter/runtime.rb +363 -434
- data/lib/graphql/execution/interpreter.rb +91 -164
- data/lib/graphql/execution/lookahead.rb +105 -31
- data/lib/graphql/execution/multiplex.rb +7 -6
- data/lib/graphql/execution/next/field_resolve_step.rb +711 -0
- data/lib/graphql/execution/next/load_argument_step.rb +60 -0
- data/lib/graphql/execution/next/prepare_object_step.rb +129 -0
- data/lib/graphql/execution/next/runner.rb +389 -0
- data/lib/graphql/execution/next/selections_step.rb +37 -0
- data/lib/graphql/execution/next.rb +70 -0
- data/lib/graphql/execution.rb +1 -0
- data/lib/graphql/execution_error.rb +13 -10
- data/lib/graphql/introspection/directive_location_enum.rb +1 -1
- data/lib/graphql/introspection/directive_type.rb +7 -3
- data/lib/graphql/introspection/dynamic_fields.rb +5 -1
- data/lib/graphql/introspection/entry_points.rb +20 -6
- data/lib/graphql/introspection/enum_value_type.rb +5 -5
- data/lib/graphql/introspection/field_type.rb +13 -5
- data/lib/graphql/introspection/input_value_type.rb +21 -13
- data/lib/graphql/introspection/schema_type.rb +8 -11
- data/lib/graphql/introspection/type_type.rb +64 -28
- data/lib/graphql/invalid_name_error.rb +1 -1
- data/lib/graphql/invalid_null_error.rb +26 -17
- data/lib/graphql/language/block_string.rb +34 -18
- data/lib/graphql/language/cache.rb +13 -0
- data/lib/graphql/language/comment.rb +18 -0
- data/lib/graphql/language/definition_slice.rb +1 -1
- data/lib/graphql/language/document_from_schema_definition.rb +90 -61
- data/lib/graphql/language/lexer.rb +319 -193
- data/lib/graphql/language/nodes.rb +136 -77
- data/lib/graphql/language/parser.rb +807 -1985
- data/lib/graphql/language/printer.rb +324 -151
- data/lib/graphql/language/sanitized_printer.rb +21 -23
- data/lib/graphql/language/static_visitor.rb +171 -0
- data/lib/graphql/language/visitor.rb +23 -83
- data/lib/graphql/language.rb +71 -1
- data/lib/graphql/load_application_object_failed_error.rb +5 -1
- data/lib/graphql/pagination/array_connection.rb +6 -6
- data/lib/graphql/pagination/connection.rb +30 -1
- data/lib/graphql/pagination/connections.rb +32 -0
- data/lib/graphql/pagination/mongoid_relation_connection.rb +1 -2
- data/lib/graphql/query/context/scoped_context.rb +101 -0
- data/lib/graphql/query/context.rb +82 -144
- data/lib/graphql/query/null_context.rb +15 -18
- data/lib/graphql/query/partial.rb +179 -0
- data/lib/graphql/query/validation_pipeline.rb +4 -4
- data/lib/graphql/query/variable_validation_error.rb +1 -1
- data/lib/graphql/query/variables.rb +3 -3
- data/lib/graphql/query.rb +126 -81
- data/lib/graphql/railtie.rb +16 -6
- data/lib/graphql/rake_task.rb +3 -12
- data/lib/graphql/rubocop/graphql/base_cop.rb +1 -1
- data/lib/graphql/rubocop/graphql/field_type_in_block.rb +144 -0
- data/lib/graphql/rubocop/graphql/root_types_in_block.rb +38 -0
- data/lib/graphql/rubocop.rb +2 -0
- data/lib/graphql/schema/addition.rb +26 -13
- data/lib/graphql/schema/always_visible.rb +7 -2
- data/lib/graphql/schema/argument.rb +75 -9
- data/lib/graphql/schema/base_64_encoder.rb +3 -5
- data/lib/graphql/schema/build_from_definition.rb +123 -60
- data/lib/graphql/schema/directive/flagged.rb +4 -2
- data/lib/graphql/schema/directive/one_of.rb +12 -0
- data/lib/graphql/schema/directive/specified_by.rb +14 -0
- data/lib/graphql/schema/directive.rb +54 -2
- data/lib/graphql/schema/enum.rb +110 -27
- data/lib/graphql/schema/enum_value.rb +10 -2
- data/lib/graphql/schema/field/connection_extension.rb +15 -49
- data/lib/graphql/schema/field/scope_extension.rb +23 -7
- data/lib/graphql/schema/field.rb +245 -118
- data/lib/graphql/schema/field_extension.rb +34 -1
- data/lib/graphql/schema/has_single_input_argument.rb +160 -0
- data/lib/graphql/schema/input_object.rb +116 -60
- data/lib/graphql/schema/interface.rb +34 -16
- data/lib/graphql/schema/introspection_system.rb +8 -17
- data/lib/graphql/schema/late_bound_type.rb +4 -0
- data/lib/graphql/schema/list.rb +3 -3
- data/lib/graphql/schema/loader.rb +3 -4
- data/lib/graphql/schema/member/base_dsl_methods.rb +18 -2
- data/lib/graphql/schema/member/has_arguments.rb +132 -100
- data/lib/graphql/schema/member/has_authorization.rb +35 -0
- data/lib/graphql/schema/member/has_dataloader.rb +99 -0
- data/lib/graphql/schema/member/has_deprecation_reason.rb +15 -0
- data/lib/graphql/schema/member/has_directives.rb +4 -4
- data/lib/graphql/schema/member/has_fields.rb +115 -15
- data/lib/graphql/schema/member/has_interfaces.rb +26 -12
- data/lib/graphql/schema/member/has_unresolved_type_error.rb +5 -1
- data/lib/graphql/schema/member/has_validators.rb +1 -1
- data/lib/graphql/schema/member/relay_shortcuts.rb +1 -1
- data/lib/graphql/schema/member/scoped.rb +19 -0
- data/lib/graphql/schema/member/type_system_helpers.rb +17 -4
- data/lib/graphql/schema/member/validates_input.rb +3 -3
- data/lib/graphql/schema/member.rb +6 -0
- data/lib/graphql/schema/mutation.rb +7 -0
- data/lib/graphql/schema/object.rb +34 -8
- data/lib/graphql/schema/printer.rb +9 -7
- data/lib/graphql/schema/ractor_shareable.rb +79 -0
- data/lib/graphql/schema/relay_classic_mutation.rb +6 -129
- data/lib/graphql/schema/resolver.rb +90 -32
- data/lib/graphql/schema/scalar.rb +4 -9
- data/lib/graphql/schema/subscription.rb +63 -10
- data/lib/graphql/schema/timeout.rb +19 -2
- data/lib/graphql/schema/type_expression.rb +2 -2
- data/lib/graphql/schema/union.rb +2 -2
- data/lib/graphql/schema/unique_within_type.rb +1 -1
- data/lib/graphql/schema/validator/all_validator.rb +62 -0
- data/lib/graphql/schema/validator/required_validator.rb +92 -11
- data/lib/graphql/schema/validator.rb +3 -1
- data/lib/graphql/schema/visibility/migration.rb +188 -0
- data/lib/graphql/schema/visibility/profile.rb +445 -0
- data/lib/graphql/schema/visibility/visit.rb +190 -0
- data/lib/graphql/schema/visibility.rb +311 -0
- data/lib/graphql/schema/warden.rb +275 -103
- data/lib/graphql/schema.rb +950 -210
- data/lib/graphql/static_validation/all_rules.rb +3 -3
- data/lib/graphql/static_validation/base_visitor.rb +7 -6
- data/lib/graphql/static_validation/literal_validator.rb +6 -7
- data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +1 -1
- data/lib/graphql/static_validation/rules/argument_names_are_unique.rb +1 -1
- data/lib/graphql/static_validation/rules/arguments_are_defined.rb +3 -2
- data/lib/graphql/static_validation/rules/directives_are_defined.rb +3 -3
- data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +2 -0
- data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +12 -2
- data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +47 -13
- data/lib/graphql/static_validation/rules/fields_will_merge.rb +88 -25
- data/lib/graphql/static_validation/rules/fields_will_merge_error.rb +10 -2
- data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +3 -3
- data/lib/graphql/static_validation/rules/fragment_types_exist.rb +12 -2
- data/lib/graphql/static_validation/rules/fragments_are_on_composite_types.rb +1 -1
- data/lib/graphql/static_validation/rules/mutation_root_exists.rb +1 -1
- data/lib/graphql/static_validation/rules/no_definitions_are_present.rb +1 -1
- data/lib/graphql/static_validation/rules/not_single_subscription_error.rb +25 -0
- data/lib/graphql/static_validation/rules/query_root_exists.rb +1 -1
- data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +5 -5
- data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +5 -5
- data/lib/graphql/static_validation/rules/subscription_root_exists_and_single_subscription_selection.rb +26 -0
- data/lib/graphql/static_validation/rules/unique_directives_per_location.rb +7 -3
- data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +18 -27
- data/lib/graphql/static_validation/rules/variable_names_are_unique.rb +1 -1
- data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +2 -2
- data/lib/graphql/static_validation/rules/variables_are_input_types.rb +11 -2
- data/lib/graphql/static_validation/validation_context.rb +21 -5
- data/lib/graphql/static_validation/validator.rb +9 -1
- data/lib/graphql/static_validation.rb +0 -1
- data/lib/graphql/subscriptions/action_cable_subscriptions.rb +8 -5
- data/lib/graphql/subscriptions/broadcast_analyzer.rb +11 -5
- data/lib/graphql/subscriptions/default_subscription_resolve_extension.rb +12 -10
- data/lib/graphql/subscriptions/event.rb +21 -4
- data/lib/graphql/subscriptions/serialize.rb +3 -1
- data/lib/graphql/subscriptions.rb +21 -17
- data/lib/graphql/testing/helpers.rb +161 -0
- data/lib/graphql/testing/mock_action_cable.rb +111 -0
- data/lib/graphql/testing.rb +3 -0
- data/lib/graphql/tracing/active_support_notifications_trace.rb +14 -3
- data/lib/graphql/tracing/active_support_notifications_tracing.rb +1 -1
- data/lib/graphql/tracing/appoptics_trace.rb +7 -3
- data/lib/graphql/tracing/appoptics_tracing.rb +9 -2
- data/lib/graphql/tracing/appsignal_trace.rb +32 -59
- 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 +46 -162
- data/lib/graphql/tracing/data_dog_tracing.rb +2 -0
- data/lib/graphql/tracing/detailed_trace/active_record_backend.rb +74 -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 +156 -0
- data/lib/graphql/tracing/legacy_hooks_trace.rb +75 -0
- data/lib/graphql/tracing/legacy_trace.rb +4 -61
- data/lib/graphql/tracing/monitor_trace.rb +283 -0
- data/lib/graphql/tracing/new_relic_trace.rb +47 -54
- data/lib/graphql/tracing/new_relic_tracing.rb +2 -0
- data/lib/graphql/tracing/notifications_trace.rb +183 -37
- 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 +864 -0
- data/lib/graphql/tracing/platform_tracing.rb +3 -1
- data/lib/graphql/tracing/{prometheus_tracing → prometheus_trace}/graphql_collector.rb +5 -1
- data/lib/graphql/tracing/prometheus_trace.rb +73 -73
- data/lib/graphql/tracing/prometheus_tracing.rb +2 -0
- data/lib/graphql/tracing/scout_trace.rb +32 -58
- data/lib/graphql/tracing/scout_tracing.rb +2 -0
- data/lib/graphql/tracing/sentry_trace.rb +82 -0
- data/lib/graphql/tracing/statsd_trace.rb +33 -45
- data/lib/graphql/tracing/statsd_tracing.rb +2 -0
- data/lib/graphql/tracing/trace.rb +112 -1
- data/lib/graphql/tracing.rb +31 -28
- data/lib/graphql/type_kinds.rb +2 -1
- data/lib/graphql/types/iso_8601_duration.rb +77 -0
- data/lib/graphql/types/relay/connection_behaviors.rb +44 -2
- data/lib/graphql/types/relay/edge_behaviors.rb +18 -0
- data/lib/graphql/types/relay/has_node_field.rb +13 -8
- data/lib/graphql/types/relay/has_nodes_field.rb +13 -8
- data/lib/graphql/types/relay/node_behaviors.rb +13 -2
- data/lib/graphql/types/relay/page_info_behaviors.rb +4 -0
- data/lib/graphql/types.rb +18 -10
- data/lib/graphql/unauthorized_enum_value_error.rb +13 -0
- data/lib/graphql/unauthorized_error.rb +5 -1
- data/lib/graphql/version.rb +1 -1
- data/lib/graphql.rb +71 -54
- data/readme.md +12 -2
- metadata +233 -37
- data/lib/graphql/analysis/ast/analyzer.rb +0 -84
- data/lib/graphql/analysis/ast/field_usage.rb +0 -57
- data/lib/graphql/analysis/ast/max_query_complexity.rb +0 -22
- data/lib/graphql/analysis/ast/max_query_depth.rb +0 -22
- data/lib/graphql/analysis/ast/query_complexity.rb +0 -230
- data/lib/graphql/analysis/ast/query_depth.rb +0 -55
- data/lib/graphql/analysis/ast/visitor.rb +0 -276
- data/lib/graphql/analysis/ast.rb +0 -81
- data/lib/graphql/backtrace/inspect_result.rb +0 -50
- data/lib/graphql/backtrace/trace.rb +0 -96
- data/lib/graphql/backtrace/tracer.rb +0 -80
- data/lib/graphql/deprecation.rb +0 -9
- data/lib/graphql/filter.rb +0 -59
- data/lib/graphql/language/parser.y +0 -560
- data/lib/graphql/language/token.rb +0 -34
- data/lib/graphql/schema/base_64_bp.rb +0 -26
- data/lib/graphql/schema/invalid_type_error.rb +0 -7
- data/lib/graphql/schema/null_mask.rb +0 -11
- data/lib/graphql/static_validation/rules/subscription_root_exists.rb +0 -17
- data/lib/graphql/static_validation/type_stack.rb +0 -216
- data/lib/graphql/subscriptions/instrumentation.rb +0 -28
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
|
+
require "graphql/execution/interpreter/runtime/graphql_result"
|
|
2
3
|
|
|
3
4
|
module GraphQL
|
|
4
5
|
module Execution
|
|
@@ -10,176 +11,19 @@ module GraphQL
|
|
|
10
11
|
class Runtime
|
|
11
12
|
class CurrentState
|
|
12
13
|
def initialize
|
|
13
|
-
@current_object = nil
|
|
14
14
|
@current_field = nil
|
|
15
15
|
@current_arguments = nil
|
|
16
16
|
@current_result_name = nil
|
|
17
17
|
@current_result = nil
|
|
18
|
+
@was_authorized_by_scope_items = nil
|
|
18
19
|
end
|
|
19
20
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
module GraphQLResult
|
|
25
|
-
def initialize(result_name, parent_result, is_non_null_in_parent)
|
|
26
|
-
@graphql_parent = parent_result
|
|
27
|
-
if parent_result && parent_result.graphql_dead
|
|
28
|
-
@graphql_dead = true
|
|
29
|
-
end
|
|
30
|
-
@graphql_result_name = result_name
|
|
31
|
-
@graphql_is_non_null_in_parent = is_non_null_in_parent
|
|
32
|
-
# Jump through some hoops to avoid creating this duplicate storage if at all possible.
|
|
33
|
-
@graphql_metadata = nil
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
def path
|
|
37
|
-
@path ||= build_path([])
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
def build_path(path_array)
|
|
41
|
-
graphql_result_name && path_array.unshift(graphql_result_name)
|
|
42
|
-
@graphql_parent ? @graphql_parent.build_path(path_array) : path_array
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
attr_accessor :graphql_dead
|
|
46
|
-
attr_reader :graphql_parent, :graphql_result_name, :graphql_is_non_null_in_parent
|
|
47
|
-
|
|
48
|
-
# @return [Hash] Plain-Ruby result data (`@graphql_metadata` contains Result wrapper objects)
|
|
49
|
-
attr_accessor :graphql_result_data
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
class GraphQLResultHash
|
|
53
|
-
def initialize(_result_name, _parent_result, _is_non_null_in_parent)
|
|
54
|
-
super
|
|
55
|
-
@graphql_result_data = {}
|
|
21
|
+
def current_object
|
|
22
|
+
@current_result.graphql_application_value
|
|
56
23
|
end
|
|
57
24
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
attr_accessor :graphql_merged_into
|
|
61
|
-
|
|
62
|
-
def set_leaf(key, value)
|
|
63
|
-
# This is a hack.
|
|
64
|
-
# Basically, this object is merged into the root-level result at some point.
|
|
65
|
-
# But the problem is, some lazies are created whose closures retain reference to _this_
|
|
66
|
-
# object. When those lazies are resolved, they cause an update to this object.
|
|
67
|
-
#
|
|
68
|
-
# In order to return a proper top-level result, we have to update that top-level result object.
|
|
69
|
-
# In order to return a proper partial result (eg, for a directive), we have to update this object, too.
|
|
70
|
-
# Yowza.
|
|
71
|
-
if (t = @graphql_merged_into)
|
|
72
|
-
t.set_leaf(key, value)
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
@graphql_result_data[key] = value
|
|
76
|
-
# keep this up-to-date if it's been initialized
|
|
77
|
-
@graphql_metadata && @graphql_metadata[key] = value
|
|
78
|
-
|
|
79
|
-
value
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
def set_child_result(key, value)
|
|
83
|
-
if (t = @graphql_merged_into)
|
|
84
|
-
t.set_child_result(key, value)
|
|
85
|
-
end
|
|
86
|
-
@graphql_result_data[key] = value.graphql_result_data
|
|
87
|
-
# If we encounter some part of this response that requires metadata tracking,
|
|
88
|
-
# then create the metadata hash if necessary. It will be kept up-to-date after this.
|
|
89
|
-
(@graphql_metadata ||= @graphql_result_data.dup)[key] = value
|
|
90
|
-
value
|
|
91
|
-
end
|
|
92
|
-
|
|
93
|
-
def delete(key)
|
|
94
|
-
@graphql_metadata && @graphql_metadata.delete(key)
|
|
95
|
-
@graphql_result_data.delete(key)
|
|
96
|
-
end
|
|
97
|
-
|
|
98
|
-
def each
|
|
99
|
-
(@graphql_metadata || @graphql_result_data).each { |k, v| yield(k, v) }
|
|
100
|
-
end
|
|
101
|
-
|
|
102
|
-
def values
|
|
103
|
-
(@graphql_metadata || @graphql_result_data).values
|
|
104
|
-
end
|
|
105
|
-
|
|
106
|
-
def key?(k)
|
|
107
|
-
@graphql_result_data.key?(k)
|
|
108
|
-
end
|
|
109
|
-
|
|
110
|
-
def [](k)
|
|
111
|
-
(@graphql_metadata || @graphql_result_data)[k]
|
|
112
|
-
end
|
|
113
|
-
|
|
114
|
-
def merge_into(into_result)
|
|
115
|
-
self.each do |key, value|
|
|
116
|
-
case value
|
|
117
|
-
when GraphQLResultHash
|
|
118
|
-
next_into = into_result[key]
|
|
119
|
-
if next_into
|
|
120
|
-
value.merge_into(next_into)
|
|
121
|
-
else
|
|
122
|
-
into_result.set_child_result(key, value)
|
|
123
|
-
end
|
|
124
|
-
when GraphQLResultArray
|
|
125
|
-
# There's no special handling of arrays because currently, there's no way to split the execution
|
|
126
|
-
# of a list over several concurrent flows.
|
|
127
|
-
into_result.set_child_result(key, value)
|
|
128
|
-
else
|
|
129
|
-
# We have to assume that, since this passed the `fields_will_merge` selection,
|
|
130
|
-
# that the old and new values are the same.
|
|
131
|
-
into_result.set_leaf(key, value)
|
|
132
|
-
end
|
|
133
|
-
end
|
|
134
|
-
@graphql_merged_into = into_result
|
|
135
|
-
end
|
|
136
|
-
end
|
|
137
|
-
|
|
138
|
-
class GraphQLResultArray
|
|
139
|
-
include GraphQLResult
|
|
140
|
-
|
|
141
|
-
def initialize(_result_name, _parent_result, _is_non_null_in_parent)
|
|
142
|
-
super
|
|
143
|
-
@graphql_result_data = []
|
|
144
|
-
end
|
|
145
|
-
|
|
146
|
-
def graphql_skip_at(index)
|
|
147
|
-
# Mark this index as dead. It's tricky because some indices may already be storing
|
|
148
|
-
# `Lazy`s. So the runtime is still holding indexes _before_ skipping,
|
|
149
|
-
# this object has to coordinate incoming writes to account for any already-skipped indices.
|
|
150
|
-
@skip_indices ||= []
|
|
151
|
-
@skip_indices << index
|
|
152
|
-
offset_by = @skip_indices.count { |skipped_idx| skipped_idx < index}
|
|
153
|
-
delete_at_index = index - offset_by
|
|
154
|
-
@graphql_metadata && @graphql_metadata.delete_at(delete_at_index)
|
|
155
|
-
@graphql_result_data.delete_at(delete_at_index)
|
|
156
|
-
end
|
|
157
|
-
|
|
158
|
-
def set_leaf(idx, value)
|
|
159
|
-
if @skip_indices
|
|
160
|
-
offset_by = @skip_indices.count { |skipped_idx| skipped_idx < idx }
|
|
161
|
-
idx -= offset_by
|
|
162
|
-
end
|
|
163
|
-
@graphql_result_data[idx] = value
|
|
164
|
-
@graphql_metadata && @graphql_metadata[idx] = value
|
|
165
|
-
value
|
|
166
|
-
end
|
|
167
|
-
|
|
168
|
-
def set_child_result(idx, value)
|
|
169
|
-
if @skip_indices
|
|
170
|
-
offset_by = @skip_indices.count { |skipped_idx| skipped_idx < idx }
|
|
171
|
-
idx -= offset_by
|
|
172
|
-
end
|
|
173
|
-
@graphql_result_data[idx] = value.graphql_result_data
|
|
174
|
-
# If we encounter some part of this response that requires metadata tracking,
|
|
175
|
-
# then create the metadata hash if necessary. It will be kept up-to-date after this.
|
|
176
|
-
(@graphql_metadata ||= @graphql_result_data.dup)[idx] = value
|
|
177
|
-
value
|
|
178
|
-
end
|
|
179
|
-
|
|
180
|
-
def values
|
|
181
|
-
(@graphql_metadata || @graphql_result_data)
|
|
182
|
-
end
|
|
25
|
+
attr_accessor :current_result, :current_result_name,
|
|
26
|
+
:current_arguments, :current_field, :was_authorized_by_scope_items
|
|
183
27
|
end
|
|
184
28
|
|
|
185
29
|
# @return [GraphQL::Query]
|
|
@@ -191,14 +35,13 @@ module GraphQL
|
|
|
191
35
|
# @return [GraphQL::Query::Context]
|
|
192
36
|
attr_reader :context
|
|
193
37
|
|
|
194
|
-
def initialize(query
|
|
38
|
+
def initialize(query:)
|
|
195
39
|
@query = query
|
|
196
40
|
@current_trace = query.current_trace
|
|
197
41
|
@dataloader = query.multiplex.dataloader
|
|
198
|
-
@lazies_at_depth = lazies_at_depth
|
|
199
42
|
@schema = query.schema
|
|
200
43
|
@context = query.context
|
|
201
|
-
@response =
|
|
44
|
+
@response = nil
|
|
202
45
|
# Identify runtime directives by checking which of this schema's directives have overridden `def self.resolve`
|
|
203
46
|
@runtime_directive_names = []
|
|
204
47
|
noop_resolve_owner = GraphQL::Schema::Directive.singleton_class
|
|
@@ -208,98 +51,165 @@ module GraphQL
|
|
|
208
51
|
@runtime_directive_names << name
|
|
209
52
|
end
|
|
210
53
|
end
|
|
211
|
-
# A cache of { Class => { String => Schema::Field } }
|
|
212
|
-
# Which assumes that MyObject.get_field("myField") will return the same field
|
|
213
|
-
# during the lifetime of a query
|
|
214
|
-
@fields_cache = Hash.new { |h, k| h[k] = {} }
|
|
215
|
-
# this can by by-identity since owners are the same object, but not the sub-hash, which uses strings.
|
|
216
|
-
@fields_cache.compare_by_identity
|
|
217
54
|
# { Class => Boolean }
|
|
218
|
-
@lazy_cache = {}
|
|
219
|
-
@lazy_cache.compare_by_identity
|
|
55
|
+
@lazy_cache = {}.compare_by_identity
|
|
220
56
|
end
|
|
221
57
|
|
|
222
58
|
def final_result
|
|
223
|
-
@response
|
|
59
|
+
@response.respond_to?(:graphql_result_data) ? @response.graphql_result_data : @response
|
|
224
60
|
end
|
|
225
61
|
|
|
226
62
|
def inspect
|
|
227
63
|
"#<#{self.class.name} response=#{@response.inspect}>"
|
|
228
64
|
end
|
|
229
65
|
|
|
230
|
-
def tap_or_each(obj_or_array)
|
|
231
|
-
if obj_or_array.is_a?(Array)
|
|
232
|
-
obj_or_array.each do |item|
|
|
233
|
-
yield(item, true)
|
|
234
|
-
end
|
|
235
|
-
else
|
|
236
|
-
yield(obj_or_array, false)
|
|
237
|
-
end
|
|
238
|
-
end
|
|
239
|
-
|
|
240
|
-
# This _begins_ the execution. Some deferred work
|
|
241
|
-
# might be stored up in lazies.
|
|
242
66
|
# @return [void]
|
|
243
67
|
def run_eager
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
68
|
+
root_type = query.root_type
|
|
69
|
+
case query
|
|
70
|
+
when GraphQL::Query
|
|
71
|
+
ast_node = query.selected_operation
|
|
72
|
+
selections = ast_node.selections
|
|
73
|
+
object = query.root_value
|
|
74
|
+
is_eager = ast_node.operation_type == "mutation"
|
|
75
|
+
base_path = nil
|
|
76
|
+
when GraphQL::Query::Partial
|
|
77
|
+
ast_node = query.ast_nodes.first
|
|
78
|
+
selections = query.ast_nodes.map(&:selections).inject(&:+)
|
|
79
|
+
object = query.object
|
|
80
|
+
is_eager = false
|
|
81
|
+
base_path = query.path
|
|
256
82
|
else
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
selections.delete(:graphql_directives)
|
|
83
|
+
raise ArgumentError, "Unexpected Runnable, can't execute: #{query.class} (#{query.inspect})"
|
|
84
|
+
end
|
|
85
|
+
object = schema.sync_lazy(object) # TODO test query partial with lazy root object
|
|
86
|
+
runtime_state = get_current_runtime_state
|
|
87
|
+
case root_type.kind.name
|
|
88
|
+
when "OBJECT"
|
|
89
|
+
object_proxy = root_type.wrap(object, context)
|
|
90
|
+
object_proxy = schema.sync_lazy(object_proxy)
|
|
91
|
+
if object_proxy.nil?
|
|
92
|
+
@response = nil
|
|
93
|
+
else
|
|
94
|
+
@response = GraphQLResultHash.new(nil, root_type, object_proxy, nil, false, selections, is_eager, ast_node, nil, nil)
|
|
95
|
+
@response.base_path = base_path
|
|
96
|
+
runtime_state.current_result = @response
|
|
97
|
+
call_method_on_directives(:resolve, object, ast_node.directives) do
|
|
98
|
+
each_gathered_selections(@response) do |selections, is_selection_array, ordered_result_keys|
|
|
99
|
+
@response.ordered_result_keys ||= ordered_result_keys
|
|
100
|
+
if is_selection_array
|
|
101
|
+
selection_response = GraphQLResultHash.new(nil, root_type, object_proxy, nil, false, selections, is_eager, ast_node, nil, nil)
|
|
102
|
+
selection_response.ordered_result_keys = ordered_result_keys
|
|
103
|
+
final_response = @response
|
|
104
|
+
else
|
|
105
|
+
selection_response = @response
|
|
106
|
+
final_response = nil
|
|
282
107
|
end
|
|
283
|
-
|
|
108
|
+
|
|
109
|
+
@dataloader.append_job {
|
|
284
110
|
evaluate_selections(
|
|
285
|
-
runtime_object,
|
|
286
|
-
root_type,
|
|
287
|
-
root_op_type == "mutation",
|
|
288
111
|
selections,
|
|
289
112
|
selection_response,
|
|
290
113
|
final_response,
|
|
291
114
|
nil,
|
|
292
115
|
)
|
|
293
|
-
|
|
294
|
-
|
|
116
|
+
}
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
when "LIST"
|
|
121
|
+
inner_type = root_type.unwrap
|
|
122
|
+
case inner_type.kind.name
|
|
123
|
+
when "SCALAR", "ENUM"
|
|
124
|
+
result_name = ast_node.alias || ast_node.name
|
|
125
|
+
field_defn = query.field_definition
|
|
126
|
+
owner_type = field_defn.owner
|
|
127
|
+
selection_result = GraphQLResultHash.new(nil, owner_type, nil, nil, false, EmptyObjects::EMPTY_ARRAY, false, ast_node, nil, nil)
|
|
128
|
+
selection_result.base_path = base_path
|
|
129
|
+
selection_result.ordered_result_keys = [result_name]
|
|
130
|
+
runtime_state = get_current_runtime_state
|
|
131
|
+
runtime_state.current_result = selection_result
|
|
132
|
+
runtime_state.current_result_name = result_name
|
|
133
|
+
continue_value = continue_value(object, field_defn, false, ast_node, result_name, selection_result)
|
|
134
|
+
if HALT != continue_value
|
|
135
|
+
continue_field(continue_value, owner_type, field_defn, root_type, ast_node, nil, false, nil, nil, result_name, selection_result, false, runtime_state) # rubocop:disable Metrics/ParameterLists
|
|
136
|
+
end
|
|
137
|
+
@response = selection_result[result_name]
|
|
138
|
+
else
|
|
139
|
+
@response = GraphQLResultArray.new(nil, root_type, nil, nil, false, selections, false, ast_node, nil, nil)
|
|
140
|
+
@response.base_path = base_path
|
|
141
|
+
idx = nil
|
|
142
|
+
object.each do |inner_value|
|
|
143
|
+
idx ||= 0
|
|
144
|
+
this_idx = idx
|
|
145
|
+
idx += 1
|
|
146
|
+
@dataloader.append_job do
|
|
147
|
+
runtime_state.current_result_name = this_idx
|
|
148
|
+
runtime_state.current_result = @response
|
|
149
|
+
continue_field(
|
|
150
|
+
inner_value, root_type, nil, inner_type, nil, @response.graphql_selections, false, object_proxy,
|
|
151
|
+
nil, this_idx, @response, false, runtime_state
|
|
152
|
+
)
|
|
153
|
+
end
|
|
295
154
|
end
|
|
296
155
|
end
|
|
156
|
+
when "SCALAR", "ENUM"
|
|
157
|
+
result_name = ast_node.alias || ast_node.name
|
|
158
|
+
field_defn = query.field_definition
|
|
159
|
+
owner_type = field_defn.owner
|
|
160
|
+
selection_result = GraphQLResultHash.new(nil, owner_type, nil, nil, false, EmptyObjects::EMPTY_ARRAY, false, ast_node, nil, nil)
|
|
161
|
+
selection_result.ordered_result_keys = [result_name]
|
|
162
|
+
selection_result.base_path = base_path
|
|
163
|
+
runtime_state = get_current_runtime_state
|
|
164
|
+
runtime_state.current_result = selection_result
|
|
165
|
+
runtime_state.current_result_name = result_name
|
|
166
|
+
continue_value = continue_value(object, field_defn, false, ast_node, result_name, selection_result)
|
|
167
|
+
if HALT != continue_value
|
|
168
|
+
continue_field(continue_value, owner_type, field_defn, query.root_type, ast_node, nil, false, nil, nil, result_name, selection_result, false, runtime_state) # rubocop:disable Metrics/ParameterLists
|
|
169
|
+
end
|
|
170
|
+
@response = selection_result[result_name]
|
|
171
|
+
when "UNION", "INTERFACE"
|
|
172
|
+
resolved_type, _resolved_obj = resolve_type(root_type, object)
|
|
173
|
+
resolved_type = schema.sync_lazy(resolved_type)
|
|
174
|
+
object_proxy = resolved_type.wrap(object, context)
|
|
175
|
+
object_proxy = schema.sync_lazy(object_proxy)
|
|
176
|
+
@response = GraphQLResultHash.new(nil, resolved_type, object_proxy, nil, false, selections, false, query.ast_nodes.first, nil, nil)
|
|
177
|
+
@response.base_path = base_path
|
|
178
|
+
each_gathered_selections(@response) do |selections, is_selection_array, ordered_result_keys|
|
|
179
|
+
@response.ordered_result_keys ||= ordered_result_keys
|
|
180
|
+
if is_selection_array == true
|
|
181
|
+
raise "This isn't supported yet"
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
@dataloader.append_job {
|
|
185
|
+
evaluate_selections(
|
|
186
|
+
selections,
|
|
187
|
+
@response,
|
|
188
|
+
nil,
|
|
189
|
+
runtime_state,
|
|
190
|
+
)
|
|
191
|
+
}
|
|
192
|
+
end
|
|
193
|
+
else
|
|
194
|
+
raise "Invariant: unsupported type kind for partial execution: #{root_type.kind.inspect} (#{root_type})"
|
|
297
195
|
end
|
|
298
|
-
delete_all_interpreter_context
|
|
299
196
|
nil
|
|
300
197
|
end
|
|
301
198
|
|
|
302
|
-
def
|
|
199
|
+
def each_gathered_selections(response_hash)
|
|
200
|
+
ordered_result_keys = []
|
|
201
|
+
gathered_selections = gather_selections(response_hash.graphql_application_value, response_hash.graphql_result_type, response_hash.graphql_selections, nil, {}, ordered_result_keys)
|
|
202
|
+
ordered_result_keys.uniq!
|
|
203
|
+
if gathered_selections.is_a?(Array)
|
|
204
|
+
gathered_selections.each do |item|
|
|
205
|
+
yield(item, true, ordered_result_keys)
|
|
206
|
+
end
|
|
207
|
+
else
|
|
208
|
+
yield(gathered_selections, false, ordered_result_keys)
|
|
209
|
+
end
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
def gather_selections(owner_object, owner_type, selections, selections_to_run, selections_by_name, ordered_result_keys)
|
|
303
213
|
selections.each do |node|
|
|
304
214
|
# Skip gathering this if the directive says so
|
|
305
215
|
if !directives_include?(node, owner_object, owner_type)
|
|
@@ -308,10 +218,11 @@ module GraphQL
|
|
|
308
218
|
|
|
309
219
|
if node.is_a?(GraphQL::Language::Nodes::Field)
|
|
310
220
|
response_key = node.alias || node.name
|
|
221
|
+
ordered_result_keys << response_key
|
|
311
222
|
selections = selections_by_name[response_key]
|
|
312
223
|
# if there was already a selection of this field,
|
|
313
224
|
# use an array to hold all selections,
|
|
314
|
-
#
|
|
225
|
+
# otherwise, use the single node to represent the selection
|
|
315
226
|
if selections
|
|
316
227
|
# This field was already selected at least once,
|
|
317
228
|
# add this node to the list of selections
|
|
@@ -324,7 +235,7 @@ module GraphQL
|
|
|
324
235
|
end
|
|
325
236
|
else
|
|
326
237
|
# This is an InlineFragment or a FragmentSpread
|
|
327
|
-
if
|
|
238
|
+
if !@runtime_directive_names.empty? && node.directives.any? { |d| @runtime_directive_names.include?(d.name) }
|
|
328
239
|
next_selections = {}
|
|
329
240
|
next_selections[:graphql_directives] = node.directives
|
|
330
241
|
if selections_to_run
|
|
@@ -341,26 +252,26 @@ module GraphQL
|
|
|
341
252
|
case node
|
|
342
253
|
when GraphQL::Language::Nodes::InlineFragment
|
|
343
254
|
if node.type
|
|
344
|
-
type_defn =
|
|
255
|
+
type_defn = query.types.type(node.type.name)
|
|
345
256
|
|
|
346
|
-
if query.
|
|
347
|
-
result = gather_selections(owner_object, owner_type, node.selections, selections_to_run, next_selections)
|
|
257
|
+
if query.types.possible_types(type_defn).include?(owner_type)
|
|
258
|
+
result = gather_selections(owner_object, owner_type, node.selections, selections_to_run, next_selections, ordered_result_keys)
|
|
348
259
|
if !result.equal?(next_selections)
|
|
349
260
|
selections_to_run = result
|
|
350
261
|
end
|
|
351
262
|
end
|
|
352
263
|
else
|
|
353
264
|
# it's an untyped fragment, definitely continue
|
|
354
|
-
result = gather_selections(owner_object, owner_type, node.selections, selections_to_run, next_selections)
|
|
265
|
+
result = gather_selections(owner_object, owner_type, node.selections, selections_to_run, next_selections, ordered_result_keys)
|
|
355
266
|
if !result.equal?(next_selections)
|
|
356
267
|
selections_to_run = result
|
|
357
268
|
end
|
|
358
269
|
end
|
|
359
270
|
when GraphQL::Language::Nodes::FragmentSpread
|
|
360
271
|
fragment_def = query.fragments[node.name]
|
|
361
|
-
type_defn = query.
|
|
362
|
-
if query.
|
|
363
|
-
result = gather_selections(owner_object, owner_type, fragment_def.selections, selections_to_run, next_selections)
|
|
272
|
+
type_defn = query.types.type(fragment_def.type.name)
|
|
273
|
+
if query.types.possible_types(type_defn).include?(owner_type)
|
|
274
|
+
result = gather_selections(owner_object, owner_type, fragment_def.selections, selections_to_run, next_selections, ordered_result_keys)
|
|
364
275
|
if !result.equal?(next_selections)
|
|
365
276
|
selections_to_run = result
|
|
366
277
|
end
|
|
@@ -376,38 +287,46 @@ module GraphQL
|
|
|
376
287
|
NO_ARGS = GraphQL::EmptyObjects::EMPTY_HASH
|
|
377
288
|
|
|
378
289
|
# @return [void]
|
|
379
|
-
def evaluate_selections(
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
if
|
|
394
|
-
|
|
290
|
+
def evaluate_selections(gathered_selections, selections_result, target_result, runtime_state) # rubocop:disable Metrics/ParameterLists
|
|
291
|
+
runtime_state ||= get_current_runtime_state
|
|
292
|
+
runtime_state.current_result_name = nil
|
|
293
|
+
runtime_state.current_result = selections_result
|
|
294
|
+
# This is a less-frequent case; use a fast check since it's often not there.
|
|
295
|
+
if (directives = gathered_selections[:graphql_directives])
|
|
296
|
+
gathered_selections.delete(:graphql_directives)
|
|
297
|
+
end
|
|
298
|
+
|
|
299
|
+
call_method_on_directives(:resolve, selections_result.graphql_application_value, directives) do
|
|
300
|
+
gathered_selections.each do |result_name, field_ast_nodes_or_ast_node|
|
|
301
|
+
# Field resolution may pause the fiber,
|
|
302
|
+
# so it wouldn't get to the `Resolve` call that happens below.
|
|
303
|
+
# So instead trigger a run from this outer context.
|
|
304
|
+
if selections_result.graphql_is_eager
|
|
305
|
+
@dataloader.clear_cache
|
|
306
|
+
@dataloader.run_isolated {
|
|
307
|
+
evaluate_selection(
|
|
308
|
+
result_name, field_ast_nodes_or_ast_node, selections_result
|
|
309
|
+
)
|
|
310
|
+
@dataloader.clear_cache
|
|
311
|
+
}
|
|
312
|
+
else
|
|
313
|
+
@dataloader.append_job {
|
|
314
|
+
evaluate_selection(
|
|
315
|
+
result_name, field_ast_nodes_or_ast_node, selections_result
|
|
316
|
+
)
|
|
317
|
+
}
|
|
395
318
|
end
|
|
396
|
-
}
|
|
397
|
-
# Field resolution may pause the fiber,
|
|
398
|
-
# so it wouldn't get to the `Resolve` call that happens below.
|
|
399
|
-
# So instead trigger a run from this outer context.
|
|
400
|
-
if is_eager_selection
|
|
401
|
-
@dataloader.run
|
|
402
319
|
end
|
|
320
|
+
if target_result
|
|
321
|
+
selections_result.merge_into(target_result)
|
|
322
|
+
end
|
|
323
|
+
selections_result
|
|
403
324
|
end
|
|
404
|
-
|
|
405
|
-
selections_result
|
|
406
325
|
end
|
|
407
326
|
|
|
408
327
|
# @return [void]
|
|
409
|
-
def evaluate_selection(result_name, field_ast_nodes_or_ast_node,
|
|
410
|
-
return if
|
|
328
|
+
def evaluate_selection(result_name, field_ast_nodes_or_ast_node, selections_result) # rubocop:disable Metrics/ParameterLists
|
|
329
|
+
return if selections_result.graphql_dead
|
|
411
330
|
# As a performance optimization, the hash key will be a `Node` if
|
|
412
331
|
# there's only one selection of the field. But if there are multiple
|
|
413
332
|
# selections of the field, it will be an Array of nodes
|
|
@@ -419,59 +338,48 @@ module GraphQL
|
|
|
419
338
|
ast_node = field_ast_nodes_or_ast_node
|
|
420
339
|
end
|
|
421
340
|
field_name = ast_node.name
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
field_defn = @fields_cache[owner_type][field_name] ||= owner_type.get_field(field_name, @context)
|
|
425
|
-
is_introspection = false
|
|
426
|
-
if field_defn.nil?
|
|
427
|
-
field_defn = if owner_type == schema.query && (entry_point_field = schema.introspection_system.entry_point(name: field_name))
|
|
428
|
-
is_introspection = true
|
|
429
|
-
entry_point_field
|
|
430
|
-
elsif (dynamic_field = schema.introspection_system.dynamic_field(name: field_name))
|
|
431
|
-
is_introspection = true
|
|
432
|
-
dynamic_field
|
|
433
|
-
else
|
|
434
|
-
raise "Invariant: no field for #{owner_type}.#{field_name}"
|
|
435
|
-
end
|
|
436
|
-
end
|
|
437
|
-
|
|
438
|
-
return_type = field_defn.type
|
|
341
|
+
owner_type = selections_result.graphql_result_type
|
|
342
|
+
field_defn = query.types.field(owner_type, field_name)
|
|
439
343
|
|
|
440
|
-
# This seems janky, but we need to know
|
|
441
|
-
# the field's return type at this path in order
|
|
442
|
-
# to propagate `null`
|
|
443
|
-
return_type_non_null = return_type.non_null?
|
|
444
344
|
# Set this before calling `run_with_directives`, so that the directive can have the latest path
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
345
|
+
runtime_state = get_current_runtime_state
|
|
346
|
+
runtime_state.current_field = field_defn
|
|
347
|
+
runtime_state.current_result = selections_result
|
|
348
|
+
runtime_state.current_result_name = result_name
|
|
449
349
|
|
|
450
|
-
|
|
350
|
+
owner_object = selections_result.graphql_application_value
|
|
351
|
+
if field_defn.dynamic_introspection
|
|
451
352
|
owner_object = field_defn.owner.wrap(owner_object, context)
|
|
452
353
|
end
|
|
453
354
|
|
|
454
|
-
|
|
455
|
-
if total_args_count == 0
|
|
355
|
+
if !field_defn.any_arguments?
|
|
456
356
|
resolved_arguments = GraphQL::Execution::Interpreter::Arguments::EMPTY
|
|
457
357
|
if field_defn.extras.size == 0
|
|
458
358
|
evaluate_selection_with_resolved_keyword_args(
|
|
459
|
-
NO_ARGS, resolved_arguments, field_defn, ast_node, field_ast_nodes,
|
|
359
|
+
NO_ARGS, resolved_arguments, field_defn, ast_node, field_ast_nodes, owner_object, result_name, selections_result, runtime_state
|
|
460
360
|
)
|
|
461
361
|
else
|
|
462
|
-
evaluate_selection_with_args(resolved_arguments, field_defn, ast_node, field_ast_nodes,
|
|
362
|
+
evaluate_selection_with_args(resolved_arguments, field_defn, ast_node, field_ast_nodes, owner_object, result_name, selections_result, runtime_state)
|
|
463
363
|
end
|
|
464
364
|
else
|
|
465
365
|
@query.arguments_cache.dataload_for(ast_node, field_defn, owner_object) do |resolved_arguments|
|
|
466
|
-
|
|
366
|
+
runtime_state = get_current_runtime_state # This might be in a different fiber
|
|
367
|
+
runtime_state.current_field = field_defn
|
|
368
|
+
runtime_state.current_arguments = resolved_arguments
|
|
369
|
+
runtime_state.current_result_name = result_name
|
|
370
|
+
runtime_state.current_result = selections_result
|
|
371
|
+
evaluate_selection_with_args(resolved_arguments, field_defn, ast_node, field_ast_nodes, owner_object, result_name, selections_result, runtime_state)
|
|
467
372
|
end
|
|
468
373
|
end
|
|
469
374
|
end
|
|
470
375
|
|
|
471
|
-
def evaluate_selection_with_args(arguments, field_defn, ast_node, field_ast_nodes,
|
|
472
|
-
after_lazy(arguments, field: field_defn, ast_node: ast_node, owner_object: object, arguments: arguments, result_name: result_name, result: selection_result) do |resolved_arguments|
|
|
376
|
+
def evaluate_selection_with_args(arguments, field_defn, ast_node, field_ast_nodes, object, result_name, selection_result, runtime_state) # rubocop:disable Metrics/ParameterLists
|
|
377
|
+
after_lazy(arguments, field: field_defn, ast_node: ast_node, owner_object: object, arguments: arguments, result_name: result_name, result: selection_result, runtime_state: runtime_state) do |resolved_arguments, runtime_state|
|
|
473
378
|
if resolved_arguments.is_a?(GraphQL::ExecutionError) || resolved_arguments.is_a?(GraphQL::UnauthorizedError)
|
|
474
|
-
|
|
379
|
+
next if selection_result.collect_result(result_name, resolved_arguments)
|
|
380
|
+
|
|
381
|
+
return_type_non_null = field_defn.type.non_null?
|
|
382
|
+
continue_value(resolved_arguments, field_defn, return_type_non_null, ast_node, result_name, selection_result)
|
|
475
383
|
next
|
|
476
384
|
end
|
|
477
385
|
|
|
@@ -509,28 +417,27 @@ module GraphQL
|
|
|
509
417
|
# to the keyword args hash _before_ freezing everything.
|
|
510
418
|
extra_args[:argument_details] = :__arguments_add_self
|
|
511
419
|
when :parent
|
|
512
|
-
|
|
420
|
+
parent_result = selection_result.graphql_parent
|
|
421
|
+
extra_args[:parent] = parent_result&.graphql_application_value&.object
|
|
513
422
|
else
|
|
514
423
|
extra_args[extra] = field_defn.fetch_extra(extra, context)
|
|
515
424
|
end
|
|
516
425
|
end
|
|
517
|
-
if extra_args.
|
|
426
|
+
if !extra_args.empty?
|
|
518
427
|
resolved_arguments = resolved_arguments.merge_extras(extra_args)
|
|
519
428
|
end
|
|
520
429
|
resolved_arguments.keyword_arguments
|
|
521
430
|
end
|
|
522
431
|
|
|
523
|
-
evaluate_selection_with_resolved_keyword_args(kwarg_arguments, resolved_arguments, field_defn, ast_node, field_ast_nodes,
|
|
432
|
+
evaluate_selection_with_resolved_keyword_args(kwarg_arguments, resolved_arguments, field_defn, ast_node, field_ast_nodes, object, result_name, selection_result, runtime_state)
|
|
524
433
|
end
|
|
525
434
|
end
|
|
526
435
|
|
|
527
|
-
def evaluate_selection_with_resolved_keyword_args(kwarg_arguments, resolved_arguments, field_defn, ast_node, field_ast_nodes,
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
st.current_result_name = result_name
|
|
533
|
-
st.current_result = selection_result
|
|
436
|
+
def evaluate_selection_with_resolved_keyword_args(kwarg_arguments, resolved_arguments, field_defn, ast_node, field_ast_nodes, object, result_name, selection_result, runtime_state) # rubocop:disable Metrics/ParameterLists
|
|
437
|
+
runtime_state.current_field = field_defn
|
|
438
|
+
runtime_state.current_arguments = resolved_arguments
|
|
439
|
+
runtime_state.current_result_name = result_name
|
|
440
|
+
runtime_state.current_result = selection_result
|
|
534
441
|
# Optimize for the case that field is selected only once
|
|
535
442
|
if field_ast_nodes.nil? || field_ast_nodes.size == 1
|
|
536
443
|
next_selections = ast_node.selections
|
|
@@ -544,9 +451,18 @@ module GraphQL
|
|
|
544
451
|
}
|
|
545
452
|
end
|
|
546
453
|
|
|
547
|
-
|
|
454
|
+
call_method_on_directives(:resolve, object, directives) do
|
|
455
|
+
if !directives.empty?
|
|
456
|
+
# This might be executed in a different context; reset this info
|
|
457
|
+
runtime_state = get_current_runtime_state
|
|
458
|
+
runtime_state.current_field = field_defn
|
|
459
|
+
runtime_state.current_arguments = resolved_arguments
|
|
460
|
+
runtime_state.current_result_name = result_name
|
|
461
|
+
runtime_state.current_result = selection_result
|
|
462
|
+
end
|
|
548
463
|
# Actually call the field resolver and capture the result
|
|
549
464
|
app_result = begin
|
|
465
|
+
@current_trace.begin_execute_field(field_defn, object, kwarg_arguments, query)
|
|
550
466
|
@current_trace.execute_field(field: field_defn, ast_node: ast_node, query: query, object: object, arguments: kwarg_arguments) do
|
|
551
467
|
field_defn.resolve(object, kwarg_arguments, context)
|
|
552
468
|
end
|
|
@@ -559,32 +475,32 @@ module GraphQL
|
|
|
559
475
|
ex_err
|
|
560
476
|
end
|
|
561
477
|
end
|
|
562
|
-
|
|
563
|
-
|
|
478
|
+
@current_trace.end_execute_field(field_defn, object, kwarg_arguments, query, app_result)
|
|
479
|
+
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|
|
|
480
|
+
next if selection_result.collect_result(result_name, inner_result)
|
|
481
|
+
|
|
482
|
+
owner_type = selection_result.graphql_result_type
|
|
483
|
+
return_type = field_defn.type
|
|
484
|
+
continue_value = continue_value(inner_result, field_defn, return_type.non_null?, ast_node, result_name, selection_result)
|
|
564
485
|
if HALT != continue_value
|
|
565
|
-
|
|
486
|
+
was_scoped = runtime_state.was_authorized_by_scope_items
|
|
487
|
+
runtime_state.was_authorized_by_scope_items = nil
|
|
488
|
+
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)
|
|
489
|
+
else
|
|
490
|
+
nil
|
|
566
491
|
end
|
|
567
492
|
end
|
|
568
493
|
end
|
|
569
|
-
|
|
570
494
|
# If this field is a root mutation field, immediately resolve
|
|
571
495
|
# all of its child fields before moving on to the next root mutation field.
|
|
572
496
|
# (Subselections of this mutation will still be resolved level-by-level.)
|
|
573
|
-
if
|
|
574
|
-
|
|
575
|
-
else
|
|
576
|
-
# Return this from `after_lazy` because it might be another lazy that needs to be resolved
|
|
577
|
-
field_result
|
|
497
|
+
if selection_result.graphql_is_eager
|
|
498
|
+
@dataloader.run
|
|
578
499
|
end
|
|
579
500
|
end
|
|
580
501
|
|
|
581
|
-
|
|
582
|
-
def dead_result?(selection_result)
|
|
583
|
-
selection_result.graphql_dead # || ((parent = selection_result.graphql_parent) && parent.graphql_dead)
|
|
584
|
-
end
|
|
585
|
-
|
|
586
502
|
def set_result(selection_result, result_name, value, is_child_result, is_non_null)
|
|
587
|
-
if !
|
|
503
|
+
if !selection_result.graphql_dead
|
|
588
504
|
if value.nil? && is_non_null
|
|
589
505
|
# This is an invalid nil that should be propagated
|
|
590
506
|
# One caller of this method passes a block,
|
|
@@ -637,14 +553,17 @@ module GraphQL
|
|
|
637
553
|
path
|
|
638
554
|
end
|
|
639
555
|
|
|
640
|
-
HALT = Object.new
|
|
641
|
-
def continue_value(value,
|
|
556
|
+
HALT = Object.new.freeze
|
|
557
|
+
def continue_value(value, field, is_non_null, ast_node, result_name, selection_result) # rubocop:disable Metrics/ParameterLists
|
|
642
558
|
case value
|
|
643
559
|
when nil
|
|
644
560
|
if is_non_null
|
|
645
561
|
set_result(selection_result, result_name, nil, false, is_non_null) do
|
|
562
|
+
# When this comes from a list item, use the parent object:
|
|
563
|
+
is_from_array = selection_result.is_a?(GraphQLResultArray)
|
|
564
|
+
parent_type = is_from_array ? selection_result.graphql_parent.graphql_result_type : selection_result.graphql_result_type
|
|
646
565
|
# This block is called if `result_name` is not dead. (Maybe a previous invalid nil caused it be marked dead.)
|
|
647
|
-
err = parent_type::InvalidNullError.new(parent_type, field,
|
|
566
|
+
err = parent_type::InvalidNullError.new(parent_type, field, ast_node, is_from_array: is_from_array)
|
|
648
567
|
schema.type_error(err, context)
|
|
649
568
|
end
|
|
650
569
|
else
|
|
@@ -656,7 +575,7 @@ module GraphQL
|
|
|
656
575
|
# to avoid the overhead of checking three different classes
|
|
657
576
|
# every time.
|
|
658
577
|
if value.is_a?(GraphQL::ExecutionError)
|
|
659
|
-
if selection_result.nil? || !
|
|
578
|
+
if selection_result.nil? || !selection_result.graphql_dead
|
|
660
579
|
value.path ||= current_path
|
|
661
580
|
value.ast_node ||= ast_node
|
|
662
581
|
context.errors << value
|
|
@@ -674,7 +593,7 @@ module GraphQL
|
|
|
674
593
|
rescue GraphQL::ExecutionError => err
|
|
675
594
|
err
|
|
676
595
|
end
|
|
677
|
-
continue_value(next_value,
|
|
596
|
+
continue_value(next_value, field, is_non_null, ast_node, result_name, selection_result)
|
|
678
597
|
elsif value.is_a?(GraphQL::UnauthorizedError)
|
|
679
598
|
# this hook might raise & crash, or it might return
|
|
680
599
|
# a replacement value
|
|
@@ -683,7 +602,7 @@ module GraphQL
|
|
|
683
602
|
rescue GraphQL::ExecutionError => err
|
|
684
603
|
err
|
|
685
604
|
end
|
|
686
|
-
continue_value(next_value,
|
|
605
|
+
continue_value(next_value, field, is_non_null, ast_node, result_name, selection_result)
|
|
687
606
|
elsif GraphQL::Execution::SKIP == value
|
|
688
607
|
# It's possible a lazy was already written here
|
|
689
608
|
case selection_result
|
|
@@ -704,9 +623,9 @@ module GraphQL
|
|
|
704
623
|
end
|
|
705
624
|
when Array
|
|
706
625
|
# It's an array full of execution errors; add them all.
|
|
707
|
-
if value.
|
|
626
|
+
if !value.empty? && value.all?(GraphQL::ExecutionError)
|
|
708
627
|
list_type_at_all = (field && (field.type.list?))
|
|
709
|
-
if selection_result.nil? || !
|
|
628
|
+
if selection_result.nil? || !selection_result.graphql_dead
|
|
710
629
|
value.each_with_index do |error, index|
|
|
711
630
|
error.ast_node ||= ast_node
|
|
712
631
|
error.path ||= current_path + (list_type_at_all ? [index] : [])
|
|
@@ -742,7 +661,7 @@ module GraphQL
|
|
|
742
661
|
# Location information from `path` and `ast_node`.
|
|
743
662
|
#
|
|
744
663
|
# @return [Lazy, Array, Hash, Object] Lazy, Array, and Hash are all traversed to resolve lazy values later
|
|
745
|
-
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
|
|
664
|
+
def continue_field(value, owner_type, field, current_type, ast_node, next_selections, is_non_null, owner_object, arguments, result_name, selection_result, was_scoped, runtime_state) # rubocop:disable Metrics/ParameterLists
|
|
746
665
|
if current_type.non_null?
|
|
747
666
|
current_type = current_type.of_type
|
|
748
667
|
is_non_null = true
|
|
@@ -752,14 +671,30 @@ module GraphQL
|
|
|
752
671
|
when "SCALAR", "ENUM"
|
|
753
672
|
r = begin
|
|
754
673
|
current_type.coerce_result(value, context)
|
|
674
|
+
rescue GraphQL::ExecutionError => ex_err
|
|
675
|
+
return continue_value(ex_err, field, is_non_null, ast_node, result_name, selection_result)
|
|
755
676
|
rescue StandardError => err
|
|
756
|
-
|
|
677
|
+
begin
|
|
678
|
+
query.handle_or_reraise(err)
|
|
679
|
+
rescue GraphQL::ExecutionError => ex_err
|
|
680
|
+
return continue_value(ex_err, field, is_non_null, ast_node, result_name, selection_result)
|
|
681
|
+
end
|
|
757
682
|
end
|
|
758
683
|
set_result(selection_result, result_name, r, false, is_non_null)
|
|
759
684
|
r
|
|
760
685
|
when "UNION", "INTERFACE"
|
|
761
|
-
resolved_type_or_lazy =
|
|
762
|
-
|
|
686
|
+
resolved_type_or_lazy = begin
|
|
687
|
+
resolve_type(current_type, value)
|
|
688
|
+
rescue GraphQL::ExecutionError, GraphQL::UnauthorizedError => ex_err
|
|
689
|
+
return continue_value(ex_err, field, is_non_null, ast_node, result_name, selection_result)
|
|
690
|
+
rescue StandardError => err
|
|
691
|
+
begin
|
|
692
|
+
query.handle_or_reraise(err)
|
|
693
|
+
rescue GraphQL::ExecutionError => ex_err
|
|
694
|
+
return continue_value(ex_err, field, is_non_null, ast_node, result_name, selection_result)
|
|
695
|
+
end
|
|
696
|
+
end
|
|
697
|
+
after_lazy(resolved_type_or_lazy, 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 |resolved_type_result, runtime_state|
|
|
763
698
|
if resolved_type_result.is_a?(Array) && resolved_type_result.length == 2
|
|
764
699
|
resolved_type, resolved_value = resolved_type_result
|
|
765
700
|
else
|
|
@@ -767,7 +702,7 @@ module GraphQL
|
|
|
767
702
|
resolved_value = value
|
|
768
703
|
end
|
|
769
704
|
|
|
770
|
-
possible_types = query.possible_types(current_type)
|
|
705
|
+
possible_types = query.types.possible_types(current_type)
|
|
771
706
|
if !possible_types.include?(resolved_type)
|
|
772
707
|
parent_type = field.owner_type
|
|
773
708
|
err_class = current_type::UnresolvedTypeError
|
|
@@ -776,60 +711,37 @@ module GraphQL
|
|
|
776
711
|
set_result(selection_result, result_name, nil, false, is_non_null)
|
|
777
712
|
nil
|
|
778
713
|
else
|
|
779
|
-
continue_field(resolved_value, owner_type, field, resolved_type, ast_node, next_selections, is_non_null, owner_object, arguments, result_name, selection_result)
|
|
714
|
+
continue_field(resolved_value, owner_type, field, resolved_type, ast_node, next_selections, is_non_null, owner_object, arguments, result_name, selection_result, was_scoped, runtime_state)
|
|
780
715
|
end
|
|
781
716
|
end
|
|
782
717
|
when "OBJECT"
|
|
783
718
|
object_proxy = begin
|
|
784
|
-
current_type.wrap(value, context)
|
|
719
|
+
was_scoped ? current_type.wrap_scoped(value, context) : current_type.wrap(value, context)
|
|
785
720
|
rescue GraphQL::ExecutionError => err
|
|
786
721
|
err
|
|
787
722
|
end
|
|
788
|
-
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) do |inner_object|
|
|
789
|
-
continue_value = continue_value(inner_object,
|
|
723
|
+
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|
|
|
724
|
+
continue_value = continue_value(inner_object, field, is_non_null, ast_node, result_name, selection_result)
|
|
790
725
|
if HALT != continue_value
|
|
791
|
-
response_hash = GraphQLResultHash.new(result_name, selection_result, is_non_null)
|
|
726
|
+
response_hash = GraphQLResultHash.new(result_name, current_type, continue_value, selection_result, is_non_null, next_selections, false, ast_node, arguments, field)
|
|
792
727
|
set_result(selection_result, result_name, response_hash, true, is_non_null)
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
# 1. All selections of this object should be evaluated together (there are no runtime directives modifying execution).
|
|
796
|
-
# This case is handled below, and the result can be written right into the main `response_hash` above.
|
|
797
|
-
# In this case, `gathered_selections` is a hash of selections.
|
|
798
|
-
# 2. Some selections of this object have runtime directives that may or may not modify execution.
|
|
799
|
-
# That part of the selection is evaluated in an isolated way, writing into a sub-response object which is
|
|
800
|
-
# eventually merged into the final response. In this case, `gathered_selections` is an array of things to run in isolation.
|
|
801
|
-
# (Technically, it's possible that one of those entries _doesn't_ require isolation.)
|
|
802
|
-
tap_or_each(gathered_selections) do |selections, is_selection_array|
|
|
728
|
+
each_gathered_selections(response_hash) do |selections, is_selection_array, ordered_result_keys|
|
|
729
|
+
response_hash.ordered_result_keys ||= ordered_result_keys
|
|
803
730
|
if is_selection_array
|
|
804
|
-
this_result = GraphQLResultHash.new(result_name, selection_result, is_non_null)
|
|
731
|
+
this_result = GraphQLResultHash.new(result_name, current_type, continue_value, selection_result, is_non_null, selections, false, ast_node, arguments, field)
|
|
732
|
+
this_result.ordered_result_keys = ordered_result_keys
|
|
805
733
|
final_result = response_hash
|
|
806
734
|
else
|
|
807
735
|
this_result = response_hash
|
|
808
736
|
final_result = nil
|
|
809
737
|
end
|
|
810
|
-
# reset this mutable state
|
|
811
|
-
# Unset `result_name` here because it's already included in the new response hash
|
|
812
|
-
st = get_current_runtime_state
|
|
813
|
-
st.current_object = continue_value
|
|
814
|
-
st.current_result_name = nil
|
|
815
|
-
st.current_result = this_result
|
|
816
738
|
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
continue_value,
|
|
824
|
-
current_type,
|
|
825
|
-
false,
|
|
826
|
-
selections,
|
|
827
|
-
this_result,
|
|
828
|
-
final_result,
|
|
829
|
-
owner_object.object,
|
|
830
|
-
)
|
|
831
|
-
this_result
|
|
832
|
-
end
|
|
739
|
+
evaluate_selections(
|
|
740
|
+
selections,
|
|
741
|
+
this_result,
|
|
742
|
+
final_result,
|
|
743
|
+
runtime_state,
|
|
744
|
+
)
|
|
833
745
|
end
|
|
834
746
|
end
|
|
835
747
|
end
|
|
@@ -838,35 +750,43 @@ module GraphQL
|
|
|
838
750
|
# This is true for objects, unions, and interfaces
|
|
839
751
|
use_dataloader_job = !inner_type.unwrap.kind.input?
|
|
840
752
|
inner_type_non_null = inner_type.non_null?
|
|
841
|
-
response_list = GraphQLResultArray.new(result_name, selection_result, is_non_null)
|
|
753
|
+
response_list = GraphQLResultArray.new(result_name, current_type, owner_object, selection_result, is_non_null, next_selections, false, ast_node, arguments, field)
|
|
842
754
|
set_result(selection_result, result_name, response_list, true, is_non_null)
|
|
843
755
|
idx = nil
|
|
844
756
|
list_value = begin
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
757
|
+
begin
|
|
758
|
+
value.each do |inner_value|
|
|
759
|
+
idx ||= 0
|
|
760
|
+
this_idx = idx
|
|
761
|
+
idx += 1
|
|
762
|
+
if use_dataloader_job
|
|
763
|
+
@dataloader.append_job do
|
|
764
|
+
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)
|
|
765
|
+
end
|
|
766
|
+
else
|
|
767
|
+
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)
|
|
852
768
|
end
|
|
853
|
-
else
|
|
854
|
-
resolve_list_item(inner_value, inner_type, inner_type_non_null, ast_node, field, owner_object, arguments, this_idx, response_list, next_selections, owner_type)
|
|
855
769
|
end
|
|
856
|
-
end
|
|
857
770
|
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
771
|
+
response_list
|
|
772
|
+
rescue NoMethodError => err
|
|
773
|
+
# Ruby 2.2 doesn't have NoMethodError#receiver, can't check that one in this case. (It's been EOL since 2017.)
|
|
774
|
+
if err.name == :each && (err.respond_to?(:receiver) ? err.receiver == value : true)
|
|
775
|
+
# This happens when the GraphQL schema doesn't match the implementation. Help the dev debug.
|
|
776
|
+
raise ListResultFailedError.new(value: value, field: field, path: current_path)
|
|
777
|
+
else
|
|
778
|
+
# This was some other NoMethodError -- let it bubble to reveal the real error.
|
|
779
|
+
raise
|
|
780
|
+
end
|
|
781
|
+
rescue GraphQL::ExecutionError, GraphQL::UnauthorizedError => ex_err
|
|
782
|
+
ex_err
|
|
783
|
+
rescue StandardError => err
|
|
784
|
+
begin
|
|
785
|
+
query.handle_or_reraise(err)
|
|
786
|
+
rescue GraphQL::ExecutionError => ex_err
|
|
787
|
+
ex_err
|
|
788
|
+
end
|
|
867
789
|
end
|
|
868
|
-
rescue GraphQL::ExecutionError, GraphQL::UnauthorizedError => ex_err
|
|
869
|
-
ex_err
|
|
870
790
|
rescue StandardError => err
|
|
871
791
|
begin
|
|
872
792
|
query.handle_or_reraise(err)
|
|
@@ -876,22 +796,21 @@ module GraphQL
|
|
|
876
796
|
end
|
|
877
797
|
# Detect whether this error came while calling `.each` (before `idx` is set) or while running list *items* (after `idx` is set)
|
|
878
798
|
error_is_non_null = idx.nil? ? is_non_null : inner_type.non_null?
|
|
879
|
-
continue_value(list_value,
|
|
799
|
+
continue_value(list_value, field, error_is_non_null, ast_node, result_name, selection_result)
|
|
880
800
|
else
|
|
881
801
|
raise "Invariant: Unhandled type kind #{current_type.kind} (#{current_type})"
|
|
882
802
|
end
|
|
883
803
|
end
|
|
884
804
|
|
|
885
|
-
def resolve_list_item(inner_value, inner_type, inner_type_non_null, ast_node, field, owner_object, arguments, this_idx, response_list,
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
st.current_result = response_list
|
|
805
|
+
def 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) # rubocop:disable Metrics/ParameterLists
|
|
806
|
+
runtime_state.current_result_name = this_idx
|
|
807
|
+
runtime_state.current_result = response_list
|
|
889
808
|
call_method_on_directives(:resolve_each, owner_object, ast_node.directives) do
|
|
890
809
|
# This will update `response_list` with the lazy
|
|
891
|
-
after_lazy(inner_value, ast_node: ast_node, field: field, owner_object: owner_object, arguments: arguments, result_name: this_idx, result: response_list) do |inner_inner_value|
|
|
892
|
-
continue_value = continue_value(inner_inner_value,
|
|
810
|
+
after_lazy(inner_value, ast_node: ast_node, field: field, owner_object: owner_object, arguments: arguments, result_name: this_idx, result: response_list, runtime_state: runtime_state) do |inner_inner_value, runtime_state|
|
|
811
|
+
continue_value = continue_value(inner_inner_value, field, inner_type_non_null, ast_node, this_idx, response_list)
|
|
893
812
|
if HALT != continue_value
|
|
894
|
-
continue_field(continue_value, owner_type, field, inner_type, ast_node,
|
|
813
|
+
continue_field(continue_value, owner_type, field, inner_type, ast_node, response_list.graphql_selections, false, owner_object, arguments, this_idx, response_list, was_scoped, runtime_state)
|
|
895
814
|
end
|
|
896
815
|
end
|
|
897
816
|
end
|
|
@@ -909,9 +828,15 @@ module GraphQL
|
|
|
909
828
|
else
|
|
910
829
|
dir_defn = @schema_directives.fetch(dir_node.name)
|
|
911
830
|
raw_dir_args = arguments(nil, dir_defn, dir_node)
|
|
831
|
+
if !raw_dir_args.is_a?(GraphQL::ExecutionError)
|
|
832
|
+
begin
|
|
833
|
+
dir_defn.validate!(raw_dir_args, context)
|
|
834
|
+
rescue GraphQL::ExecutionError => err
|
|
835
|
+
raw_dir_args = err
|
|
836
|
+
end
|
|
837
|
+
end
|
|
912
838
|
dir_args = continue_value(
|
|
913
839
|
raw_dir_args, # value
|
|
914
|
-
dir_defn, # parent_type
|
|
915
840
|
nil, # field
|
|
916
841
|
false, # is_non_null
|
|
917
842
|
dir_node, # ast_node
|
|
@@ -942,12 +867,7 @@ module GraphQL
|
|
|
942
867
|
end
|
|
943
868
|
|
|
944
869
|
def get_current_runtime_state
|
|
945
|
-
current_state =
|
|
946
|
-
per_query_state = {}
|
|
947
|
-
per_query_state.compare_by_identity
|
|
948
|
-
per_query_state
|
|
949
|
-
end
|
|
950
|
-
|
|
870
|
+
current_state = Fiber[:__graphql_runtime_info] ||= {}.compare_by_identity
|
|
951
871
|
current_state[@query] ||= CurrentState.new
|
|
952
872
|
end
|
|
953
873
|
|
|
@@ -968,20 +888,25 @@ module GraphQL
|
|
|
968
888
|
# @param eager [Boolean] Set to `true` for mutation root fields only
|
|
969
889
|
# @param trace [Boolean] If `false`, don't wrap this with field tracing
|
|
970
890
|
# @return [GraphQL::Execution::Lazy, Object] If loading `object` will be deferred, it's a wrapper over it.
|
|
971
|
-
def after_lazy(lazy_obj, field:, owner_object:, arguments:, ast_node:, result:, result_name:, eager: false, trace: true, &block)
|
|
891
|
+
def after_lazy(lazy_obj, field:, owner_object:, arguments:, ast_node:, result:, result_name:, eager: false, runtime_state:, trace: true, &block)
|
|
972
892
|
if lazy?(lazy_obj)
|
|
973
|
-
|
|
893
|
+
was_authorized_by_scope_items = runtime_state.was_authorized_by_scope_items
|
|
974
894
|
lazy = GraphQL::Execution::Lazy.new(field: field) do
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
895
|
+
# This block might be called in a new fiber;
|
|
896
|
+
# In that case, this will initialize a new state
|
|
897
|
+
# to avoid conflicting with the parent fiber.
|
|
898
|
+
runtime_state = get_current_runtime_state
|
|
899
|
+
runtime_state.current_field = field
|
|
900
|
+
runtime_state.current_arguments = arguments
|
|
901
|
+
runtime_state.current_result_name = result_name
|
|
902
|
+
runtime_state.current_result = result
|
|
903
|
+
runtime_state.was_authorized_by_scope_items = was_authorized_by_scope_items
|
|
981
904
|
# Wrap the execution of _this_ method with tracing,
|
|
982
905
|
# but don't wrap the continuation below
|
|
906
|
+
sync_result = nil
|
|
983
907
|
inner_obj = begin
|
|
984
|
-
if trace
|
|
908
|
+
sync_result = if trace
|
|
909
|
+
@current_trace.begin_execute_field(field, owner_object, arguments, query)
|
|
985
910
|
@current_trace.execute_field_lazy(field: field, query: query, object: owner_object, arguments: arguments, ast_node: ast_node) do
|
|
986
911
|
schema.sync_lazy(lazy_obj)
|
|
987
912
|
end
|
|
@@ -996,25 +921,24 @@ module GraphQL
|
|
|
996
921
|
rescue GraphQL::ExecutionError => ex_err
|
|
997
922
|
ex_err
|
|
998
923
|
end
|
|
924
|
+
ensure
|
|
925
|
+
if trace
|
|
926
|
+
@current_trace.end_execute_field(field, owner_object, arguments, query, sync_result)
|
|
927
|
+
end
|
|
999
928
|
end
|
|
1000
|
-
yield(inner_obj)
|
|
929
|
+
yield(inner_obj, runtime_state)
|
|
1001
930
|
end
|
|
1002
931
|
|
|
1003
932
|
if eager
|
|
1004
933
|
lazy.value
|
|
1005
934
|
else
|
|
1006
935
|
set_result(result, result_name, lazy, false, false) # is_non_null is irrelevant here
|
|
1007
|
-
|
|
1008
|
-
while result
|
|
1009
|
-
current_depth += 1
|
|
1010
|
-
result = result.graphql_parent
|
|
1011
|
-
end
|
|
1012
|
-
@lazies_at_depth[current_depth] << lazy
|
|
936
|
+
@dataloader.lazy_at_depth(result.depth, lazy)
|
|
1013
937
|
lazy
|
|
1014
938
|
end
|
|
1015
939
|
else
|
|
1016
940
|
# Don't need to reset state here because it _wasn't_ lazy.
|
|
1017
|
-
yield(lazy_obj)
|
|
941
|
+
yield(lazy_obj, runtime_state)
|
|
1018
942
|
end
|
|
1019
943
|
end
|
|
1020
944
|
|
|
@@ -1028,25 +952,30 @@ module GraphQL
|
|
|
1028
952
|
end
|
|
1029
953
|
|
|
1030
954
|
def delete_all_interpreter_context
|
|
1031
|
-
per_query_state =
|
|
955
|
+
per_query_state = Fiber[:__graphql_runtime_info]
|
|
1032
956
|
if per_query_state
|
|
1033
957
|
per_query_state.delete(@query)
|
|
1034
958
|
if per_query_state.size == 0
|
|
1035
|
-
|
|
959
|
+
Fiber[:__graphql_runtime_info] = nil
|
|
1036
960
|
end
|
|
1037
961
|
end
|
|
1038
962
|
nil
|
|
1039
963
|
end
|
|
1040
964
|
|
|
1041
965
|
def resolve_type(type, value)
|
|
966
|
+
@current_trace.begin_resolve_type(type, value, context)
|
|
1042
967
|
resolved_type, resolved_value = @current_trace.resolve_type(query: query, type: type, object: value) do
|
|
1043
968
|
query.resolve_type(type, value)
|
|
1044
969
|
end
|
|
970
|
+
@current_trace.end_resolve_type(type, value, context, resolved_type)
|
|
1045
971
|
|
|
1046
972
|
if lazy?(resolved_type)
|
|
1047
973
|
GraphQL::Execution::Lazy.new do
|
|
974
|
+
@current_trace.begin_resolve_type(type, value, context)
|
|
1048
975
|
@current_trace.resolve_type_lazy(query: query, type: type, object: value) do
|
|
1049
|
-
schema.sync_lazy(resolved_type)
|
|
976
|
+
rt = schema.sync_lazy(resolved_type)
|
|
977
|
+
@current_trace.end_resolve_type(type, value, context, rt)
|
|
978
|
+
rt
|
|
1050
979
|
end
|
|
1051
980
|
end
|
|
1052
981
|
else
|