graphql 1.13.10 → 2.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/graphql/analysis/ast/max_query_complexity.rb +0 -1
- data/lib/graphql/analysis/ast/query_complexity.rb +1 -1
- data/lib/graphql/analysis/ast/query_depth.rb +0 -1
- data/lib/graphql/analysis/ast/visitor.rb +1 -1
- data/lib/graphql/analysis/ast.rb +0 -10
- data/lib/graphql/analysis.rb +0 -7
- data/lib/graphql/backtrace/table.rb +0 -18
- data/lib/graphql/backtrace/tracer.rb +1 -2
- data/lib/graphql/backtrace.rb +2 -8
- data/lib/graphql/dataloader/null_dataloader.rb +3 -1
- data/lib/graphql/dig.rb +1 -1
- data/lib/graphql/execution/errors.rb +1 -9
- data/lib/graphql/execution/interpreter/runtime.rb +17 -31
- data/lib/graphql/execution/interpreter.rb +0 -22
- data/lib/graphql/execution/lazy.rb +1 -1
- data/lib/graphql/execution/lookahead.rb +6 -13
- data/lib/graphql/execution/multiplex.rb +50 -107
- data/lib/graphql/execution.rb +11 -3
- data/lib/graphql/introspection/dynamic_fields.rb +3 -8
- data/lib/graphql/introspection/entry_points.rb +2 -15
- data/lib/graphql/language/document_from_schema_definition.rb +0 -17
- data/lib/graphql/pagination/connections.rb +2 -28
- data/lib/graphql/query/context.rb +97 -194
- data/lib/graphql/query/input_validation_result.rb +10 -1
- data/lib/graphql/query/validation_pipeline.rb +8 -37
- data/lib/graphql/query/variables.rb +22 -18
- data/lib/graphql/query.rb +5 -36
- data/lib/graphql/railtie.rb +0 -104
- data/lib/graphql/relay.rb +0 -15
- data/lib/graphql/schema/addition.rb +1 -8
- data/lib/graphql/schema/argument.rb +5 -26
- data/lib/graphql/schema/build_from_definition.rb +0 -1
- data/lib/graphql/schema/directive.rb +0 -21
- data/lib/graphql/schema/enum.rb +4 -23
- data/lib/graphql/schema/enum_value.rb +0 -22
- data/lib/graphql/schema/field.rb +70 -230
- data/lib/graphql/schema/input_object.rb +21 -68
- data/lib/graphql/schema/interface.rb +0 -25
- data/lib/graphql/schema/introspection_system.rb +3 -8
- data/lib/graphql/schema/late_bound_type.rb +2 -2
- data/lib/graphql/schema/list.rb +2 -7
- data/lib/graphql/schema/loader.rb +0 -1
- data/lib/graphql/schema/member/base_dsl_methods.rb +0 -5
- data/lib/graphql/schema/member/build_type.rb +4 -6
- data/lib/graphql/schema/member/has_arguments.rb +50 -24
- data/lib/graphql/schema/member/has_fields.rb +2 -2
- data/lib/graphql/schema/member/has_interfaces.rb +1 -3
- data/lib/graphql/schema/member/validates_input.rb +2 -2
- data/lib/graphql/schema/member.rb +0 -6
- data/lib/graphql/schema/mutation.rb +0 -9
- data/lib/graphql/schema/non_null.rb +1 -7
- data/lib/graphql/schema/object.rb +7 -42
- data/lib/graphql/schema/relay_classic_mutation.rb +49 -42
- data/lib/graphql/schema/resolver/has_payload_type.rb +11 -1
- data/lib/graphql/schema/resolver.rb +23 -45
- data/lib/graphql/schema/scalar.rb +4 -19
- data/lib/graphql/schema/subscription.rb +0 -7
- data/lib/graphql/schema/union.rb +0 -16
- data/lib/graphql/schema/warden.rb +2 -2
- data/lib/graphql/schema/wrapper.rb +0 -5
- data/lib/graphql/schema.rb +106 -944
- data/lib/graphql/static_validation/base_visitor.rb +4 -21
- data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +12 -12
- data/lib/graphql/static_validation/validator.rb +2 -24
- data/lib/graphql/static_validation.rb +0 -2
- data/lib/graphql/subscriptions/default_subscription_resolve_extension.rb +38 -1
- data/lib/graphql/subscriptions/event.rb +1 -1
- data/lib/graphql/subscriptions/instrumentation.rb +0 -51
- data/lib/graphql/subscriptions.rb +14 -16
- data/lib/graphql/tracing/platform_tracing.rb +0 -23
- data/lib/graphql/tracing.rb +0 -1
- data/lib/graphql/types/relay/connection_behaviors.rb +2 -6
- data/lib/graphql/types/relay/default_relay.rb +0 -10
- data/lib/graphql/types/relay/node_behaviors.rb +5 -1
- data/lib/graphql/types/relay.rb +0 -2
- data/lib/graphql/version.rb +1 -1
- data/lib/graphql.rb +1 -65
- metadata +2 -128
- data/lib/graphql/analysis/analyze_query.rb +0 -98
- data/lib/graphql/analysis/field_usage.rb +0 -45
- data/lib/graphql/analysis/max_query_complexity.rb +0 -26
- data/lib/graphql/analysis/max_query_depth.rb +0 -26
- data/lib/graphql/analysis/query_complexity.rb +0 -88
- data/lib/graphql/analysis/query_depth.rb +0 -43
- data/lib/graphql/analysis/reducer_state.rb +0 -48
- data/lib/graphql/argument.rb +0 -131
- data/lib/graphql/authorization.rb +0 -82
- data/lib/graphql/backtrace/legacy_tracer.rb +0 -56
- data/lib/graphql/backwards_compatibility.rb +0 -61
- data/lib/graphql/base_type.rb +0 -232
- data/lib/graphql/boolean_type.rb +0 -2
- data/lib/graphql/compatibility/execution_specification/counter_schema.rb +0 -53
- data/lib/graphql/compatibility/execution_specification/specification_schema.rb +0 -200
- data/lib/graphql/compatibility/execution_specification.rb +0 -436
- data/lib/graphql/compatibility/lazy_execution_specification/lazy_schema.rb +0 -111
- data/lib/graphql/compatibility/lazy_execution_specification.rb +0 -215
- data/lib/graphql/compatibility/query_parser_specification/parse_error_specification.rb +0 -87
- data/lib/graphql/compatibility/query_parser_specification/query_assertions.rb +0 -79
- data/lib/graphql/compatibility/query_parser_specification.rb +0 -266
- data/lib/graphql/compatibility/schema_parser_specification.rb +0 -682
- data/lib/graphql/compatibility.rb +0 -5
- data/lib/graphql/define/assign_argument.rb +0 -12
- data/lib/graphql/define/assign_connection.rb +0 -13
- data/lib/graphql/define/assign_enum_value.rb +0 -18
- data/lib/graphql/define/assign_global_id_field.rb +0 -11
- data/lib/graphql/define/assign_mutation_function.rb +0 -34
- data/lib/graphql/define/assign_object_field.rb +0 -42
- data/lib/graphql/define/defined_object_proxy.rb +0 -53
- data/lib/graphql/define/instance_definable.rb +0 -240
- data/lib/graphql/define/no_definition_error.rb +0 -7
- data/lib/graphql/define/non_null_with_bang.rb +0 -16
- data/lib/graphql/define/type_definer.rb +0 -31
- data/lib/graphql/define.rb +0 -31
- data/lib/graphql/deprecated_dsl.rb +0 -55
- data/lib/graphql/directive/deprecated_directive.rb +0 -2
- data/lib/graphql/directive/include_directive.rb +0 -2
- data/lib/graphql/directive/skip_directive.rb +0 -2
- data/lib/graphql/directive.rb +0 -107
- data/lib/graphql/enum_type.rb +0 -133
- data/lib/graphql/execution/execute.rb +0 -333
- data/lib/graphql/execution/flatten.rb +0 -40
- data/lib/graphql/execution/typecast.rb +0 -50
- data/lib/graphql/field/resolve.rb +0 -59
- data/lib/graphql/field.rb +0 -226
- data/lib/graphql/float_type.rb +0 -2
- data/lib/graphql/function.rb +0 -128
- data/lib/graphql/id_type.rb +0 -2
- data/lib/graphql/input_object_type.rb +0 -138
- data/lib/graphql/int_type.rb +0 -2
- data/lib/graphql/interface_type.rb +0 -72
- data/lib/graphql/internal_representation/document.rb +0 -27
- data/lib/graphql/internal_representation/node.rb +0 -206
- data/lib/graphql/internal_representation/print.rb +0 -51
- data/lib/graphql/internal_representation/rewrite.rb +0 -184
- data/lib/graphql/internal_representation/scope.rb +0 -88
- data/lib/graphql/internal_representation/visit.rb +0 -36
- data/lib/graphql/internal_representation.rb +0 -7
- data/lib/graphql/list_type.rb +0 -80
- data/lib/graphql/non_null_type.rb +0 -71
- data/lib/graphql/object_type.rb +0 -130
- data/lib/graphql/query/arguments.rb +0 -189
- data/lib/graphql/query/arguments_cache.rb +0 -24
- data/lib/graphql/query/executor.rb +0 -52
- data/lib/graphql/query/literal_input.rb +0 -136
- data/lib/graphql/query/serial_execution/field_resolution.rb +0 -92
- data/lib/graphql/query/serial_execution/operation_resolution.rb +0 -19
- data/lib/graphql/query/serial_execution/selection_resolution.rb +0 -23
- data/lib/graphql/query/serial_execution/value_resolution.rb +0 -87
- data/lib/graphql/query/serial_execution.rb +0 -40
- data/lib/graphql/relay/array_connection.rb +0 -83
- data/lib/graphql/relay/base_connection.rb +0 -189
- data/lib/graphql/relay/connection_instrumentation.rb +0 -54
- data/lib/graphql/relay/connection_resolve.rb +0 -43
- data/lib/graphql/relay/connection_type.rb +0 -54
- data/lib/graphql/relay/edge.rb +0 -27
- data/lib/graphql/relay/edge_type.rb +0 -19
- data/lib/graphql/relay/edges_instrumentation.rb +0 -39
- data/lib/graphql/relay/global_id_resolve.rb +0 -17
- data/lib/graphql/relay/mongo_relation_connection.rb +0 -50
- data/lib/graphql/relay/mutation/instrumentation.rb +0 -23
- data/lib/graphql/relay/mutation/resolve.rb +0 -56
- data/lib/graphql/relay/mutation/result.rb +0 -38
- data/lib/graphql/relay/mutation.rb +0 -106
- data/lib/graphql/relay/node.rb +0 -39
- data/lib/graphql/relay/page_info.rb +0 -7
- data/lib/graphql/relay/relation_connection.rb +0 -188
- data/lib/graphql/relay/type_extensions.rb +0 -32
- data/lib/graphql/scalar_type.rb +0 -91
- data/lib/graphql/schema/catchall_middleware.rb +0 -35
- data/lib/graphql/schema/default_parse_error.rb +0 -10
- data/lib/graphql/schema/default_type_error.rb +0 -17
- data/lib/graphql/schema/member/accepts_definition.rb +0 -164
- data/lib/graphql/schema/member/cached_graphql_definition.rb +0 -58
- data/lib/graphql/schema/member/instrumentation.rb +0 -131
- data/lib/graphql/schema/middleware_chain.rb +0 -82
- data/lib/graphql/schema/possible_types.rb +0 -44
- data/lib/graphql/schema/rescue_middleware.rb +0 -60
- data/lib/graphql/schema/timeout_middleware.rb +0 -88
- data/lib/graphql/schema/traversal.rb +0 -228
- data/lib/graphql/schema/validation.rb +0 -313
- data/lib/graphql/static_validation/default_visitor.rb +0 -15
- data/lib/graphql/static_validation/no_validate_visitor.rb +0 -10
- data/lib/graphql/string_type.rb +0 -2
- data/lib/graphql/subscriptions/subscription_root.rb +0 -76
- data/lib/graphql/tracing/skylight_tracing.rb +0 -70
- data/lib/graphql/types/relay/node_field.rb +0 -24
- data/lib/graphql/types/relay/nodes_field.rb +0 -43
- data/lib/graphql/union_type.rb +0 -115
- data/lib/graphql/upgrader/member.rb +0 -937
- data/lib/graphql/upgrader/schema.rb +0 -38
|
@@ -5,49 +5,10 @@ module GraphQL
|
|
|
5
5
|
# It delegates `[]` to the hash that's passed to `GraphQL::Query#initialize`.
|
|
6
6
|
class Context
|
|
7
7
|
module SharedMethods
|
|
8
|
-
# @return [Object] The target for field resolution
|
|
9
|
-
attr_accessor :object
|
|
10
|
-
|
|
11
|
-
# @return [Hash, Array, String, Integer, Float, Boolean, nil] The resolved value for this field
|
|
12
|
-
attr_reader :value
|
|
13
|
-
|
|
14
|
-
# @return [Boolean] were any fields of this selection skipped?
|
|
15
|
-
attr_reader :skipped
|
|
16
|
-
alias :skipped? :skipped
|
|
17
|
-
|
|
18
|
-
# @api private
|
|
19
|
-
attr_writer :skipped
|
|
20
|
-
|
|
21
8
|
# Return this value to tell the runtime
|
|
22
9
|
# to exclude this field from the response altogether
|
|
23
10
|
def skip
|
|
24
|
-
GraphQL::Execution::
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
# @return [Boolean] True if this selection has been nullified by a null child
|
|
28
|
-
def invalid_null?
|
|
29
|
-
@invalid_null
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
# Remove this child from the result value
|
|
33
|
-
# (used for null propagation and skip)
|
|
34
|
-
# @api private
|
|
35
|
-
def delete_child(child_ctx)
|
|
36
|
-
@value.delete(child_ctx.key)
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
# Create a child context to use for `key`
|
|
40
|
-
# @param key [String, Integer] The key in the response (name or index)
|
|
41
|
-
# @param irep_node [InternalRepresentation::Node] The node being evaluated
|
|
42
|
-
# @api private
|
|
43
|
-
def spawn_child(key:, irep_node:, object:)
|
|
44
|
-
FieldResolutionContext.new(
|
|
45
|
-
@context,
|
|
46
|
-
key,
|
|
47
|
-
irep_node,
|
|
48
|
-
self,
|
|
49
|
-
object
|
|
50
|
-
)
|
|
11
|
+
GraphQL::Execution::SKIP
|
|
51
12
|
end
|
|
52
13
|
|
|
53
14
|
# Add error at query-level.
|
|
@@ -72,12 +33,6 @@ module GraphQL
|
|
|
72
33
|
def execution_errors
|
|
73
34
|
@execution_errors ||= ExecutionErrors.new(self)
|
|
74
35
|
end
|
|
75
|
-
|
|
76
|
-
def lookahead
|
|
77
|
-
ast_nodes = irep_node.ast_nodes
|
|
78
|
-
field = irep_node.definition.metadata[:type_class] || raise("Lookahead is only compatible with class-based schemas")
|
|
79
|
-
Execution::Lookahead.new(query: query, ast_nodes: ast_nodes, field: field)
|
|
80
|
-
end
|
|
81
36
|
end
|
|
82
37
|
|
|
83
38
|
class ExecutionErrors
|
|
@@ -105,27 +60,6 @@ module GraphQL
|
|
|
105
60
|
include SharedMethods
|
|
106
61
|
extend Forwardable
|
|
107
62
|
|
|
108
|
-
attr_reader :execution_strategy
|
|
109
|
-
# `strategy` is required by GraphQL::Batch
|
|
110
|
-
alias_method :strategy, :execution_strategy
|
|
111
|
-
|
|
112
|
-
def execution_strategy=(new_strategy)
|
|
113
|
-
# GraphQL::Batch re-assigns this value but it was previously not used
|
|
114
|
-
# (ExecutionContext#strategy was used instead)
|
|
115
|
-
# now it _is_ used, but it breaks GraphQL::Batch tests
|
|
116
|
-
@execution_strategy ||= new_strategy
|
|
117
|
-
end
|
|
118
|
-
|
|
119
|
-
# @return [GraphQL::InternalRepresentation::Node] The internal representation for this query node
|
|
120
|
-
def irep_node
|
|
121
|
-
@irep_node ||= query.irep_selection
|
|
122
|
-
end
|
|
123
|
-
|
|
124
|
-
# @return [GraphQL::Language::Nodes::Field] The AST node for the currently-executing field
|
|
125
|
-
def ast_node
|
|
126
|
-
@irep_node.ast_node
|
|
127
|
-
end
|
|
128
|
-
|
|
129
63
|
# @return [Array<GraphQL::ExecutionError>] errors returned during execution
|
|
130
64
|
attr_reader :errors
|
|
131
65
|
|
|
@@ -152,8 +86,83 @@ module GraphQL
|
|
|
152
86
|
@errors = []
|
|
153
87
|
@path = []
|
|
154
88
|
@value = nil
|
|
155
|
-
@context = self # for SharedMethods
|
|
156
|
-
@scoped_context =
|
|
89
|
+
@context = self # for SharedMethods TODO delete sharedmethods
|
|
90
|
+
@scoped_context = ScopedContext.new(self)
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
class ScopedContext
|
|
94
|
+
def initialize(query_context)
|
|
95
|
+
@query_context = query_context
|
|
96
|
+
@path_contexts = {}
|
|
97
|
+
@no_path = [].freeze
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def merged_context
|
|
101
|
+
merged_ctx = {}
|
|
102
|
+
each_present_path_ctx do |path_ctx|
|
|
103
|
+
merged_ctx = path_ctx.merge(merged_ctx)
|
|
104
|
+
end
|
|
105
|
+
merged_ctx
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def merge!(hash)
|
|
109
|
+
current_ctx = @path_contexts[current_path] ||= {}
|
|
110
|
+
current_ctx.merge!(hash)
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def current_path
|
|
114
|
+
@query_context.namespace(:interpreter)[:current_path] || @no_path
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def key?(key)
|
|
118
|
+
each_present_path_ctx do |path_ctx|
|
|
119
|
+
if path_ctx.key?(key)
|
|
120
|
+
return true
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
false
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def [](key)
|
|
127
|
+
each_present_path_ctx do |path_ctx|
|
|
128
|
+
if path_ctx.key?(key)
|
|
129
|
+
return path_ctx[key]
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
nil
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def dig(key, *other_keys)
|
|
136
|
+
each_present_path_ctx do |path_ctx|
|
|
137
|
+
if path_ctx.key?(key)
|
|
138
|
+
found_value = path_ctx[key]
|
|
139
|
+
if other_keys.any?
|
|
140
|
+
return found_value.dig(*other_keys)
|
|
141
|
+
else
|
|
142
|
+
return found_value
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
nil
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
private
|
|
150
|
+
|
|
151
|
+
# Start at the current location,
|
|
152
|
+
# but look up the tree for previously-assigned scoped values
|
|
153
|
+
def each_present_path_ctx
|
|
154
|
+
search_path = current_path.dup
|
|
155
|
+
if (current_path_ctx = @path_contexts[search_path])
|
|
156
|
+
yield(current_path_ctx)
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
while search_path.size > 0
|
|
160
|
+
search_path.pop # look one level higher
|
|
161
|
+
if (search_path_ctx = @path_contexts[search_path])
|
|
162
|
+
yield(search_path_ctx)
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
end
|
|
157
166
|
end
|
|
158
167
|
|
|
159
168
|
# @return [Hash] A hash that will be added verbatim to the result hash, as `"extensions" => { ... }`
|
|
@@ -172,7 +181,7 @@ module GraphQL
|
|
|
172
181
|
attr_writer :value
|
|
173
182
|
|
|
174
183
|
# @api private
|
|
175
|
-
|
|
184
|
+
attr_reader :scoped_context
|
|
176
185
|
|
|
177
186
|
def []=(key, value)
|
|
178
187
|
@provided_values[key] = value
|
|
@@ -185,8 +194,11 @@ module GraphQL
|
|
|
185
194
|
|
|
186
195
|
# Lookup `key` from the hash passed to {Schema#execute} as `context:`
|
|
187
196
|
def [](key)
|
|
188
|
-
|
|
189
|
-
|
|
197
|
+
if @scoped_context.key?(key)
|
|
198
|
+
@scoped_context[key]
|
|
199
|
+
else
|
|
200
|
+
@provided_values[key]
|
|
201
|
+
end
|
|
190
202
|
end
|
|
191
203
|
|
|
192
204
|
def delete(key)
|
|
@@ -201,7 +213,7 @@ module GraphQL
|
|
|
201
213
|
|
|
202
214
|
def fetch(key, default = UNSPECIFIED_FETCH_DEFAULT)
|
|
203
215
|
if @scoped_context.key?(key)
|
|
204
|
-
|
|
216
|
+
scoped_context[key]
|
|
205
217
|
elsif @provided_values.key?(key)
|
|
206
218
|
@provided_values[key]
|
|
207
219
|
elsif default != UNSPECIFIED_FETCH_DEFAULT
|
|
@@ -214,12 +226,21 @@ module GraphQL
|
|
|
214
226
|
end
|
|
215
227
|
|
|
216
228
|
def dig(key, *other_keys)
|
|
217
|
-
@scoped_context.key?(key)
|
|
229
|
+
if @scoped_context.key?(key)
|
|
230
|
+
@scoped_context.dig(key, *other_keys)
|
|
231
|
+
else
|
|
232
|
+
@provided_values.dig(key, *other_keys)
|
|
233
|
+
end
|
|
218
234
|
end
|
|
219
235
|
|
|
220
236
|
def to_h
|
|
221
|
-
|
|
237
|
+
if (current_scoped_context = @scoped_context.merged_context)
|
|
238
|
+
@provided_values.merge(current_scoped_context)
|
|
239
|
+
else
|
|
240
|
+
@provided_values
|
|
241
|
+
end
|
|
222
242
|
end
|
|
243
|
+
|
|
223
244
|
alias :to_hash :to_h
|
|
224
245
|
|
|
225
246
|
def key?(key)
|
|
@@ -250,132 +271,14 @@ module GraphQL
|
|
|
250
271
|
"#<Query::Context ...>"
|
|
251
272
|
end
|
|
252
273
|
|
|
253
|
-
# @api private
|
|
254
|
-
def received_null_child
|
|
255
|
-
@invalid_null = true
|
|
256
|
-
@value = nil
|
|
257
|
-
end
|
|
258
|
-
|
|
259
274
|
def scoped_merge!(hash)
|
|
260
|
-
@scoped_context
|
|
275
|
+
@scoped_context.merge!(hash)
|
|
261
276
|
end
|
|
262
277
|
|
|
263
278
|
def scoped_set!(key, value)
|
|
264
279
|
scoped_merge!(key => value)
|
|
265
280
|
nil
|
|
266
281
|
end
|
|
267
|
-
|
|
268
|
-
class FieldResolutionContext
|
|
269
|
-
include SharedMethods
|
|
270
|
-
include Tracing::Traceable
|
|
271
|
-
extend Forwardable
|
|
272
|
-
|
|
273
|
-
attr_reader :irep_node, :field, :parent_type, :query, :schema, :parent, :key, :type
|
|
274
|
-
alias :selection :irep_node
|
|
275
|
-
|
|
276
|
-
def initialize(context, key, irep_node, parent, object)
|
|
277
|
-
@context = context
|
|
278
|
-
@key = key
|
|
279
|
-
@parent = parent
|
|
280
|
-
@object = object
|
|
281
|
-
@irep_node = irep_node
|
|
282
|
-
@field = irep_node.definition
|
|
283
|
-
@parent_type = irep_node.owner_type
|
|
284
|
-
@type = field.type
|
|
285
|
-
# This is needed constantly, so set it ahead of time:
|
|
286
|
-
@query = context.query
|
|
287
|
-
@schema = context.schema
|
|
288
|
-
@tracers = @query.tracers
|
|
289
|
-
# This hack flag is required by ConnectionResolve
|
|
290
|
-
@wrapped_connection = false
|
|
291
|
-
@wrapped_object = false
|
|
292
|
-
end
|
|
293
|
-
|
|
294
|
-
# @api private
|
|
295
|
-
attr_accessor :wrapped_connection, :wrapped_object
|
|
296
|
-
|
|
297
|
-
def path
|
|
298
|
-
@path ||= @parent.path.dup << @key
|
|
299
|
-
end
|
|
300
|
-
|
|
301
|
-
def_delegators :@context,
|
|
302
|
-
:[], :[]=, :key?, :fetch, :to_h, :namespace, :dig,
|
|
303
|
-
:spawn, :warden, :errors,
|
|
304
|
-
:execution_strategy, :strategy, :interpreter?
|
|
305
|
-
|
|
306
|
-
# @return [GraphQL::Language::Nodes::Field] The AST node for the currently-executing field
|
|
307
|
-
def ast_node
|
|
308
|
-
@irep_node.ast_node
|
|
309
|
-
end
|
|
310
|
-
|
|
311
|
-
# Add error to current field resolution.
|
|
312
|
-
# @param error [GraphQL::ExecutionError] an execution error
|
|
313
|
-
# @return [void]
|
|
314
|
-
def add_error(error)
|
|
315
|
-
super
|
|
316
|
-
error.ast_node ||= irep_node.ast_node
|
|
317
|
-
error.path ||= path
|
|
318
|
-
nil
|
|
319
|
-
end
|
|
320
|
-
|
|
321
|
-
def inspect
|
|
322
|
-
"#<GraphQL Context @ #{irep_node.owner_type.name}.#{field.name}>"
|
|
323
|
-
end
|
|
324
|
-
|
|
325
|
-
# Set a new value for this field in the response.
|
|
326
|
-
# It may be updated after resolving a {Lazy}.
|
|
327
|
-
# If it is {Execute::PROPAGATE_NULL}, tell the owner to propagate null.
|
|
328
|
-
# If it's {Execute::Execution::SKIP}, remove this field result from its parent
|
|
329
|
-
# @param new_value [Any] The GraphQL-ready value
|
|
330
|
-
# @api private
|
|
331
|
-
def value=(new_value)
|
|
332
|
-
case new_value
|
|
333
|
-
when GraphQL::Execution::Execute::PROPAGATE_NULL, nil
|
|
334
|
-
@invalid_null = true
|
|
335
|
-
@value = nil
|
|
336
|
-
if @type.kind.non_null?
|
|
337
|
-
@parent.received_null_child
|
|
338
|
-
end
|
|
339
|
-
when GraphQL::Execution::Execute::SKIP
|
|
340
|
-
@parent.skipped = true
|
|
341
|
-
@parent.delete_child(self)
|
|
342
|
-
else
|
|
343
|
-
@value = new_value
|
|
344
|
-
end
|
|
345
|
-
end
|
|
346
|
-
|
|
347
|
-
protected
|
|
348
|
-
|
|
349
|
-
def received_null_child
|
|
350
|
-
case @value
|
|
351
|
-
when Hash
|
|
352
|
-
self.value = GraphQL::Execution::Execute::PROPAGATE_NULL
|
|
353
|
-
when Array
|
|
354
|
-
if list_of_non_null_items?(@type)
|
|
355
|
-
self.value = GraphQL::Execution::Execute::PROPAGATE_NULL
|
|
356
|
-
end
|
|
357
|
-
when nil
|
|
358
|
-
# TODO This is a hack
|
|
359
|
-
# It was already nulled out but it's getting reassigned
|
|
360
|
-
else
|
|
361
|
-
raise "Unexpected value for received_null_child (#{self.value.class}): #{value}"
|
|
362
|
-
end
|
|
363
|
-
end
|
|
364
|
-
|
|
365
|
-
private
|
|
366
|
-
|
|
367
|
-
def list_of_non_null_items?(type)
|
|
368
|
-
case type
|
|
369
|
-
when GraphQL::NonNullType
|
|
370
|
-
# Unwrap [T]!
|
|
371
|
-
list_of_non_null_items?(type.of_type)
|
|
372
|
-
when GraphQL::ListType
|
|
373
|
-
type.of_type.is_a?(GraphQL::NonNullType)
|
|
374
|
-
else
|
|
375
|
-
raise "Unexpected list_of_non_null_items check: #{type}"
|
|
376
|
-
end
|
|
377
|
-
end
|
|
378
|
-
end
|
|
379
282
|
end
|
|
380
283
|
end
|
|
381
284
|
end
|
|
@@ -4,6 +4,12 @@ module GraphQL
|
|
|
4
4
|
class InputValidationResult
|
|
5
5
|
attr_accessor :problems
|
|
6
6
|
|
|
7
|
+
def self.from_problem(explanation, path = nil, extensions: nil, message: nil)
|
|
8
|
+
result = self.new
|
|
9
|
+
result.add_problem(explanation, path, extensions: extensions, message: message)
|
|
10
|
+
result
|
|
11
|
+
end
|
|
12
|
+
|
|
7
13
|
def initialize(valid: true, problems: nil)
|
|
8
14
|
@valid = valid
|
|
9
15
|
@problems = problems
|
|
@@ -27,7 +33,7 @@ module GraphQL
|
|
|
27
33
|
end
|
|
28
34
|
|
|
29
35
|
def merge_result!(path, inner_result)
|
|
30
|
-
return if inner_result.valid?
|
|
36
|
+
return if inner_result.nil? || inner_result.valid?
|
|
31
37
|
|
|
32
38
|
if inner_result.problems
|
|
33
39
|
inner_result.problems.each do |p|
|
|
@@ -38,6 +44,9 @@ module GraphQL
|
|
|
38
44
|
# It could have been explicitly set on inner_result (if it had no problems)
|
|
39
45
|
@valid = false
|
|
40
46
|
end
|
|
47
|
+
|
|
48
|
+
VALID = self.new
|
|
49
|
+
VALID.freeze
|
|
41
50
|
end
|
|
42
51
|
end
|
|
43
52
|
end
|
|
@@ -16,10 +16,8 @@ module GraphQL
|
|
|
16
16
|
class ValidationPipeline
|
|
17
17
|
attr_reader :max_depth, :max_complexity
|
|
18
18
|
|
|
19
|
-
def initialize(query:,
|
|
19
|
+
def initialize(query:, parse_error:, operation_name_error:, max_depth:, max_complexity:)
|
|
20
20
|
@validation_errors = []
|
|
21
|
-
@internal_representation = nil
|
|
22
|
-
@validate = validate
|
|
23
21
|
@parse_error = parse_error
|
|
24
22
|
@operation_name_error = operation_name_error
|
|
25
23
|
@query = query
|
|
@@ -42,12 +40,6 @@ module GraphQL
|
|
|
42
40
|
@validation_errors
|
|
43
41
|
end
|
|
44
42
|
|
|
45
|
-
# @return [Hash<String, nil => GraphQL::InternalRepresentation::Node] Operation name -> Irep node pairs
|
|
46
|
-
def internal_representation
|
|
47
|
-
ensure_has_validated
|
|
48
|
-
@internal_representation
|
|
49
|
-
end
|
|
50
|
-
|
|
51
43
|
def analyzers
|
|
52
44
|
ensure_has_validated
|
|
53
45
|
@query_analyzers
|
|
@@ -63,7 +55,7 @@ module GraphQL
|
|
|
63
55
|
|
|
64
56
|
if @parse_error
|
|
65
57
|
# This is kind of crazy: we push the parse error into `ctx`
|
|
66
|
-
# in
|
|
58
|
+
# in `def self.parse_error` by default so that users can _opt out_ by redefining that hook.
|
|
67
59
|
# That means we can't _re-add_ the error here (otherwise we'd either
|
|
68
60
|
# add it twice _or_ override the user's choice to not add it).
|
|
69
61
|
# So we just have to know that it was invalid and go from there.
|
|
@@ -72,9 +64,8 @@ module GraphQL
|
|
|
72
64
|
elsif @operation_name_error
|
|
73
65
|
@validation_errors << @operation_name_error
|
|
74
66
|
else
|
|
75
|
-
validation_result = @schema.static_validator.validate(@query, validate: @validate, timeout: @schema.validate_timeout, max_errors: @schema.validate_max_errors)
|
|
67
|
+
validation_result = @schema.static_validator.validate(@query, validate: @query.validate, timeout: @schema.validate_timeout, max_errors: @schema.validate_max_errors)
|
|
76
68
|
@validation_errors.concat(validation_result[:errors])
|
|
77
|
-
@internal_representation = validation_result[:irep]
|
|
78
69
|
|
|
79
70
|
if @validation_errors.empty?
|
|
80
71
|
@validation_errors.concat(@query.variables.errors)
|
|
@@ -100,35 +91,15 @@ module GraphQL
|
|
|
100
91
|
def build_analyzers(schema, max_depth, max_complexity)
|
|
101
92
|
qa = schema.query_analyzers.dup
|
|
102
93
|
|
|
103
|
-
# Filter out the built in authorization analyzer.
|
|
104
|
-
# It is deprecated and does not have an AST analyzer alternative.
|
|
105
|
-
qa = qa.select do |analyzer|
|
|
106
|
-
if analyzer == GraphQL::Authorization::Analyzer && schema.using_ast_analysis?
|
|
107
|
-
raise "The Authorization analyzer is not supported with AST Analyzers"
|
|
108
|
-
else
|
|
109
|
-
true
|
|
110
|
-
end
|
|
111
|
-
end
|
|
112
|
-
|
|
113
94
|
if max_depth || max_complexity
|
|
114
95
|
# Depending on the analysis engine, we must use different analyzers
|
|
115
96
|
# remove this once everything has switched over to AST analyzers
|
|
116
|
-
if
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
qa << GraphQL::Analysis::AST::MaxQueryComplexity
|
|
122
|
-
end
|
|
123
|
-
else
|
|
124
|
-
if max_depth
|
|
125
|
-
qa << GraphQL::Analysis::MaxQueryDepth.new(max_depth)
|
|
126
|
-
end
|
|
127
|
-
if max_complexity
|
|
128
|
-
qa << GraphQL::Analysis::MaxQueryComplexity.new(max_complexity)
|
|
129
|
-
end
|
|
97
|
+
if max_depth
|
|
98
|
+
qa << GraphQL::Analysis::AST::MaxQueryDepth
|
|
99
|
+
end
|
|
100
|
+
if max_complexity
|
|
101
|
+
qa << GraphQL::Analysis::AST::MaxQueryComplexity
|
|
130
102
|
end
|
|
131
|
-
|
|
132
103
|
qa
|
|
133
104
|
else
|
|
134
105
|
qa
|
|
@@ -14,7 +14,7 @@ module GraphQL
|
|
|
14
14
|
schema = ctx.schema
|
|
15
15
|
@context = ctx
|
|
16
16
|
|
|
17
|
-
@provided_variables =
|
|
17
|
+
@provided_variables = deep_stringify(provided_variables)
|
|
18
18
|
@errors = []
|
|
19
19
|
@storage = ast_variables.each_with_object({}) do |ast_variable, memo|
|
|
20
20
|
# Find the right value for this variable:
|
|
@@ -34,25 +34,12 @@ module GraphQL
|
|
|
34
34
|
if validation_result.valid?
|
|
35
35
|
if value_was_provided
|
|
36
36
|
# Add the variable if a value was provided
|
|
37
|
-
memo[variable_name] =
|
|
38
|
-
provided_value
|
|
39
|
-
elsif provided_value.nil?
|
|
40
|
-
nil
|
|
41
|
-
else
|
|
42
|
-
schema.error_handler.with_error_handling(context) do
|
|
43
|
-
variable_type.coerce_input(provided_value, ctx)
|
|
44
|
-
end
|
|
45
|
-
end
|
|
37
|
+
memo[variable_name] = provided_value
|
|
46
38
|
elsif default_value != nil
|
|
47
|
-
memo[variable_name] = if
|
|
48
|
-
|
|
49
|
-
nil
|
|
50
|
-
else
|
|
51
|
-
default_value
|
|
52
|
-
end
|
|
39
|
+
memo[variable_name] = if default_value.is_a?(Language::Nodes::NullValue)
|
|
40
|
+
nil
|
|
53
41
|
else
|
|
54
|
-
|
|
55
|
-
GraphQL::Query::LiteralInput.coerce(variable_type, default_value, self)
|
|
42
|
+
default_value
|
|
56
43
|
end
|
|
57
44
|
end
|
|
58
45
|
end
|
|
@@ -73,6 +60,23 @@ module GraphQL
|
|
|
73
60
|
end
|
|
74
61
|
|
|
75
62
|
def_delegators :@storage, :length, :key?, :[], :fetch, :to_h
|
|
63
|
+
|
|
64
|
+
private
|
|
65
|
+
|
|
66
|
+
def deep_stringify(val)
|
|
67
|
+
case val
|
|
68
|
+
when Array
|
|
69
|
+
val.map { |v| deep_stringify(v) }
|
|
70
|
+
when Hash
|
|
71
|
+
new_val = {}
|
|
72
|
+
val.each do |k, v|
|
|
73
|
+
new_val[k.to_s] = deep_stringify(v)
|
|
74
|
+
end
|
|
75
|
+
new_val
|
|
76
|
+
else
|
|
77
|
+
val
|
|
78
|
+
end
|
|
79
|
+
end
|
|
76
80
|
end
|
|
77
81
|
end
|
|
78
82
|
end
|
data/lib/graphql/query.rb
CHANGED
|
@@ -1,13 +1,8 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
|
-
require "graphql/query/arguments"
|
|
3
|
-
require "graphql/query/arguments_cache"
|
|
4
2
|
require "graphql/query/context"
|
|
5
|
-
require "graphql/query/executor"
|
|
6
3
|
require "graphql/query/fingerprint"
|
|
7
|
-
require "graphql/query/literal_input"
|
|
8
4
|
require "graphql/query/null_context"
|
|
9
5
|
require "graphql/query/result"
|
|
10
|
-
require "graphql/query/serial_execution"
|
|
11
6
|
require "graphql/query/variables"
|
|
12
7
|
require "graphql/query/input_validation_result"
|
|
13
8
|
require "graphql/query/variable_validation_error"
|
|
@@ -82,13 +77,7 @@ module GraphQL
|
|
|
82
77
|
def initialize(schema, query_string = nil, query: nil, document: nil, context: nil, variables: nil, validate: true, subscription_topic: nil, operation_name: nil, root_value: nil, max_depth: schema.max_depth, max_complexity: schema.max_complexity, except: nil, only: nil, warden: nil)
|
|
83
78
|
# Even if `variables: nil` is passed, use an empty hash for simpler logic
|
|
84
79
|
variables ||= {}
|
|
85
|
-
|
|
86
|
-
# Use the `.graphql_definition` here which will return legacy types instead of classes
|
|
87
|
-
if schema.is_a?(Class) && !schema.interpreter?
|
|
88
|
-
schema = schema.graphql_definition
|
|
89
|
-
end
|
|
90
80
|
@schema = schema
|
|
91
|
-
@interpreter = @schema.interpreter?
|
|
92
81
|
@filter = schema.default_filter.merge(except: except, only: only)
|
|
93
82
|
@context = schema.context_class.new(query: self, object: root_value, values: context)
|
|
94
83
|
@warden = warden
|
|
@@ -154,7 +143,7 @@ module GraphQL
|
|
|
154
143
|
end
|
|
155
144
|
|
|
156
145
|
def interpreter?
|
|
157
|
-
|
|
146
|
+
true
|
|
158
147
|
end
|
|
159
148
|
|
|
160
149
|
attr_accessor :multiplex
|
|
@@ -169,7 +158,6 @@ module GraphQL
|
|
|
169
158
|
@lookahead ||= begin
|
|
170
159
|
ast_node = selected_operation
|
|
171
160
|
root_type = warden.root_type_for_operation(ast_node.operation_type || "query")
|
|
172
|
-
root_type = root_type.type_class || raise("Invariant: `lookahead` only works with class-based types")
|
|
173
161
|
GraphQL::Execution::Lookahead.new(query: self, root_type: root_type, ast_nodes: [ast_node])
|
|
174
162
|
end
|
|
175
163
|
end
|
|
@@ -199,7 +187,7 @@ module GraphQL
|
|
|
199
187
|
# @return [Hash] A GraphQL response, with `"data"` and/or `"errors"` keys
|
|
200
188
|
def result
|
|
201
189
|
if !@executed
|
|
202
|
-
Execution::Multiplex.
|
|
190
|
+
Execution::Multiplex.run_all(@schema, [self], context: @context)
|
|
203
191
|
end
|
|
204
192
|
@result ||= Query::Result.new(query: self, values: @result_values)
|
|
205
193
|
end
|
|
@@ -237,35 +225,17 @@ module GraphQL
|
|
|
237
225
|
end
|
|
238
226
|
end
|
|
239
227
|
|
|
240
|
-
def irep_selection
|
|
241
|
-
@selection ||= begin
|
|
242
|
-
if selected_operation && internal_representation
|
|
243
|
-
internal_representation.operation_definitions[selected_operation.name]
|
|
244
|
-
else
|
|
245
|
-
nil
|
|
246
|
-
end
|
|
247
|
-
end
|
|
248
|
-
end
|
|
249
|
-
|
|
250
228
|
# Node-level cache for calculating arguments. Used during execution and query analysis.
|
|
251
229
|
# @param ast_node [GraphQL::Language::Nodes::AbstractNode]
|
|
252
230
|
# @param definition [GraphQL::Schema::Field]
|
|
253
231
|
# @param parent_object [GraphQL::Schema::Object]
|
|
254
232
|
# @return Hash{Symbol => Object}
|
|
255
233
|
def arguments_for(ast_node, definition, parent_object: nil)
|
|
256
|
-
|
|
257
|
-
arguments_cache.fetch(ast_node, definition, parent_object)
|
|
258
|
-
else
|
|
259
|
-
arguments_cache[ast_node][definition]
|
|
260
|
-
end
|
|
234
|
+
arguments_cache.fetch(ast_node, definition, parent_object)
|
|
261
235
|
end
|
|
262
236
|
|
|
263
237
|
def arguments_cache
|
|
264
|
-
|
|
265
|
-
@arguments_cache ||= Execution::Interpreter::ArgumentsCache.new(self)
|
|
266
|
-
else
|
|
267
|
-
@arguments_cache ||= ArgumentsCache.build(self)
|
|
268
|
-
end
|
|
238
|
+
@arguments_cache ||= Execution::Interpreter::ArgumentsCache.new(self)
|
|
269
239
|
end
|
|
270
240
|
|
|
271
241
|
# A version of the given query string, with:
|
|
@@ -308,7 +278,7 @@ module GraphQL
|
|
|
308
278
|
with_prepared_ast { @validation_pipeline }
|
|
309
279
|
end
|
|
310
280
|
|
|
311
|
-
def_delegators :validation_pipeline, :validation_errors,
|
|
281
|
+
def_delegators :validation_pipeline, :validation_errors,
|
|
312
282
|
:analyzers, :ast_analyzers, :max_depth, :max_complexity
|
|
313
283
|
|
|
314
284
|
attr_accessor :analysis_errors
|
|
@@ -434,7 +404,6 @@ module GraphQL
|
|
|
434
404
|
|
|
435
405
|
@validation_pipeline = GraphQL::Query::ValidationPipeline.new(
|
|
436
406
|
query: self,
|
|
437
|
-
validate: @validate,
|
|
438
407
|
parse_error: parse_error,
|
|
439
408
|
operation_name_error: operation_name_error,
|
|
440
409
|
max_depth: @max_depth,
|