graphql 2.4.5 → 2.5.21
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/templates/create_graphql_detailed_traces.erb +10 -0
- data/lib/graphql/analysis/analyzer.rb +2 -1
- data/lib/graphql/analysis/query_complexity.rb +87 -7
- data/lib/graphql/analysis/visitor.rb +37 -40
- data/lib/graphql/analysis.rb +12 -9
- data/lib/graphql/autoload.rb +1 -0
- data/lib/graphql/backtrace/table.rb +118 -55
- data/lib/graphql/backtrace.rb +1 -19
- data/lib/graphql/current.rb +6 -1
- 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 +38 -15
- data/lib/graphql/dataloader/null_dataloader.rb +55 -10
- data/lib/graphql/dataloader/source.rb +18 -6
- data/lib/graphql/dataloader.rb +110 -26
- data/lib/graphql/date_encoding_error.rb +1 -1
- data/lib/graphql/dig.rb +2 -1
- data/lib/graphql/execution/interpreter/resolve.rb +10 -16
- data/lib/graphql/execution/interpreter/runtime/graphql_result.rb +58 -5
- data/lib/graphql/execution/interpreter/runtime.rb +229 -93
- data/lib/graphql/execution/interpreter.rb +15 -24
- data/lib/graphql/execution/multiplex.rb +7 -6
- data/lib/graphql/execution/next/field_resolve_step.rb +690 -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 +69 -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 +11 -3
- 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/type_type.rb +64 -28
- data/lib/graphql/invalid_name_error.rb +1 -1
- data/lib/graphql/invalid_null_error.rb +25 -16
- data/lib/graphql/language/document_from_schema_definition.rb +2 -1
- data/lib/graphql/language/lexer.rb +16 -5
- data/lib/graphql/language/nodes.rb +8 -1
- data/lib/graphql/language/parser.rb +16 -8
- data/lib/graphql/language/static_visitor.rb +37 -33
- data/lib/graphql/language/visitor.rb +59 -55
- data/lib/graphql/language.rb +21 -12
- data/lib/graphql/pagination/connection.rb +2 -0
- data/lib/graphql/pagination/connections.rb +32 -0
- data/lib/graphql/query/context.rb +6 -10
- data/lib/graphql/query/null_context.rb +9 -3
- data/lib/graphql/query/partial.rb +179 -0
- data/lib/graphql/query.rb +64 -64
- data/lib/graphql/railtie.rb +1 -1
- data/lib/graphql/schema/addition.rb +3 -1
- data/lib/graphql/schema/always_visible.rb +1 -0
- data/lib/graphql/schema/argument.rb +24 -8
- data/lib/graphql/schema/build_from_definition.rb +113 -54
- data/lib/graphql/schema/directive/flagged.rb +2 -0
- data/lib/graphql/schema/directive.rb +52 -2
- data/lib/graphql/schema/enum.rb +36 -1
- data/lib/graphql/schema/enum_value.rb +1 -1
- data/lib/graphql/schema/field/connection_extension.rb +15 -35
- data/lib/graphql/schema/field/scope_extension.rb +22 -13
- data/lib/graphql/schema/field.rb +101 -51
- data/lib/graphql/schema/field_extension.rb +33 -0
- data/lib/graphql/schema/input_object.rb +45 -38
- data/lib/graphql/schema/interface.rb +2 -1
- data/lib/graphql/schema/list.rb +1 -1
- data/lib/graphql/schema/member/base_dsl_methods.rb +1 -1
- data/lib/graphql/schema/member/has_arguments.rb +56 -19
- data/lib/graphql/schema/member/has_authorization.rb +35 -0
- data/lib/graphql/schema/member/has_dataloader.rb +79 -0
- data/lib/graphql/schema/member/has_deprecation_reason.rb +15 -0
- data/lib/graphql/schema/member/has_directives.rb +1 -1
- data/lib/graphql/schema/member/has_fields.rb +81 -5
- data/lib/graphql/schema/member/has_interfaces.rb +3 -3
- data/lib/graphql/schema/member/scoped.rb +1 -1
- data/lib/graphql/schema/member/type_system_helpers.rb +17 -3
- data/lib/graphql/schema/member.rb +6 -0
- data/lib/graphql/schema/object.rb +18 -8
- data/lib/graphql/schema/ractor_shareable.rb +79 -0
- data/lib/graphql/schema/resolver.rb +52 -6
- data/lib/graphql/schema/scalar.rb +1 -6
- data/lib/graphql/schema/subscription.rb +50 -4
- data/lib/graphql/schema/timeout.rb +19 -2
- data/lib/graphql/schema/validator/required_validator.rb +71 -14
- data/lib/graphql/schema/visibility/migration.rb +3 -2
- data/lib/graphql/schema/visibility/profile.rb +115 -23
- data/lib/graphql/schema/visibility.rb +49 -32
- data/lib/graphql/schema/warden.rb +23 -2
- data/lib/graphql/schema.rb +333 -68
- data/lib/graphql/static_validation/all_rules.rb +2 -2
- data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +47 -13
- data/lib/graphql/static_validation/rules/fields_will_merge.rb +79 -17
- data/lib/graphql/static_validation/rules/fields_will_merge_error.rb +10 -2
- data/lib/graphql/static_validation/rules/not_single_subscription_error.rb +25 -0
- 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 +6 -2
- data/lib/graphql/static_validation/validator.rb +6 -1
- data/lib/graphql/subscriptions/action_cable_subscriptions.rb +1 -0
- data/lib/graphql/subscriptions/default_subscription_resolve_extension.rb +12 -10
- data/lib/graphql/subscriptions/event.rb +12 -1
- data/lib/graphql/subscriptions/serialize.rb +1 -1
- data/lib/graphql/subscriptions.rb +1 -1
- data/lib/graphql/testing/helpers.rb +17 -11
- 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 +9 -1
- data/lib/graphql/tracing/appoptics_tracing.rb +7 -0
- data/lib/graphql/tracing/appsignal_trace.rb +32 -55
- 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 -158
- 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 +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 +184 -34
- 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_trace.rb +5 -0
- data/lib/graphql/tracing/prometheus_trace/graphql_collector.rb +2 -0
- data/lib/graphql/tracing/prometheus_trace.rb +72 -68
- data/lib/graphql/tracing/prometheus_tracing.rb +2 -0
- data/lib/graphql/tracing/scout_trace.rb +32 -55
- data/lib/graphql/tracing/scout_tracing.rb +2 -0
- data/lib/graphql/tracing/sentry_trace.rb +64 -94
- data/lib/graphql/tracing/statsd_trace.rb +33 -41
- 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 +1 -0
- data/lib/graphql/types/relay/connection_behaviors.rb +9 -7
- data/lib/graphql/types/relay/edge_behaviors.rb +5 -4
- 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/unauthorized_error.rb +5 -1
- data/lib/graphql/version.rb +1 -1
- data/lib/graphql.rb +12 -31
- metadata +174 -11
- data/lib/graphql/backtrace/inspect_result.rb +0 -38
- data/lib/graphql/backtrace/trace.rb +0 -93
- data/lib/graphql/backtrace/tracer.rb +0 -80
- data/lib/graphql/schema/null_mask.rb +0 -11
- data/lib/graphql/static_validation/rules/subscription_root_exists.rb +0 -17
|
@@ -35,11 +35,10 @@ module GraphQL
|
|
|
35
35
|
# @return [GraphQL::Query::Context]
|
|
36
36
|
attr_reader :context
|
|
37
37
|
|
|
38
|
-
def initialize(query
|
|
38
|
+
def initialize(query:)
|
|
39
39
|
@query = query
|
|
40
40
|
@current_trace = query.current_trace
|
|
41
41
|
@dataloader = query.multiplex.dataloader
|
|
42
|
-
@lazies_at_depth = lazies_at_depth
|
|
43
42
|
@schema = query.schema
|
|
44
43
|
@context = query.context
|
|
45
44
|
@response = nil
|
|
@@ -57,67 +56,160 @@ module GraphQL
|
|
|
57
56
|
end
|
|
58
57
|
|
|
59
58
|
def final_result
|
|
60
|
-
@response
|
|
59
|
+
@response.respond_to?(:graphql_result_data) ? @response.graphql_result_data : @response
|
|
61
60
|
end
|
|
62
61
|
|
|
63
62
|
def inspect
|
|
64
63
|
"#<#{self.class.name} response=#{@response.inspect}>"
|
|
65
64
|
end
|
|
66
65
|
|
|
67
|
-
# This _begins_ the execution. Some deferred work
|
|
68
|
-
# might be stored up in lazies.
|
|
69
66
|
# @return [void]
|
|
70
67
|
def run_eager
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
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
|
|
84
82
|
else
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
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
|
|
107
|
+
end
|
|
94
108
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
109
|
+
@dataloader.append_job {
|
|
110
|
+
evaluate_selections(
|
|
111
|
+
selections,
|
|
112
|
+
selection_response,
|
|
113
|
+
final_response,
|
|
114
|
+
nil,
|
|
115
|
+
)
|
|
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
|
|
101
152
|
)
|
|
102
|
-
|
|
153
|
+
end
|
|
103
154
|
end
|
|
104
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})"
|
|
105
195
|
end
|
|
106
196
|
nil
|
|
107
197
|
end
|
|
108
198
|
|
|
109
199
|
def each_gathered_selections(response_hash)
|
|
110
|
-
|
|
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!
|
|
111
203
|
if gathered_selections.is_a?(Array)
|
|
112
204
|
gathered_selections.each do |item|
|
|
113
|
-
yield(item, true)
|
|
205
|
+
yield(item, true, ordered_result_keys)
|
|
114
206
|
end
|
|
115
207
|
else
|
|
116
|
-
yield(gathered_selections, false)
|
|
208
|
+
yield(gathered_selections, false, ordered_result_keys)
|
|
117
209
|
end
|
|
118
210
|
end
|
|
119
211
|
|
|
120
|
-
def gather_selections(owner_object, owner_type, selections, selections_to_run
|
|
212
|
+
def gather_selections(owner_object, owner_type, selections, selections_to_run, selections_by_name, ordered_result_keys)
|
|
121
213
|
selections.each do |node|
|
|
122
214
|
# Skip gathering this if the directive says so
|
|
123
215
|
if !directives_include?(node, owner_object, owner_type)
|
|
@@ -126,6 +218,7 @@ module GraphQL
|
|
|
126
218
|
|
|
127
219
|
if node.is_a?(GraphQL::Language::Nodes::Field)
|
|
128
220
|
response_key = node.alias || node.name
|
|
221
|
+
ordered_result_keys << response_key
|
|
129
222
|
selections = selections_by_name[response_key]
|
|
130
223
|
# if there was already a selection of this field,
|
|
131
224
|
# use an array to hold all selections,
|
|
@@ -162,14 +255,14 @@ module GraphQL
|
|
|
162
255
|
type_defn = query.types.type(node.type.name)
|
|
163
256
|
|
|
164
257
|
if query.types.possible_types(type_defn).include?(owner_type)
|
|
165
|
-
result = gather_selections(owner_object, owner_type, node.selections, selections_to_run, next_selections)
|
|
258
|
+
result = gather_selections(owner_object, owner_type, node.selections, selections_to_run, next_selections, ordered_result_keys)
|
|
166
259
|
if !result.equal?(next_selections)
|
|
167
260
|
selections_to_run = result
|
|
168
261
|
end
|
|
169
262
|
end
|
|
170
263
|
else
|
|
171
264
|
# it's an untyped fragment, definitely continue
|
|
172
|
-
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)
|
|
173
266
|
if !result.equal?(next_selections)
|
|
174
267
|
selections_to_run = result
|
|
175
268
|
end
|
|
@@ -178,7 +271,7 @@ module GraphQL
|
|
|
178
271
|
fragment_def = query.fragments[node.name]
|
|
179
272
|
type_defn = query.types.type(fragment_def.type.name)
|
|
180
273
|
if query.types.possible_types(type_defn).include?(owner_type)
|
|
181
|
-
result = gather_selections(owner_object, owner_type, fragment_def.selections, selections_to_run, next_selections)
|
|
274
|
+
result = gather_selections(owner_object, owner_type, fragment_def.selections, selections_to_run, next_selections, ordered_result_keys)
|
|
182
275
|
if !result.equal?(next_selections)
|
|
183
276
|
selections_to_run = result
|
|
184
277
|
end
|
|
@@ -204,10 +297,7 @@ module GraphQL
|
|
|
204
297
|
end
|
|
205
298
|
|
|
206
299
|
call_method_on_directives(:resolve, selections_result.graphql_application_value, directives) do
|
|
207
|
-
finished_jobs = 0
|
|
208
|
-
enqueued_jobs = gathered_selections.size
|
|
209
300
|
gathered_selections.each do |result_name, field_ast_nodes_or_ast_node|
|
|
210
|
-
|
|
211
301
|
# Field resolution may pause the fiber,
|
|
212
302
|
# so it wouldn't get to the `Resolve` call that happens below.
|
|
213
303
|
# So instead trigger a run from this outer context.
|
|
@@ -217,10 +307,6 @@ module GraphQL
|
|
|
217
307
|
evaluate_selection(
|
|
218
308
|
result_name, field_ast_nodes_or_ast_node, selections_result
|
|
219
309
|
)
|
|
220
|
-
finished_jobs += 1
|
|
221
|
-
if target_result && finished_jobs == enqueued_jobs
|
|
222
|
-
selections_result.merge_into(target_result)
|
|
223
|
-
end
|
|
224
310
|
@dataloader.clear_cache
|
|
225
311
|
}
|
|
226
312
|
else
|
|
@@ -228,13 +314,12 @@ module GraphQL
|
|
|
228
314
|
evaluate_selection(
|
|
229
315
|
result_name, field_ast_nodes_or_ast_node, selections_result
|
|
230
316
|
)
|
|
231
|
-
finished_jobs += 1
|
|
232
|
-
if target_result && finished_jobs == enqueued_jobs
|
|
233
|
-
selections_result.merge_into(target_result)
|
|
234
|
-
end
|
|
235
317
|
}
|
|
236
318
|
end
|
|
237
319
|
end
|
|
320
|
+
if target_result
|
|
321
|
+
selections_result.merge_into(target_result)
|
|
322
|
+
end
|
|
238
323
|
selections_result
|
|
239
324
|
end
|
|
240
325
|
end
|
|
@@ -279,6 +364,10 @@ module GraphQL
|
|
|
279
364
|
else
|
|
280
365
|
@query.arguments_cache.dataload_for(ast_node, field_defn, owner_object) do |resolved_arguments|
|
|
281
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
|
|
282
371
|
evaluate_selection_with_args(resolved_arguments, field_defn, ast_node, field_ast_nodes, owner_object, result_name, selections_result, runtime_state)
|
|
283
372
|
end
|
|
284
373
|
end
|
|
@@ -287,6 +376,8 @@ module GraphQL
|
|
|
287
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
|
|
288
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|
|
|
289
378
|
if resolved_arguments.is_a?(GraphQL::ExecutionError) || resolved_arguments.is_a?(GraphQL::UnauthorizedError)
|
|
379
|
+
next if selection_result.collect_result(result_name, resolved_arguments)
|
|
380
|
+
|
|
290
381
|
return_type_non_null = field_defn.type.non_null?
|
|
291
382
|
continue_value(resolved_arguments, field_defn, return_type_non_null, ast_node, result_name, selection_result)
|
|
292
383
|
next
|
|
@@ -360,7 +451,7 @@ module GraphQL
|
|
|
360
451
|
}
|
|
361
452
|
end
|
|
362
453
|
|
|
363
|
-
|
|
454
|
+
call_method_on_directives(:resolve, object, directives) do
|
|
364
455
|
if !directives.empty?
|
|
365
456
|
# This might be executed in a different context; reset this info
|
|
366
457
|
runtime_state = get_current_runtime_state
|
|
@@ -371,6 +462,7 @@ module GraphQL
|
|
|
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,7 +475,10 @@ 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|
|
|
480
|
+
next if selection_result.collect_result(result_name, inner_result)
|
|
481
|
+
|
|
387
482
|
owner_type = selection_result.graphql_result_type
|
|
388
483
|
return_type = field_defn.type
|
|
389
484
|
continue_value = continue_value(inner_result, field_defn, return_type.non_null?, ast_node, result_name, selection_result)
|
|
@@ -391,6 +486,8 @@ module GraphQL
|
|
|
391
486
|
was_scoped = runtime_state.was_authorized_by_scope_items
|
|
392
487
|
runtime_state.was_authorized_by_scope_items = nil
|
|
393
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
|
|
394
491
|
end
|
|
395
492
|
end
|
|
396
493
|
end
|
|
@@ -398,7 +495,7 @@ module GraphQL
|
|
|
398
495
|
# all of its child fields before moving on to the next root mutation field.
|
|
399
496
|
# (Subselections of this mutation will still be resolved level-by-level.)
|
|
400
497
|
if selection_result.graphql_is_eager
|
|
401
|
-
|
|
498
|
+
@dataloader.run
|
|
402
499
|
end
|
|
403
500
|
end
|
|
404
501
|
|
|
@@ -456,16 +553,17 @@ module GraphQL
|
|
|
456
553
|
path
|
|
457
554
|
end
|
|
458
555
|
|
|
459
|
-
HALT = Object.new
|
|
556
|
+
HALT = Object.new.freeze
|
|
460
557
|
def continue_value(value, field, is_non_null, ast_node, result_name, selection_result) # rubocop:disable Metrics/ParameterLists
|
|
461
558
|
case value
|
|
462
559
|
when nil
|
|
463
560
|
if is_non_null
|
|
464
561
|
set_result(selection_result, result_name, nil, false, is_non_null) do
|
|
465
562
|
# When this comes from a list item, use the parent object:
|
|
466
|
-
|
|
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
|
|
467
565
|
# This block is called if `result_name` is not dead. (Maybe a previous invalid nil caused it be marked dead.)
|
|
468
|
-
err = parent_type::InvalidNullError.new(parent_type, field,
|
|
566
|
+
err = parent_type::InvalidNullError.new(parent_type, field, ast_node, is_from_array: is_from_array)
|
|
469
567
|
schema.type_error(err, context)
|
|
470
568
|
end
|
|
471
569
|
else
|
|
@@ -573,13 +671,29 @@ module GraphQL
|
|
|
573
671
|
when "SCALAR", "ENUM"
|
|
574
672
|
r = begin
|
|
575
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)
|
|
576
676
|
rescue StandardError => err
|
|
577
|
-
|
|
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
|
|
578
682
|
end
|
|
579
683
|
set_result(selection_result, result_name, r, false, is_non_null)
|
|
580
684
|
r
|
|
581
685
|
when "UNION", "INTERFACE"
|
|
582
|
-
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
|
|
583
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|
|
|
584
698
|
if resolved_type_result.is_a?(Array) && resolved_type_result.length == 2
|
|
585
699
|
resolved_type, resolved_value = resolved_type_result
|
|
@@ -609,11 +723,13 @@ module GraphQL
|
|
|
609
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|
|
|
610
724
|
continue_value = continue_value(inner_object, field, is_non_null, ast_node, result_name, selection_result)
|
|
611
725
|
if HALT != continue_value
|
|
612
|
-
response_hash = GraphQLResultHash.new(result_name, current_type, continue_value, selection_result, is_non_null, next_selections, false)
|
|
726
|
+
response_hash = GraphQLResultHash.new(result_name, current_type, continue_value, selection_result, is_non_null, next_selections, false, ast_node, arguments, field)
|
|
613
727
|
set_result(selection_result, result_name, response_hash, true, is_non_null)
|
|
614
|
-
each_gathered_selections(response_hash) 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
|
|
615
730
|
if is_selection_array
|
|
616
|
-
this_result = GraphQLResultHash.new(result_name, current_type, continue_value, selection_result, is_non_null, selections, false)
|
|
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
|
|
617
733
|
final_result = response_hash
|
|
618
734
|
else
|
|
619
735
|
this_result = response_hash
|
|
@@ -634,35 +750,43 @@ module GraphQL
|
|
|
634
750
|
# This is true for objects, unions, and interfaces
|
|
635
751
|
use_dataloader_job = !inner_type.unwrap.kind.input?
|
|
636
752
|
inner_type_non_null = inner_type.non_null?
|
|
637
|
-
response_list = GraphQLResultArray.new(result_name, current_type, owner_object, selection_result, is_non_null, next_selections, false)
|
|
753
|
+
response_list = GraphQLResultArray.new(result_name, current_type, owner_object, selection_result, is_non_null, next_selections, false, ast_node, arguments, field)
|
|
638
754
|
set_result(selection_result, result_name, response_list, true, is_non_null)
|
|
639
755
|
idx = nil
|
|
640
756
|
list_value = begin
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
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
|
|
647
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)
|
|
648
768
|
end
|
|
649
|
-
else
|
|
650
|
-
resolve_list_item(inner_value, inner_type, inner_type_non_null, ast_node, field, owner_object, arguments, this_idx, response_list, owner_type, was_scoped, runtime_state)
|
|
651
769
|
end
|
|
652
|
-
end
|
|
653
770
|
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
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
|
|
663
789
|
end
|
|
664
|
-
rescue GraphQL::ExecutionError, GraphQL::UnauthorizedError => ex_err
|
|
665
|
-
ex_err
|
|
666
790
|
rescue StandardError => err
|
|
667
791
|
begin
|
|
668
792
|
query.handle_or_reraise(err)
|
|
@@ -704,6 +828,13 @@ module GraphQL
|
|
|
704
828
|
else
|
|
705
829
|
dir_defn = @schema_directives.fetch(dir_node.name)
|
|
706
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
|
|
707
838
|
dir_args = continue_value(
|
|
708
839
|
raw_dir_args, # value
|
|
709
840
|
nil, # field
|
|
@@ -759,7 +890,6 @@ module GraphQL
|
|
|
759
890
|
# @return [GraphQL::Execution::Lazy, Object] If loading `object` will be deferred, it's a wrapper over it.
|
|
760
891
|
def after_lazy(lazy_obj, field:, owner_object:, arguments:, ast_node:, result:, result_name:, eager: false, runtime_state:, trace: true, &block)
|
|
761
892
|
if lazy?(lazy_obj)
|
|
762
|
-
orig_result = result
|
|
763
893
|
was_authorized_by_scope_items = runtime_state.was_authorized_by_scope_items
|
|
764
894
|
lazy = GraphQL::Execution::Lazy.new(field: field) do
|
|
765
895
|
# This block might be called in a new fiber;
|
|
@@ -769,12 +899,14 @@ module GraphQL
|
|
|
769
899
|
runtime_state.current_field = field
|
|
770
900
|
runtime_state.current_arguments = arguments
|
|
771
901
|
runtime_state.current_result_name = result_name
|
|
772
|
-
runtime_state.current_result =
|
|
902
|
+
runtime_state.current_result = result
|
|
773
903
|
runtime_state.was_authorized_by_scope_items = was_authorized_by_scope_items
|
|
774
904
|
# Wrap the execution of _this_ method with tracing,
|
|
775
905
|
# but don't wrap the continuation below
|
|
906
|
+
sync_result = nil
|
|
776
907
|
inner_obj = begin
|
|
777
|
-
if trace
|
|
908
|
+
sync_result = if trace
|
|
909
|
+
@current_trace.begin_execute_field(field, owner_object, arguments, query)
|
|
778
910
|
@current_trace.execute_field_lazy(field: field, query: query, object: owner_object, arguments: arguments, ast_node: ast_node) do
|
|
779
911
|
schema.sync_lazy(lazy_obj)
|
|
780
912
|
end
|
|
@@ -789,6 +921,10 @@ module GraphQL
|
|
|
789
921
|
rescue GraphQL::ExecutionError => ex_err
|
|
790
922
|
ex_err
|
|
791
923
|
end
|
|
924
|
+
ensure
|
|
925
|
+
if trace
|
|
926
|
+
@current_trace.end_execute_field(field, owner_object, arguments, query, sync_result)
|
|
927
|
+
end
|
|
792
928
|
end
|
|
793
929
|
yield(inner_obj, runtime_state)
|
|
794
930
|
end
|
|
@@ -797,12 +933,7 @@ module GraphQL
|
|
|
797
933
|
lazy.value
|
|
798
934
|
else
|
|
799
935
|
set_result(result, result_name, lazy, false, false) # is_non_null is irrelevant here
|
|
800
|
-
|
|
801
|
-
while result
|
|
802
|
-
current_depth += 1
|
|
803
|
-
result = result.graphql_parent
|
|
804
|
-
end
|
|
805
|
-
@lazies_at_depth[current_depth] << lazy
|
|
936
|
+
@dataloader.lazy_at_depth(result.depth, lazy)
|
|
806
937
|
lazy
|
|
807
938
|
end
|
|
808
939
|
else
|
|
@@ -832,14 +963,19 @@ module GraphQL
|
|
|
832
963
|
end
|
|
833
964
|
|
|
834
965
|
def resolve_type(type, value)
|
|
966
|
+
@current_trace.begin_resolve_type(type, value, context)
|
|
835
967
|
resolved_type, resolved_value = @current_trace.resolve_type(query: query, type: type, object: value) do
|
|
836
968
|
query.resolve_type(type, value)
|
|
837
969
|
end
|
|
970
|
+
@current_trace.end_resolve_type(type, value, context, resolved_type)
|
|
838
971
|
|
|
839
972
|
if lazy?(resolved_type)
|
|
840
973
|
GraphQL::Execution::Lazy.new do
|
|
974
|
+
@current_trace.begin_resolve_type(type, value, context)
|
|
841
975
|
@current_trace.resolve_type_lazy(query: query, type: type, object: value) do
|
|
842
|
-
schema.sync_lazy(resolved_type)
|
|
976
|
+
rt = schema.sync_lazy(resolved_type)
|
|
977
|
+
@current_trace.end_resolve_type(type, value, context, rt)
|
|
978
|
+
rt
|
|
843
979
|
end
|
|
844
980
|
end
|
|
845
981
|
else
|
|
@@ -23,28 +23,34 @@ module GraphQL
|
|
|
23
23
|
# @return [Array<GraphQL::Query::Result>] One result per query
|
|
24
24
|
def run_all(schema, query_options, context: {}, max_complexity: schema.max_complexity)
|
|
25
25
|
queries = query_options.map do |opts|
|
|
26
|
-
case opts
|
|
26
|
+
query = case opts
|
|
27
27
|
when Hash
|
|
28
28
|
schema.query_class.new(schema, nil, **opts)
|
|
29
|
-
when GraphQL::Query
|
|
29
|
+
when GraphQL::Query, GraphQL::Query::Partial
|
|
30
30
|
opts
|
|
31
31
|
else
|
|
32
32
|
raise "Expected Hash or GraphQL::Query, not #{opts.class} (#{opts.inspect})"
|
|
33
33
|
end
|
|
34
|
+
query
|
|
34
35
|
end
|
|
35
36
|
|
|
37
|
+
return GraphQL::EmptyObjects::EMPTY_ARRAY if queries.empty?
|
|
38
|
+
|
|
36
39
|
multiplex = Execution::Multiplex.new(schema: schema, queries: queries, context: context, max_complexity: max_complexity)
|
|
40
|
+
trace = multiplex.current_trace
|
|
37
41
|
Fiber[:__graphql_current_multiplex] = multiplex
|
|
38
|
-
|
|
42
|
+
trace.execute_multiplex(multiplex: multiplex) do
|
|
39
43
|
schema = multiplex.schema
|
|
40
44
|
queries = multiplex.queries
|
|
41
|
-
lazies_at_depth = Hash.new { |h, k| h[k] = [] }
|
|
42
45
|
multiplex_analyzers = schema.multiplex_analyzers
|
|
43
46
|
if multiplex.max_complexity
|
|
44
47
|
multiplex_analyzers += [GraphQL::Analysis::MaxQueryComplexity]
|
|
45
48
|
end
|
|
46
49
|
|
|
50
|
+
trace.begin_analyze_multiplex(multiplex, multiplex_analyzers)
|
|
47
51
|
schema.analysis_engine.analyze_multiplex(multiplex, multiplex_analyzers)
|
|
52
|
+
trace.end_analyze_multiplex(multiplex, multiplex_analyzers)
|
|
53
|
+
|
|
48
54
|
begin
|
|
49
55
|
# Since this is basically the batching context,
|
|
50
56
|
# share it for a whole multiplex
|
|
@@ -53,7 +59,9 @@ module GraphQL
|
|
|
53
59
|
results = []
|
|
54
60
|
queries.each_with_index do |query, idx|
|
|
55
61
|
if query.subscription? && !query.subscription_update?
|
|
56
|
-
query.context.namespace(:subscriptions)
|
|
62
|
+
subs_namespace = query.context.namespace(:subscriptions)
|
|
63
|
+
subs_namespace[:events] = []
|
|
64
|
+
subs_namespace[:subscriptions] = {}
|
|
57
65
|
end
|
|
58
66
|
multiplex.dataloader.append_job {
|
|
59
67
|
operation = query.selected_operation
|
|
@@ -64,7 +72,7 @@ module GraphQL
|
|
|
64
72
|
# Although queries in a multiplex _share_ an Interpreter instance,
|
|
65
73
|
# they also have another item of state, which is private to that query
|
|
66
74
|
# in particular, assign it here:
|
|
67
|
-
runtime = Runtime.new(query: query
|
|
75
|
+
runtime = Runtime.new(query: query)
|
|
68
76
|
query.context.namespace(:interpreter_runtime)[:runtime] = runtime
|
|
69
77
|
|
|
70
78
|
query.current_trace.execute_query(query: query) do
|
|
@@ -72,30 +80,13 @@ module GraphQL
|
|
|
72
80
|
end
|
|
73
81
|
rescue GraphQL::ExecutionError => err
|
|
74
82
|
query.context.errors << err
|
|
75
|
-
NO_OPERATION
|
|
76
83
|
end
|
|
77
84
|
end
|
|
78
85
|
results[idx] = result
|
|
79
86
|
}
|
|
80
87
|
end
|
|
81
88
|
|
|
82
|
-
multiplex.dataloader.run
|
|
83
|
-
|
|
84
|
-
# Then, work through lazy results in a breadth-first way
|
|
85
|
-
multiplex.dataloader.append_job {
|
|
86
|
-
query = multiplex.queries.length == 1 ? multiplex.queries[0] : nil
|
|
87
|
-
queries = multiplex ? multiplex.queries : [query]
|
|
88
|
-
final_values = queries.map do |query|
|
|
89
|
-
runtime = query.context.namespace(:interpreter_runtime)[:runtime]
|
|
90
|
-
# it might not be present if the query has an error
|
|
91
|
-
runtime ? runtime.final_result : nil
|
|
92
|
-
end
|
|
93
|
-
final_values.compact!
|
|
94
|
-
multiplex.current_trace.execute_query_lazy(multiplex: multiplex, query: query) do
|
|
95
|
-
Interpreter::Resolve.resolve_each_depth(lazies_at_depth, multiplex.dataloader)
|
|
96
|
-
end
|
|
97
|
-
}
|
|
98
|
-
multiplex.dataloader.run
|
|
89
|
+
multiplex.dataloader.run(trace_query_lazy: multiplex)
|
|
99
90
|
|
|
100
91
|
# Then, find all errors and assign the result to the query object
|
|
101
92
|
results.each_with_index do |data_result, idx|
|