graphql 2.2.17 → 2.5.16
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/install/mutation_root_generator.rb +2 -2
- data/lib/generators/graphql/install_generator.rb +46 -0
- data/lib/generators/graphql/orm_mutations_base.rb +1 -1
- data/lib/generators/graphql/templates/base_resolver.erb +2 -0
- data/lib/generators/graphql/templates/schema.erb +3 -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/{ast/query_depth.rb → query_depth.rb} +23 -25
- 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/current.rb +57 -0
- data/lib/graphql/dashboard/detailed_traces.rb +47 -0
- data/lib/graphql/dashboard/installable.rb +22 -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/subscriptions.rb +96 -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 +23 -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 +158 -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 +46 -19
- data/lib/graphql/dataloader/null_dataloader.rb +51 -10
- data/lib/graphql/dataloader/source.rb +20 -9
- data/lib/graphql/dataloader.rb +153 -45
- data/lib/graphql/date_encoding_error.rb +1 -1
- data/lib/graphql/dig.rb +2 -1
- 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 +63 -5
- data/lib/graphql/execution/interpreter/runtime.rb +321 -222
- data/lib/graphql/execution/interpreter.rb +23 -30
- data/lib/graphql/execution/lookahead.rb +18 -11
- data/lib/graphql/execution/multiplex.rb +6 -5
- data/lib/graphql/introspection/directive_location_enum.rb +1 -1
- data/lib/graphql/introspection/directive_type.rb +1 -1
- data/lib/graphql/introspection/entry_points.rb +2 -2
- data/lib/graphql/introspection/field_type.rb +1 -1
- data/lib/graphql/introspection/schema_type.rb +6 -11
- data/lib/graphql/introspection/type_type.rb +5 -5
- data/lib/graphql/invalid_name_error.rb +1 -1
- data/lib/graphql/invalid_null_error.rb +20 -17
- data/lib/graphql/language/cache.rb +13 -0
- data/lib/graphql/language/comment.rb +18 -0
- data/lib/graphql/language/document_from_schema_definition.rb +64 -35
- data/lib/graphql/language/lexer.rb +72 -42
- data/lib/graphql/language/nodes.rb +93 -52
- data/lib/graphql/language/parser.rb +168 -61
- data/lib/graphql/language/printer.rb +31 -15
- data/lib/graphql/language/sanitized_printer.rb +1 -1
- data/lib/graphql/language.rb +61 -1
- data/lib/graphql/pagination/connection.rb +1 -1
- data/lib/graphql/query/context/scoped_context.rb +1 -1
- data/lib/graphql/query/context.rb +46 -47
- data/lib/graphql/query/null_context.rb +3 -5
- data/lib/graphql/query/partial.rb +179 -0
- data/lib/graphql/query/validation_pipeline.rb +2 -2
- data/lib/graphql/query/variable_validation_error.rb +1 -1
- data/lib/graphql/query.rb +123 -69
- data/lib/graphql/railtie.rb +7 -0
- 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 +57 -8
- data/lib/graphql/schema/build_from_definition.rb +116 -49
- data/lib/graphql/schema/directive/flagged.rb +4 -2
- data/lib/graphql/schema/directive.rb +54 -2
- data/lib/graphql/schema/enum.rb +107 -24
- data/lib/graphql/schema/enum_value.rb +10 -2
- data/lib/graphql/schema/field/connection_extension.rb +1 -1
- data/lib/graphql/schema/field/scope_extension.rb +1 -1
- data/lib/graphql/schema/field.rb +134 -45
- data/lib/graphql/schema/field_extension.rb +1 -1
- data/lib/graphql/schema/has_single_input_argument.rb +6 -2
- data/lib/graphql/schema/input_object.rb +122 -64
- data/lib/graphql/schema/interface.rb +23 -5
- data/lib/graphql/schema/introspection_system.rb +6 -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 -2
- data/lib/graphql/schema/member/base_dsl_methods.rb +15 -0
- data/lib/graphql/schema/member/has_arguments.rb +44 -58
- data/lib/graphql/schema/member/has_dataloader.rb +62 -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 +26 -6
- data/lib/graphql/schema/member/has_interfaces.rb +6 -6
- 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/type_system_helpers.rb +17 -4
- data/lib/graphql/schema/member.rb +1 -0
- data/lib/graphql/schema/mutation.rb +7 -0
- data/lib/graphql/schema/object.rb +25 -8
- data/lib/graphql/schema/printer.rb +1 -0
- data/lib/graphql/schema/ractor_shareable.rb +79 -0
- data/lib/graphql/schema/relay_classic_mutation.rb +0 -1
- data/lib/graphql/schema/resolver.rb +29 -23
- data/lib/graphql/schema/scalar.rb +1 -6
- data/lib/graphql/schema/subscription.rb +52 -6
- data/lib/graphql/schema/timeout.rb +19 -2
- data/lib/graphql/schema/type_expression.rb +2 -2
- data/lib/graphql/schema/union.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 +190 -20
- data/lib/graphql/schema.rb +695 -167
- data/lib/graphql/static_validation/all_rules.rb +2 -2
- data/lib/graphql/static_validation/base_visitor.rb +6 -5
- data/lib/graphql/static_validation/literal_validator.rb +4 -4
- 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 +4 -4
- data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +3 -3
- 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 +18 -2
- data/lib/graphql/static_validation/validator.rb +6 -1
- data/lib/graphql/subscriptions/action_cable_subscriptions.rb +5 -3
- 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 +13 -2
- data/lib/graphql/subscriptions/serialize.rb +1 -1
- data/lib/graphql/subscriptions.rb +7 -5
- data/lib/graphql/testing/helpers.rb +48 -16
- data/lib/graphql/testing/mock_action_cable.rb +111 -0
- data/lib/graphql/testing.rb +1 -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 +5 -1
- data/lib/graphql/tracing/appoptics_tracing.rb +7 -0
- 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/memory_backend.rb +60 -0
- data/lib/graphql/tracing/detailed_trace/redis_backend.rb +72 -0
- data/lib/graphql/tracing/detailed_trace.rb +141 -0
- data/lib/graphql/tracing/legacy_hooks_trace.rb +1 -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 +818 -0
- data/lib/graphql/tracing/platform_tracing.rb +1 -1
- data/lib/graphql/tracing/prometheus_trace/graphql_collector.rb +2 -0
- 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 +64 -98
- data/lib/graphql/tracing/statsd_trace.rb +33 -45
- data/lib/graphql/tracing/statsd_tracing.rb +2 -0
- data/lib/graphql/tracing/trace.rb +111 -1
- data/lib/graphql/tracing.rb +31 -30
- data/lib/graphql/type_kinds.rb +2 -1
- data/lib/graphql/types/relay/connection_behaviors.rb +12 -2
- data/lib/graphql/types/relay/edge_behaviors.rb +11 -1
- data/lib/graphql/types/relay/page_info_behaviors.rb +4 -0
- data/lib/graphql/types.rb +18 -11
- data/lib/graphql/unauthorized_enum_value_error.rb +13 -0
- data/lib/graphql/version.rb +1 -1
- data/lib/graphql.rb +64 -54
- metadata +197 -22
- data/lib/graphql/analysis/ast/analyzer.rb +0 -91
- data/lib/graphql/analysis/ast/field_usage.rb +0 -82
- 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 -182
- data/lib/graphql/analysis/ast/visitor.rb +0 -276
- data/lib/graphql/analysis/ast.rb +0 -94
- data/lib/graphql/backtrace/inspect_result.rb +0 -50
- data/lib/graphql/backtrace/trace.rb +0 -93
- data/lib/graphql/backtrace/tracer.rb +0 -80
- data/lib/graphql/language/token.rb +0 -34
- 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
|
@@ -11,7 +11,6 @@ module GraphQL
|
|
|
11
11
|
class Runtime
|
|
12
12
|
class CurrentState
|
|
13
13
|
def initialize
|
|
14
|
-
@current_object = nil
|
|
15
14
|
@current_field = nil
|
|
16
15
|
@current_arguments = nil
|
|
17
16
|
@current_result_name = nil
|
|
@@ -19,8 +18,12 @@ module GraphQL
|
|
|
19
18
|
@was_authorized_by_scope_items = nil
|
|
20
19
|
end
|
|
21
20
|
|
|
21
|
+
def current_object
|
|
22
|
+
@current_result.graphql_application_value
|
|
23
|
+
end
|
|
24
|
+
|
|
22
25
|
attr_accessor :current_result, :current_result_name,
|
|
23
|
-
:current_arguments, :current_field, :
|
|
26
|
+
:current_arguments, :current_field, :was_authorized_by_scope_items
|
|
24
27
|
end
|
|
25
28
|
|
|
26
29
|
# @return [GraphQL::Query]
|
|
@@ -32,14 +35,13 @@ module GraphQL
|
|
|
32
35
|
# @return [GraphQL::Query::Context]
|
|
33
36
|
attr_reader :context
|
|
34
37
|
|
|
35
|
-
def initialize(query
|
|
38
|
+
def initialize(query:)
|
|
36
39
|
@query = query
|
|
37
40
|
@current_trace = query.current_trace
|
|
38
41
|
@dataloader = query.multiplex.dataloader
|
|
39
|
-
@lazies_at_depth = lazies_at_depth
|
|
40
42
|
@schema = query.schema
|
|
41
43
|
@context = query.context
|
|
42
|
-
@response =
|
|
44
|
+
@response = nil
|
|
43
45
|
# Identify runtime directives by checking which of this schema's directives have overridden `def self.resolve`
|
|
44
46
|
@runtime_directive_names = []
|
|
45
47
|
noop_resolve_owner = GraphQL::Schema::Directive.singleton_class
|
|
@@ -50,93 +52,164 @@ module GraphQL
|
|
|
50
52
|
end
|
|
51
53
|
end
|
|
52
54
|
# { Class => Boolean }
|
|
53
|
-
@lazy_cache = {}
|
|
54
|
-
@lazy_cache.compare_by_identity
|
|
55
|
+
@lazy_cache = {}.compare_by_identity
|
|
55
56
|
end
|
|
56
57
|
|
|
57
58
|
def final_result
|
|
58
|
-
@response
|
|
59
|
+
@response.respond_to?(:graphql_result_data) ? @response.graphql_result_data : @response
|
|
59
60
|
end
|
|
60
61
|
|
|
61
62
|
def inspect
|
|
62
63
|
"#<#{self.class.name} response=#{@response.inspect}>"
|
|
63
64
|
end
|
|
64
65
|
|
|
65
|
-
def tap_or_each(obj_or_array)
|
|
66
|
-
if obj_or_array.is_a?(Array)
|
|
67
|
-
obj_or_array.each do |item|
|
|
68
|
-
yield(item, true)
|
|
69
|
-
end
|
|
70
|
-
else
|
|
71
|
-
yield(obj_or_array, false)
|
|
72
|
-
end
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
# This _begins_ the execution. Some deferred work
|
|
76
|
-
# might be stored up in lazies.
|
|
77
66
|
# @return [void]
|
|
78
67
|
def run_eager
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
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
|
|
92
82
|
else
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
if (directives = selections[:graphql_directives])
|
|
118
|
-
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
|
|
119
107
|
end
|
|
120
|
-
|
|
108
|
+
|
|
109
|
+
@dataloader.append_job {
|
|
121
110
|
evaluate_selections(
|
|
122
|
-
runtime_object,
|
|
123
|
-
root_type,
|
|
124
|
-
root_op_type == "mutation",
|
|
125
111
|
selections,
|
|
126
112
|
selection_response,
|
|
127
113
|
final_response,
|
|
128
114
|
nil,
|
|
129
|
-
st,
|
|
130
115
|
)
|
|
131
|
-
|
|
132
|
-
|
|
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
|
|
133
154
|
end
|
|
134
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})"
|
|
135
195
|
end
|
|
136
196
|
nil
|
|
137
197
|
end
|
|
138
198
|
|
|
139
|
-
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)
|
|
140
213
|
selections.each do |node|
|
|
141
214
|
# Skip gathering this if the directive says so
|
|
142
215
|
if !directives_include?(node, owner_object, owner_type)
|
|
@@ -145,10 +218,11 @@ module GraphQL
|
|
|
145
218
|
|
|
146
219
|
if node.is_a?(GraphQL::Language::Nodes::Field)
|
|
147
220
|
response_key = node.alias || node.name
|
|
221
|
+
ordered_result_keys << response_key
|
|
148
222
|
selections = selections_by_name[response_key]
|
|
149
223
|
# if there was already a selection of this field,
|
|
150
224
|
# use an array to hold all selections,
|
|
151
|
-
#
|
|
225
|
+
# otherwise, use the single node to represent the selection
|
|
152
226
|
if selections
|
|
153
227
|
# This field was already selected at least once,
|
|
154
228
|
# add this node to the list of selections
|
|
@@ -161,7 +235,7 @@ module GraphQL
|
|
|
161
235
|
end
|
|
162
236
|
else
|
|
163
237
|
# This is an InlineFragment or a FragmentSpread
|
|
164
|
-
if
|
|
238
|
+
if !@runtime_directive_names.empty? && node.directives.any? { |d| @runtime_directive_names.include?(d.name) }
|
|
165
239
|
next_selections = {}
|
|
166
240
|
next_selections[:graphql_directives] = node.directives
|
|
167
241
|
if selections_to_run
|
|
@@ -178,26 +252,26 @@ module GraphQL
|
|
|
178
252
|
case node
|
|
179
253
|
when GraphQL::Language::Nodes::InlineFragment
|
|
180
254
|
if node.type
|
|
181
|
-
type_defn =
|
|
255
|
+
type_defn = query.types.type(node.type.name)
|
|
182
256
|
|
|
183
|
-
if query.
|
|
184
|
-
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)
|
|
185
259
|
if !result.equal?(next_selections)
|
|
186
260
|
selections_to_run = result
|
|
187
261
|
end
|
|
188
262
|
end
|
|
189
263
|
else
|
|
190
264
|
# it's an untyped fragment, definitely continue
|
|
191
|
-
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)
|
|
192
266
|
if !result.equal?(next_selections)
|
|
193
267
|
selections_to_run = result
|
|
194
268
|
end
|
|
195
269
|
end
|
|
196
270
|
when GraphQL::Language::Nodes::FragmentSpread
|
|
197
271
|
fragment_def = query.fragments[node.name]
|
|
198
|
-
type_defn = query.
|
|
199
|
-
if query.
|
|
200
|
-
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)
|
|
201
275
|
if !result.equal?(next_selections)
|
|
202
276
|
selections_to_run = result
|
|
203
277
|
end
|
|
@@ -213,36 +287,46 @@ module GraphQL
|
|
|
213
287
|
NO_ARGS = GraphQL::EmptyObjects::EMPTY_HASH
|
|
214
288
|
|
|
215
289
|
# @return [void]
|
|
216
|
-
def evaluate_selections(
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
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
|
+
}
|
|
228
318
|
end
|
|
229
|
-
}
|
|
230
|
-
# Field resolution may pause the fiber,
|
|
231
|
-
# so it wouldn't get to the `Resolve` call that happens below.
|
|
232
|
-
# So instead trigger a run from this outer context.
|
|
233
|
-
if is_eager_selection
|
|
234
|
-
@dataloader.clear_cache
|
|
235
|
-
@dataloader.run
|
|
236
|
-
@dataloader.clear_cache
|
|
237
319
|
end
|
|
320
|
+
if target_result
|
|
321
|
+
selections_result.merge_into(target_result)
|
|
322
|
+
end
|
|
323
|
+
selections_result
|
|
238
324
|
end
|
|
239
|
-
|
|
240
|
-
selections_result
|
|
241
325
|
end
|
|
242
326
|
|
|
243
327
|
# @return [void]
|
|
244
|
-
def evaluate_selection(result_name, field_ast_nodes_or_ast_node,
|
|
245
|
-
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
|
|
246
330
|
# As a performance optimization, the hash key will be a `Node` if
|
|
247
331
|
# there's only one selection of the field. But if there are multiple
|
|
248
332
|
# selections of the field, it will be an Array of nodes
|
|
@@ -254,40 +338,48 @@ module GraphQL
|
|
|
254
338
|
ast_node = field_ast_nodes_or_ast_node
|
|
255
339
|
end
|
|
256
340
|
field_name = ast_node.name
|
|
257
|
-
|
|
341
|
+
owner_type = selections_result.graphql_result_type
|
|
342
|
+
field_defn = query.types.field(owner_type, field_name)
|
|
258
343
|
|
|
259
344
|
# Set this before calling `run_with_directives`, so that the directive can have the latest path
|
|
345
|
+
runtime_state = get_current_runtime_state
|
|
260
346
|
runtime_state.current_field = field_defn
|
|
261
347
|
runtime_state.current_result = selections_result
|
|
262
348
|
runtime_state.current_result_name = result_name
|
|
263
349
|
|
|
350
|
+
owner_object = selections_result.graphql_application_value
|
|
264
351
|
if field_defn.dynamic_introspection
|
|
265
352
|
owner_object = field_defn.owner.wrap(owner_object, context)
|
|
266
353
|
end
|
|
267
354
|
|
|
268
|
-
return_type = field_defn.type
|
|
269
355
|
if !field_defn.any_arguments?
|
|
270
356
|
resolved_arguments = GraphQL::Execution::Interpreter::Arguments::EMPTY
|
|
271
357
|
if field_defn.extras.size == 0
|
|
272
358
|
evaluate_selection_with_resolved_keyword_args(
|
|
273
|
-
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
|
|
274
360
|
)
|
|
275
361
|
else
|
|
276
|
-
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)
|
|
277
363
|
end
|
|
278
364
|
else
|
|
279
365
|
@query.arguments_cache.dataload_for(ast_node, field_defn, owner_object) do |resolved_arguments|
|
|
280
366
|
runtime_state = get_current_runtime_state # This might be in a different fiber
|
|
281
|
-
|
|
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)
|
|
282
372
|
end
|
|
283
373
|
end
|
|
284
374
|
end
|
|
285
375
|
|
|
286
|
-
def evaluate_selection_with_args(arguments, field_defn, ast_node, field_ast_nodes,
|
|
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
|
|
287
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|
|
|
288
|
-
return_type_non_null = return_type.non_null?
|
|
289
378
|
if resolved_arguments.is_a?(GraphQL::ExecutionError) || resolved_arguments.is_a?(GraphQL::UnauthorizedError)
|
|
290
|
-
|
|
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)
|
|
291
383
|
next
|
|
292
384
|
end
|
|
293
385
|
|
|
@@ -325,24 +417,24 @@ module GraphQL
|
|
|
325
417
|
# to the keyword args hash _before_ freezing everything.
|
|
326
418
|
extra_args[:argument_details] = :__arguments_add_self
|
|
327
419
|
when :parent
|
|
328
|
-
|
|
420
|
+
parent_result = selection_result.graphql_parent
|
|
421
|
+
extra_args[:parent] = parent_result&.graphql_application_value&.object
|
|
329
422
|
else
|
|
330
423
|
extra_args[extra] = field_defn.fetch_extra(extra, context)
|
|
331
424
|
end
|
|
332
425
|
end
|
|
333
|
-
if extra_args.
|
|
426
|
+
if !extra_args.empty?
|
|
334
427
|
resolved_arguments = resolved_arguments.merge_extras(extra_args)
|
|
335
428
|
end
|
|
336
429
|
resolved_arguments.keyword_arguments
|
|
337
430
|
end
|
|
338
431
|
|
|
339
|
-
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)
|
|
340
433
|
end
|
|
341
434
|
end
|
|
342
435
|
|
|
343
|
-
def evaluate_selection_with_resolved_keyword_args(kwarg_arguments, resolved_arguments, field_defn, ast_node, field_ast_nodes,
|
|
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
|
|
344
437
|
runtime_state.current_field = field_defn
|
|
345
|
-
runtime_state.current_object = object
|
|
346
438
|
runtime_state.current_arguments = resolved_arguments
|
|
347
439
|
runtime_state.current_result_name = result_name
|
|
348
440
|
runtime_state.current_result = selection_result
|
|
@@ -359,18 +451,18 @@ module GraphQL
|
|
|
359
451
|
}
|
|
360
452
|
end
|
|
361
453
|
|
|
362
|
-
|
|
363
|
-
if directives.
|
|
454
|
+
call_method_on_directives(:resolve, object, directives) do
|
|
455
|
+
if !directives.empty?
|
|
364
456
|
# This might be executed in a different context; reset this info
|
|
365
457
|
runtime_state = get_current_runtime_state
|
|
366
458
|
runtime_state.current_field = field_defn
|
|
367
|
-
runtime_state.current_object = object
|
|
368
459
|
runtime_state.current_arguments = resolved_arguments
|
|
369
460
|
runtime_state.current_result_name = result_name
|
|
370
461
|
runtime_state.current_result = selection_result
|
|
371
462
|
end
|
|
372
463
|
# Actually call the field resolver and capture the result
|
|
373
464
|
app_result = begin
|
|
465
|
+
@current_trace.begin_execute_field(field_defn, object, kwarg_arguments, query)
|
|
374
466
|
@current_trace.execute_field(field: field_defn, ast_node: ast_node, query: query, object: object, arguments: kwarg_arguments) do
|
|
375
467
|
field_defn.resolve(object, kwarg_arguments, context)
|
|
376
468
|
end
|
|
@@ -383,34 +475,32 @@ module GraphQL
|
|
|
383
475
|
ex_err
|
|
384
476
|
end
|
|
385
477
|
end
|
|
478
|
+
@current_trace.end_execute_field(field_defn, object, kwarg_arguments, query, app_result)
|
|
386
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|
|
|
387
|
-
|
|
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)
|
|
388
485
|
if HALT != continue_value
|
|
389
486
|
was_scoped = runtime_state.was_authorized_by_scope_items
|
|
390
487
|
runtime_state.was_authorized_by_scope_items = nil
|
|
391
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
|
|
392
491
|
end
|
|
393
492
|
end
|
|
394
493
|
end
|
|
395
|
-
|
|
396
494
|
# If this field is a root mutation field, immediately resolve
|
|
397
495
|
# all of its child fields before moving on to the next root mutation field.
|
|
398
496
|
# (Subselections of this mutation will still be resolved level-by-level.)
|
|
399
|
-
if
|
|
400
|
-
|
|
401
|
-
else
|
|
402
|
-
# Return this from `after_lazy` because it might be another lazy that needs to be resolved
|
|
403
|
-
field_result
|
|
497
|
+
if selection_result.graphql_is_eager
|
|
498
|
+
@dataloader.run
|
|
404
499
|
end
|
|
405
500
|
end
|
|
406
501
|
|
|
407
|
-
|
|
408
|
-
def dead_result?(selection_result)
|
|
409
|
-
selection_result.graphql_dead # || ((parent = selection_result.graphql_parent) && parent.graphql_dead)
|
|
410
|
-
end
|
|
411
|
-
|
|
412
502
|
def set_result(selection_result, result_name, value, is_child_result, is_non_null)
|
|
413
|
-
if !
|
|
503
|
+
if !selection_result.graphql_dead
|
|
414
504
|
if value.nil? && is_non_null
|
|
415
505
|
# This is an invalid nil that should be propagated
|
|
416
506
|
# One caller of this method passes a block,
|
|
@@ -463,14 +553,17 @@ module GraphQL
|
|
|
463
553
|
path
|
|
464
554
|
end
|
|
465
555
|
|
|
466
|
-
HALT = Object.new
|
|
467
|
-
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
|
|
468
558
|
case value
|
|
469
559
|
when nil
|
|
470
560
|
if is_non_null
|
|
471
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
|
|
472
565
|
# This block is called if `result_name` is not dead. (Maybe a previous invalid nil caused it be marked dead.)
|
|
473
|
-
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)
|
|
474
567
|
schema.type_error(err, context)
|
|
475
568
|
end
|
|
476
569
|
else
|
|
@@ -482,7 +575,7 @@ module GraphQL
|
|
|
482
575
|
# to avoid the overhead of checking three different classes
|
|
483
576
|
# every time.
|
|
484
577
|
if value.is_a?(GraphQL::ExecutionError)
|
|
485
|
-
if selection_result.nil? || !
|
|
578
|
+
if selection_result.nil? || !selection_result.graphql_dead
|
|
486
579
|
value.path ||= current_path
|
|
487
580
|
value.ast_node ||= ast_node
|
|
488
581
|
context.errors << value
|
|
@@ -500,7 +593,7 @@ module GraphQL
|
|
|
500
593
|
rescue GraphQL::ExecutionError => err
|
|
501
594
|
err
|
|
502
595
|
end
|
|
503
|
-
continue_value(next_value,
|
|
596
|
+
continue_value(next_value, field, is_non_null, ast_node, result_name, selection_result)
|
|
504
597
|
elsif value.is_a?(GraphQL::UnauthorizedError)
|
|
505
598
|
# this hook might raise & crash, or it might return
|
|
506
599
|
# a replacement value
|
|
@@ -509,7 +602,7 @@ module GraphQL
|
|
|
509
602
|
rescue GraphQL::ExecutionError => err
|
|
510
603
|
err
|
|
511
604
|
end
|
|
512
|
-
continue_value(next_value,
|
|
605
|
+
continue_value(next_value, field, is_non_null, ast_node, result_name, selection_result)
|
|
513
606
|
elsif GraphQL::Execution::SKIP == value
|
|
514
607
|
# It's possible a lazy was already written here
|
|
515
608
|
case selection_result
|
|
@@ -530,9 +623,9 @@ module GraphQL
|
|
|
530
623
|
end
|
|
531
624
|
when Array
|
|
532
625
|
# It's an array full of execution errors; add them all.
|
|
533
|
-
if value.
|
|
626
|
+
if !value.empty? && value.all?(GraphQL::ExecutionError)
|
|
534
627
|
list_type_at_all = (field && (field.type.list?))
|
|
535
|
-
if selection_result.nil? || !
|
|
628
|
+
if selection_result.nil? || !selection_result.graphql_dead
|
|
536
629
|
value.each_with_index do |error, index|
|
|
537
630
|
error.ast_node ||= ast_node
|
|
538
631
|
error.path ||= current_path + (list_type_at_all ? [index] : [])
|
|
@@ -578,13 +671,29 @@ module GraphQL
|
|
|
578
671
|
when "SCALAR", "ENUM"
|
|
579
672
|
r = begin
|
|
580
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)
|
|
581
676
|
rescue StandardError => err
|
|
582
|
-
|
|
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
|
|
583
682
|
end
|
|
584
683
|
set_result(selection_result, result_name, r, false, is_non_null)
|
|
585
684
|
r
|
|
586
685
|
when "UNION", "INTERFACE"
|
|
587
|
-
resolved_type_or_lazy =
|
|
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
|
|
588
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|
|
|
589
698
|
if resolved_type_result.is_a?(Array) && resolved_type_result.length == 2
|
|
590
699
|
resolved_type, resolved_value = resolved_type_result
|
|
@@ -593,7 +702,7 @@ module GraphQL
|
|
|
593
702
|
resolved_value = value
|
|
594
703
|
end
|
|
595
704
|
|
|
596
|
-
possible_types = query.possible_types(current_type)
|
|
705
|
+
possible_types = query.types.possible_types(current_type)
|
|
597
706
|
if !possible_types.include?(resolved_type)
|
|
598
707
|
parent_type = field.owner_type
|
|
599
708
|
err_class = current_type::UnresolvedTypeError
|
|
@@ -612,50 +721,27 @@ module GraphQL
|
|
|
612
721
|
err
|
|
613
722
|
end
|
|
614
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|
|
|
615
|
-
continue_value = continue_value(inner_object,
|
|
724
|
+
continue_value = continue_value(inner_object, field, is_non_null, ast_node, result_name, selection_result)
|
|
616
725
|
if HALT != continue_value
|
|
617
|
-
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)
|
|
618
727
|
set_result(selection_result, result_name, response_hash, true, is_non_null)
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
# There are two possibilities for `gathered_selections`:
|
|
622
|
-
# 1. All selections of this object should be evaluated together (there are no runtime directives modifying execution).
|
|
623
|
-
# This case is handled below, and the result can be written right into the main `response_hash` above.
|
|
624
|
-
# In this case, `gathered_selections` is a hash of selections.
|
|
625
|
-
# 2. Some selections of this object have runtime directives that may or may not modify execution.
|
|
626
|
-
# That part of the selection is evaluated in an isolated way, writing into a sub-response object which is
|
|
627
|
-
# eventually merged into the final response. In this case, `gathered_selections` is an array of things to run in isolation.
|
|
628
|
-
# (Technically, it's possible that one of those entries _doesn't_ require isolation.)
|
|
629
|
-
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
|
|
630
730
|
if is_selection_array
|
|
631
|
-
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
|
|
632
733
|
final_result = response_hash
|
|
633
734
|
else
|
|
634
735
|
this_result = response_hash
|
|
635
736
|
final_result = nil
|
|
636
737
|
end
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
selections.delete(:graphql_directives)
|
|
645
|
-
end
|
|
646
|
-
call_method_on_directives(:resolve, continue_value, directives) do
|
|
647
|
-
evaluate_selections(
|
|
648
|
-
continue_value,
|
|
649
|
-
current_type,
|
|
650
|
-
false,
|
|
651
|
-
selections,
|
|
652
|
-
this_result,
|
|
653
|
-
final_result,
|
|
654
|
-
owner_object.object,
|
|
655
|
-
runtime_state,
|
|
656
|
-
)
|
|
657
|
-
this_result
|
|
658
|
-
end
|
|
738
|
+
|
|
739
|
+
evaluate_selections(
|
|
740
|
+
selections,
|
|
741
|
+
this_result,
|
|
742
|
+
final_result,
|
|
743
|
+
runtime_state,
|
|
744
|
+
)
|
|
659
745
|
end
|
|
660
746
|
end
|
|
661
747
|
end
|
|
@@ -664,35 +750,43 @@ module GraphQL
|
|
|
664
750
|
# This is true for objects, unions, and interfaces
|
|
665
751
|
use_dataloader_job = !inner_type.unwrap.kind.input?
|
|
666
752
|
inner_type_non_null = inner_type.non_null?
|
|
667
|
-
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)
|
|
668
754
|
set_result(selection_result, result_name, response_list, true, is_non_null)
|
|
669
755
|
idx = nil
|
|
670
756
|
list_value = begin
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
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)
|
|
678
768
|
end
|
|
679
|
-
else
|
|
680
|
-
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, was_scoped, runtime_state)
|
|
681
769
|
end
|
|
682
|
-
end
|
|
683
770
|
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
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
|
|
693
789
|
end
|
|
694
|
-
rescue GraphQL::ExecutionError, GraphQL::UnauthorizedError => ex_err
|
|
695
|
-
ex_err
|
|
696
790
|
rescue StandardError => err
|
|
697
791
|
begin
|
|
698
792
|
query.handle_or_reraise(err)
|
|
@@ -702,21 +796,21 @@ module GraphQL
|
|
|
702
796
|
end
|
|
703
797
|
# Detect whether this error came while calling `.each` (before `idx` is set) or while running list *items* (after `idx` is set)
|
|
704
798
|
error_is_non_null = idx.nil? ? is_non_null : inner_type.non_null?
|
|
705
|
-
continue_value(list_value,
|
|
799
|
+
continue_value(list_value, field, error_is_non_null, ast_node, result_name, selection_result)
|
|
706
800
|
else
|
|
707
801
|
raise "Invariant: Unhandled type kind #{current_type.kind} (#{current_type})"
|
|
708
802
|
end
|
|
709
803
|
end
|
|
710
804
|
|
|
711
|
-
def resolve_list_item(inner_value, inner_type, inner_type_non_null, ast_node, field, owner_object, arguments, this_idx, 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
|
|
712
806
|
runtime_state.current_result_name = this_idx
|
|
713
807
|
runtime_state.current_result = response_list
|
|
714
808
|
call_method_on_directives(:resolve_each, owner_object, ast_node.directives) do
|
|
715
809
|
# This will update `response_list` with the lazy
|
|
716
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|
|
|
717
|
-
continue_value = continue_value(inner_inner_value,
|
|
811
|
+
continue_value = continue_value(inner_inner_value, field, inner_type_non_null, ast_node, this_idx, response_list)
|
|
718
812
|
if HALT != continue_value
|
|
719
|
-
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)
|
|
720
814
|
end
|
|
721
815
|
end
|
|
722
816
|
end
|
|
@@ -734,9 +828,15 @@ module GraphQL
|
|
|
734
828
|
else
|
|
735
829
|
dir_defn = @schema_directives.fetch(dir_node.name)
|
|
736
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
|
|
737
838
|
dir_args = continue_value(
|
|
738
839
|
raw_dir_args, # value
|
|
739
|
-
dir_defn, # parent_type
|
|
740
840
|
nil, # field
|
|
741
841
|
false, # is_non_null
|
|
742
842
|
dir_node, # ast_node
|
|
@@ -767,12 +867,7 @@ module GraphQL
|
|
|
767
867
|
end
|
|
768
868
|
|
|
769
869
|
def get_current_runtime_state
|
|
770
|
-
current_state =
|
|
771
|
-
per_query_state = {}
|
|
772
|
-
per_query_state.compare_by_identity
|
|
773
|
-
per_query_state
|
|
774
|
-
end
|
|
775
|
-
|
|
870
|
+
current_state = Fiber[:__graphql_runtime_info] ||= {}.compare_by_identity
|
|
776
871
|
current_state[@query] ||= CurrentState.new
|
|
777
872
|
end
|
|
778
873
|
|
|
@@ -795,23 +890,23 @@ module GraphQL
|
|
|
795
890
|
# @return [GraphQL::Execution::Lazy, Object] If loading `object` will be deferred, it's a wrapper over it.
|
|
796
891
|
def after_lazy(lazy_obj, field:, owner_object:, arguments:, ast_node:, result:, result_name:, eager: false, runtime_state:, trace: true, &block)
|
|
797
892
|
if lazy?(lazy_obj)
|
|
798
|
-
orig_result = result
|
|
799
893
|
was_authorized_by_scope_items = runtime_state.was_authorized_by_scope_items
|
|
800
894
|
lazy = GraphQL::Execution::Lazy.new(field: field) do
|
|
801
895
|
# This block might be called in a new fiber;
|
|
802
896
|
# In that case, this will initialize a new state
|
|
803
897
|
# to avoid conflicting with the parent fiber.
|
|
804
898
|
runtime_state = get_current_runtime_state
|
|
805
|
-
runtime_state.current_object = owner_object
|
|
806
899
|
runtime_state.current_field = field
|
|
807
900
|
runtime_state.current_arguments = arguments
|
|
808
901
|
runtime_state.current_result_name = result_name
|
|
809
|
-
runtime_state.current_result =
|
|
902
|
+
runtime_state.current_result = result
|
|
810
903
|
runtime_state.was_authorized_by_scope_items = was_authorized_by_scope_items
|
|
811
904
|
# Wrap the execution of _this_ method with tracing,
|
|
812
905
|
# but don't wrap the continuation below
|
|
906
|
+
sync_result = nil
|
|
813
907
|
inner_obj = begin
|
|
814
|
-
if trace
|
|
908
|
+
sync_result = if trace
|
|
909
|
+
@current_trace.begin_execute_field(field, owner_object, arguments, query)
|
|
815
910
|
@current_trace.execute_field_lazy(field: field, query: query, object: owner_object, arguments: arguments, ast_node: ast_node) do
|
|
816
911
|
schema.sync_lazy(lazy_obj)
|
|
817
912
|
end
|
|
@@ -826,6 +921,10 @@ module GraphQL
|
|
|
826
921
|
rescue GraphQL::ExecutionError => ex_err
|
|
827
922
|
ex_err
|
|
828
923
|
end
|
|
924
|
+
ensure
|
|
925
|
+
if trace
|
|
926
|
+
@current_trace.end_execute_field(field, owner_object, arguments, query, sync_result)
|
|
927
|
+
end
|
|
829
928
|
end
|
|
830
929
|
yield(inner_obj, runtime_state)
|
|
831
930
|
end
|
|
@@ -834,12 +933,7 @@ module GraphQL
|
|
|
834
933
|
lazy.value
|
|
835
934
|
else
|
|
836
935
|
set_result(result, result_name, lazy, false, false) # is_non_null is irrelevant here
|
|
837
|
-
|
|
838
|
-
while result
|
|
839
|
-
current_depth += 1
|
|
840
|
-
result = result.graphql_parent
|
|
841
|
-
end
|
|
842
|
-
@lazies_at_depth[current_depth] << lazy
|
|
936
|
+
@dataloader.lazy_at_depth(result.depth, lazy)
|
|
843
937
|
lazy
|
|
844
938
|
end
|
|
845
939
|
else
|
|
@@ -858,25 +952,30 @@ module GraphQL
|
|
|
858
952
|
end
|
|
859
953
|
|
|
860
954
|
def delete_all_interpreter_context
|
|
861
|
-
per_query_state =
|
|
955
|
+
per_query_state = Fiber[:__graphql_runtime_info]
|
|
862
956
|
if per_query_state
|
|
863
957
|
per_query_state.delete(@query)
|
|
864
958
|
if per_query_state.size == 0
|
|
865
|
-
|
|
959
|
+
Fiber[:__graphql_runtime_info] = nil
|
|
866
960
|
end
|
|
867
961
|
end
|
|
868
962
|
nil
|
|
869
963
|
end
|
|
870
964
|
|
|
871
965
|
def resolve_type(type, value)
|
|
966
|
+
@current_trace.begin_resolve_type(type, value, context)
|
|
872
967
|
resolved_type, resolved_value = @current_trace.resolve_type(query: query, type: type, object: value) do
|
|
873
968
|
query.resolve_type(type, value)
|
|
874
969
|
end
|
|
970
|
+
@current_trace.end_resolve_type(type, value, context, resolved_type)
|
|
875
971
|
|
|
876
972
|
if lazy?(resolved_type)
|
|
877
973
|
GraphQL::Execution::Lazy.new do
|
|
974
|
+
@current_trace.begin_resolve_type(type, value, context)
|
|
878
975
|
@current_trace.resolve_type_lazy(query: query, type: type, object: value) do
|
|
879
|
-
schema.sync_lazy(resolved_type)
|
|
976
|
+
rt = schema.sync_lazy(resolved_type)
|
|
977
|
+
@current_trace.end_resolve_type(type, value, context, rt)
|
|
978
|
+
rt
|
|
880
979
|
end
|
|
881
980
|
end
|
|
882
981
|
else
|