graphql 2.0.14 → 2.0.32
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/mutation_delete_generator.rb +1 -1
- data/lib/generators/graphql/mutation_update_generator.rb +1 -1
- data/lib/generators/graphql/relay.rb +18 -1
- data/lib/graphql/analysis/ast/visitor.rb +42 -35
- data/lib/graphql/analysis/ast.rb +2 -2
- data/lib/graphql/backtrace/table.rb +2 -2
- data/lib/graphql/backtrace/trace.rb +96 -0
- data/lib/graphql/backtrace/tracer.rb +1 -1
- data/lib/graphql/backtrace.rb +2 -1
- data/lib/graphql/dataloader/source.rb +69 -45
- data/lib/graphql/dataloader.rb +8 -5
- data/lib/graphql/execution/interpreter/arguments.rb +1 -1
- data/lib/graphql/execution/interpreter/arguments_cache.rb +33 -33
- data/lib/graphql/execution/interpreter/resolve.rb +19 -0
- data/lib/graphql/execution/interpreter/runtime.rb +355 -268
- data/lib/graphql/execution/interpreter.rb +19 -15
- data/lib/graphql/execution/lazy.rb +6 -12
- data/lib/graphql/execution/lookahead.rb +16 -5
- data/lib/graphql/execution/multiplex.rb +2 -1
- data/lib/graphql/filter.rb +8 -2
- data/lib/graphql/introspection/directive_type.rb +2 -2
- data/lib/graphql/introspection/entry_points.rb +1 -1
- data/lib/graphql/introspection/field_type.rb +1 -1
- data/lib/graphql/introspection/schema_type.rb +2 -2
- data/lib/graphql/introspection/type_type.rb +5 -5
- data/lib/graphql/introspection.rb +1 -1
- data/lib/graphql/language/document_from_schema_definition.rb +58 -35
- data/lib/graphql/language/lexer.rb +248 -1505
- data/lib/graphql/language/nodes.rb +69 -40
- data/lib/graphql/language/parser.rb +775 -742
- data/lib/graphql/language/parser.y +44 -38
- data/lib/graphql/language/printer.rb +48 -25
- data/lib/graphql/language/visitor.rb +192 -81
- data/lib/graphql/pagination/active_record_relation_connection.rb +0 -8
- data/lib/graphql/pagination/connection.rb +5 -5
- data/lib/graphql/query/context.rb +93 -27
- data/lib/graphql/query/null_context.rb +8 -18
- data/lib/graphql/query/validation_pipeline.rb +2 -1
- data/lib/graphql/query.rb +55 -13
- data/lib/graphql/rake_task.rb +28 -1
- data/lib/graphql/schema/addition.rb +38 -12
- data/lib/graphql/schema/always_visible.rb +10 -0
- data/lib/graphql/schema/argument.rb +15 -23
- data/lib/graphql/schema/build_from_definition.rb +54 -25
- data/lib/graphql/schema/directive/transform.rb +1 -1
- data/lib/graphql/schema/directive.rb +12 -2
- data/lib/graphql/schema/enum.rb +24 -17
- data/lib/graphql/schema/enum_value.rb +3 -4
- data/lib/graphql/schema/field/connection_extension.rb +1 -1
- data/lib/graphql/schema/field.rb +95 -73
- data/lib/graphql/schema/field_extension.rb +1 -4
- data/lib/graphql/schema/find_inherited_value.rb +2 -7
- data/lib/graphql/schema/input_object.rb +9 -7
- data/lib/graphql/schema/interface.rb +5 -11
- data/lib/graphql/schema/introspection_system.rb +1 -1
- data/lib/graphql/schema/late_bound_type.rb +2 -0
- data/lib/graphql/schema/member/base_dsl_methods.rb +17 -14
- data/lib/graphql/schema/member/build_type.rb +11 -3
- data/lib/graphql/schema/member/has_arguments.rb +114 -65
- data/lib/graphql/schema/member/has_ast_node.rb +12 -0
- data/lib/graphql/schema/member/has_deprecation_reason.rb +3 -4
- data/lib/graphql/schema/member/has_directives.rb +81 -61
- data/lib/graphql/schema/member/has_fields.rb +95 -38
- data/lib/graphql/schema/member/has_interfaces.rb +49 -8
- data/lib/graphql/schema/member/has_validators.rb +32 -6
- data/lib/graphql/schema/member/relay_shortcuts.rb +19 -0
- data/lib/graphql/schema/member/type_system_helpers.rb +17 -0
- data/lib/graphql/schema/object.rb +8 -5
- data/lib/graphql/schema/printer.rb +3 -1
- data/lib/graphql/schema/relay_classic_mutation.rb +1 -1
- data/lib/graphql/schema/resolver/has_payload_type.rb +9 -9
- data/lib/graphql/schema/resolver.rb +16 -14
- data/lib/graphql/schema/timeout.rb +25 -29
- data/lib/graphql/schema/type_membership.rb +3 -0
- data/lib/graphql/schema/union.rb +10 -1
- data/lib/graphql/schema/validator.rb +2 -2
- data/lib/graphql/schema/warden.rb +64 -7
- data/lib/graphql/schema.rb +171 -28
- data/lib/graphql/static_validation/definition_dependencies.rb +7 -1
- data/lib/graphql/static_validation/literal_validator.rb +15 -1
- data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +12 -4
- data/lib/graphql/static_validation/rules/fields_will_merge.rb +2 -2
- data/lib/graphql/static_validation/validator.rb +1 -1
- data/lib/graphql/subscriptions/action_cable_subscriptions.rb +7 -1
- data/lib/graphql/subscriptions/event.rb +2 -7
- data/lib/graphql/subscriptions.rb +5 -0
- data/lib/graphql/tracing/active_support_notifications_trace.rb +16 -0
- data/lib/graphql/tracing/appoptics_trace.rb +255 -0
- data/lib/graphql/tracing/appsignal_trace.rb +81 -0
- data/lib/graphql/tracing/data_dog_trace.rb +187 -0
- data/lib/graphql/tracing/data_dog_tracing.rb +7 -21
- data/lib/graphql/tracing/legacy_trace.rb +69 -0
- data/lib/graphql/tracing/new_relic_trace.rb +75 -0
- data/lib/graphql/tracing/notifications_trace.rb +49 -0
- data/lib/graphql/tracing/platform_trace.rb +123 -0
- data/lib/graphql/tracing/platform_tracing.rb +15 -3
- data/lib/graphql/tracing/prometheus_trace.rb +93 -0
- data/lib/graphql/tracing/prometheus_tracing/graphql_collector.rb +1 -1
- data/lib/graphql/tracing/prometheus_tracing.rb +3 -3
- data/lib/graphql/tracing/scout_trace.rb +75 -0
- data/lib/graphql/tracing/statsd_trace.rb +60 -0
- data/lib/graphql/tracing/trace.rb +75 -0
- data/lib/graphql/tracing.rb +17 -39
- data/lib/graphql/type_kinds.rb +6 -3
- data/lib/graphql/types/relay/base_connection.rb +1 -1
- data/lib/graphql/types/relay/connection_behaviors.rb +28 -6
- data/lib/graphql/types/relay/edge_behaviors.rb +16 -5
- data/lib/graphql/types/relay/node_behaviors.rb +8 -2
- data/lib/graphql/types/relay/page_info_behaviors.rb +7 -2
- data/lib/graphql/types/relay.rb +0 -1
- data/lib/graphql/types/string.rb +1 -1
- data/lib/graphql/version.rb +1 -1
- data/lib/graphql.rb +16 -9
- data/readme.md +1 -1
- metadata +66 -29
- data/lib/graphql/language/lexer.rl +0 -280
- data/lib/graphql/types/relay/default_relay.rb +0 -21
|
@@ -65,7 +65,9 @@ module GraphQL
|
|
|
65
65
|
# Visit `document` and all children, applying hooks as you go
|
|
66
66
|
# @return [void]
|
|
67
67
|
def visit
|
|
68
|
-
|
|
68
|
+
# `@document` may be any kind of node:
|
|
69
|
+
visit_method = :"#{@document.visit_method}_with_modifications"
|
|
70
|
+
result = public_send(visit_method, @document, nil)
|
|
69
71
|
@result = if result.is_a?(Array)
|
|
70
72
|
result.first
|
|
71
73
|
else
|
|
@@ -74,104 +76,213 @@ module GraphQL
|
|
|
74
76
|
end
|
|
75
77
|
end
|
|
76
78
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
79
|
+
def on_document_children(document_node)
|
|
80
|
+
new_node = document_node
|
|
81
|
+
document_node.children.each do |child_node|
|
|
82
|
+
visit_method = :"#{child_node.visit_method}_with_modifications"
|
|
83
|
+
new_child_and_node = public_send(visit_method, child_node, new_node)
|
|
84
|
+
# Reassign `node` in case the child hook makes a modification
|
|
85
|
+
if new_child_and_node.is_a?(Array)
|
|
86
|
+
new_node = new_child_and_node[1]
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
new_node
|
|
80
90
|
end
|
|
81
91
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
# @param node [GraphQL::Language::Nodes::AbstractNode] the node being visited
|
|
89
|
-
# @param parent [GraphQL::Language::Nodes::AbstractNode, nil] the previously-visited node, or `nil` if this is the root node.
|
|
90
|
-
# @return [Array, nil] If there were modifications, it returns an array of new nodes, otherwise, it returns `nil`.
|
|
91
|
-
def on_abstract_node(node, parent)
|
|
92
|
-
if node.equal?(DELETE_NODE)
|
|
93
|
-
# This might be passed to `super(DELETE_NODE, ...)`
|
|
94
|
-
# by a user hook, don't want to keep visiting in that case.
|
|
95
|
-
nil
|
|
96
|
-
else
|
|
97
|
-
# Run hooks if there are any
|
|
98
|
-
new_node = node
|
|
99
|
-
no_hooks = !@visitors.key?(node.class)
|
|
100
|
-
if no_hooks || begin_visit(new_node, parent)
|
|
101
|
-
node.children.each do |child_node|
|
|
102
|
-
new_child_and_node = on_node_with_modifications(child_node, new_node)
|
|
103
|
-
# Reassign `node` in case the child hook makes a modification
|
|
104
|
-
if new_child_and_node.is_a?(Array)
|
|
105
|
-
new_node = new_child_and_node[1]
|
|
106
|
-
end
|
|
107
|
-
end
|
|
92
|
+
def on_field_children(new_node)
|
|
93
|
+
new_node.arguments.each do |arg_node| # rubocop:disable Development/ContextIsPassedCop
|
|
94
|
+
new_child_and_node = on_argument_with_modifications(arg_node, new_node)
|
|
95
|
+
# Reassign `node` in case the child hook makes a modification
|
|
96
|
+
if new_child_and_node.is_a?(Array)
|
|
97
|
+
new_node = new_child_and_node[1]
|
|
108
98
|
end
|
|
109
|
-
|
|
99
|
+
end
|
|
100
|
+
new_node = visit_directives(new_node)
|
|
101
|
+
new_node = visit_selections(new_node)
|
|
102
|
+
new_node
|
|
103
|
+
end
|
|
110
104
|
|
|
111
|
-
|
|
112
|
-
|
|
105
|
+
def visit_directives(new_node)
|
|
106
|
+
new_node.directives.each do |dir_node|
|
|
107
|
+
new_child_and_node = on_directive_with_modifications(dir_node, new_node)
|
|
108
|
+
# Reassign `node` in case the child hook makes a modification
|
|
109
|
+
if new_child_and_node.is_a?(Array)
|
|
110
|
+
new_node = new_child_and_node[1]
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
new_node
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def visit_selections(new_node)
|
|
117
|
+
new_node.selections.each do |selection|
|
|
118
|
+
new_child_and_node = case selection
|
|
119
|
+
when GraphQL::Language::Nodes::Field
|
|
120
|
+
on_field_with_modifications(selection, new_node)
|
|
121
|
+
when GraphQL::Language::Nodes::InlineFragment
|
|
122
|
+
on_inline_fragment_with_modifications(selection, new_node)
|
|
123
|
+
when GraphQL::Language::Nodes::FragmentSpread
|
|
124
|
+
on_fragment_spread_with_modifications(selection, new_node)
|
|
113
125
|
else
|
|
114
|
-
|
|
126
|
+
raise ArgumentError, "Invariant: unexpected field selection #{selection.class} (#{selection.inspect})"
|
|
127
|
+
end
|
|
128
|
+
# Reassign `node` in case the child hook makes a modification
|
|
129
|
+
if new_child_and_node.is_a?(Array)
|
|
130
|
+
new_node = new_child_and_node[1]
|
|
115
131
|
end
|
|
116
132
|
end
|
|
133
|
+
new_node
|
|
117
134
|
end
|
|
118
135
|
|
|
119
|
-
|
|
120
|
-
|
|
136
|
+
def on_fragment_definition_children(new_node)
|
|
137
|
+
new_node = visit_directives(new_node)
|
|
138
|
+
new_node = visit_selections(new_node)
|
|
139
|
+
new_node
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
alias :on_inline_fragment_children :on_fragment_definition_children
|
|
143
|
+
|
|
144
|
+
def on_operation_definition_children(new_node)
|
|
145
|
+
new_node.variables.each do |arg_node|
|
|
146
|
+
new_child_and_node = on_variable_definition_with_modifications(arg_node, new_node)
|
|
147
|
+
# Reassign `node` in case the child hook makes a modification
|
|
148
|
+
if new_child_and_node.is_a?(Array)
|
|
149
|
+
new_node = new_child_and_node[1]
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
new_node = visit_directives(new_node)
|
|
153
|
+
new_node = visit_selections(new_node)
|
|
154
|
+
new_node
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
def on_argument_children(new_node)
|
|
158
|
+
new_node.children.each do |value_node|
|
|
159
|
+
new_child_and_node = case value_node
|
|
160
|
+
when Language::Nodes::VariableIdentifier
|
|
161
|
+
on_variable_identifier_with_modifications(value_node, new_node)
|
|
162
|
+
when Language::Nodes::InputObject
|
|
163
|
+
on_input_object_with_modifications(value_node, new_node)
|
|
164
|
+
when Language::Nodes::Enum
|
|
165
|
+
on_enum_with_modifications(value_node, new_node)
|
|
166
|
+
when Language::Nodes::NullValue
|
|
167
|
+
on_null_value_with_modifications(value_node, new_node)
|
|
168
|
+
else
|
|
169
|
+
raise ArgumentError, "Invariant: unexpected argument value node #{value_node.class} (#{value_node.inspect})"
|
|
170
|
+
end
|
|
171
|
+
# Reassign `node` in case the child hook makes a modification
|
|
172
|
+
if new_child_and_node.is_a?(Array)
|
|
173
|
+
new_node = new_child_and_node[1]
|
|
174
|
+
end
|
|
175
|
+
end
|
|
176
|
+
new_node
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
# rubocop:disable Development/NoEvalCop This eval takes static inputs at load-time
|
|
180
|
+
|
|
181
|
+
def self.make_visit_methods(ast_node_class)
|
|
182
|
+
node_method = ast_node_class.visit_method
|
|
183
|
+
children_of_type = ast_node_class.children_of_type
|
|
184
|
+
child_visit_method = :"#{node_method}_children"
|
|
185
|
+
|
|
121
186
|
class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
|
|
187
|
+
# The default implementation for visiting an AST node.
|
|
188
|
+
# It doesn't _do_ anything, but it continues to visiting the node's children.
|
|
189
|
+
# To customize this hook, override one of its make_visit_methods (or the base method?)
|
|
190
|
+
# in your subclasses.
|
|
191
|
+
#
|
|
192
|
+
# For compatibility, it calls hook procs, too.
|
|
193
|
+
# @param node [GraphQL::Language::Nodes::AbstractNode] the node being visited
|
|
194
|
+
# @param parent [GraphQL::Language::Nodes::AbstractNode, nil] the previously-visited node, or `nil` if this is the root node.
|
|
195
|
+
# @return [Array, nil] If there were modifications, it returns an array of new nodes, otherwise, it returns `nil`.
|
|
122
196
|
def #{node_method}(node, parent)
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
197
|
+
if node.equal?(DELETE_NODE)
|
|
198
|
+
# This might be passed to `super(DELETE_NODE, ...)`
|
|
199
|
+
# by a user hook, don't want to keep visiting in that case.
|
|
200
|
+
[node, parent]
|
|
201
|
+
else
|
|
202
|
+
# Run hooks if there are any
|
|
203
|
+
new_node = node
|
|
204
|
+
no_hooks = !@visitors.key?(node.class)
|
|
205
|
+
if no_hooks || begin_visit(new_node, parent)
|
|
206
|
+
#{
|
|
207
|
+
if method_defined?(child_visit_method)
|
|
208
|
+
"new_node = #{child_visit_method}(new_node)"
|
|
209
|
+
elsif children_of_type
|
|
210
|
+
children_of_type.map do |child_accessor, child_class|
|
|
211
|
+
"node.#{child_accessor}.each do |child_node|
|
|
212
|
+
new_child_and_node = #{child_class.visit_method}_with_modifications(child_node, new_node)
|
|
213
|
+
# Reassign `node` in case the child hook makes a modification
|
|
214
|
+
if new_child_and_node.is_a?(Array)
|
|
215
|
+
new_node = new_child_and_node[1]
|
|
216
|
+
end
|
|
217
|
+
end"
|
|
218
|
+
end.join("\n")
|
|
219
|
+
else
|
|
220
|
+
""
|
|
221
|
+
end
|
|
222
|
+
}
|
|
223
|
+
end
|
|
224
|
+
end_visit(new_node, parent) unless no_hooks
|
|
225
|
+
if new_node.equal?(node)
|
|
226
|
+
[node, parent]
|
|
227
|
+
else
|
|
228
|
+
[new_node, parent]
|
|
229
|
+
end
|
|
230
|
+
end
|
|
231
|
+
end
|
|
232
|
+
def #{node_method}_with_modifications(node, parent)
|
|
233
|
+
new_node_and_new_parent = #{node_method}(node, parent)
|
|
234
|
+
apply_modifications(node, parent, new_node_and_new_parent)
|
|
126
235
|
end
|
|
127
236
|
RUBY
|
|
128
237
|
end
|
|
129
238
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
[
|
|
242
|
+
Language::Nodes::Argument,
|
|
243
|
+
Language::Nodes::Directive,
|
|
244
|
+
Language::Nodes::DirectiveDefinition,
|
|
245
|
+
Language::Nodes::DirectiveLocation,
|
|
246
|
+
Language::Nodes::Document,
|
|
247
|
+
Language::Nodes::Enum,
|
|
248
|
+
Language::Nodes::EnumTypeDefinition,
|
|
249
|
+
Language::Nodes::EnumTypeExtension,
|
|
250
|
+
Language::Nodes::EnumValueDefinition,
|
|
251
|
+
Language::Nodes::Field,
|
|
252
|
+
Language::Nodes::FieldDefinition,
|
|
253
|
+
Language::Nodes::FragmentDefinition,
|
|
254
|
+
Language::Nodes::FragmentSpread,
|
|
255
|
+
Language::Nodes::InlineFragment,
|
|
256
|
+
Language::Nodes::InputObject,
|
|
257
|
+
Language::Nodes::InputObjectTypeDefinition,
|
|
258
|
+
Language::Nodes::InputObjectTypeExtension,
|
|
259
|
+
Language::Nodes::InputValueDefinition,
|
|
260
|
+
Language::Nodes::InterfaceTypeDefinition,
|
|
261
|
+
Language::Nodes::InterfaceTypeExtension,
|
|
262
|
+
Language::Nodes::ListType,
|
|
263
|
+
Language::Nodes::NonNullType,
|
|
264
|
+
Language::Nodes::NullValue,
|
|
265
|
+
Language::Nodes::ObjectTypeDefinition,
|
|
266
|
+
Language::Nodes::ObjectTypeExtension,
|
|
267
|
+
Language::Nodes::OperationDefinition,
|
|
268
|
+
Language::Nodes::ScalarTypeDefinition,
|
|
269
|
+
Language::Nodes::ScalarTypeExtension,
|
|
270
|
+
Language::Nodes::SchemaDefinition,
|
|
271
|
+
Language::Nodes::SchemaExtension,
|
|
272
|
+
Language::Nodes::TypeName,
|
|
273
|
+
Language::Nodes::UnionTypeDefinition,
|
|
274
|
+
Language::Nodes::UnionTypeExtension,
|
|
275
|
+
Language::Nodes::VariableDefinition,
|
|
276
|
+
Language::Nodes::VariableIdentifier,
|
|
277
|
+
].each do |ast_node_class|
|
|
278
|
+
make_visit_methods(ast_node_class)
|
|
279
|
+
end
|
|
280
|
+
|
|
281
|
+
# rubocop:enable Development/NoEvalCop
|
|
165
282
|
|
|
166
283
|
private
|
|
167
284
|
|
|
168
|
-
|
|
169
|
-
# copy `parent` so that it contains the copy of that node as a child,
|
|
170
|
-
# then return the copies
|
|
171
|
-
# If a non-array value is returned, consuming functions should ignore
|
|
172
|
-
# said value
|
|
173
|
-
def on_node_with_modifications(node, parent)
|
|
174
|
-
new_node_and_new_parent = visit_node(node, parent)
|
|
285
|
+
def apply_modifications(node, parent, new_node_and_new_parent)
|
|
175
286
|
if new_node_and_new_parent.is_a?(Array)
|
|
176
287
|
new_node = new_node_and_new_parent[0]
|
|
177
288
|
new_parent = new_node_and_new_parent[1]
|
|
@@ -7,14 +7,6 @@ module GraphQL
|
|
|
7
7
|
class ActiveRecordRelationConnection < Pagination::RelationConnection
|
|
8
8
|
private
|
|
9
9
|
|
|
10
|
-
def relation_larger_than(relation, initial_offset, size)
|
|
11
|
-
if already_loaded?(relation)
|
|
12
|
-
(relation.size + initial_offset) > size
|
|
13
|
-
else
|
|
14
|
-
set_offset(sliced_nodes, initial_offset + size).exists?
|
|
15
|
-
end
|
|
16
|
-
end
|
|
17
|
-
|
|
18
10
|
def relation_count(relation)
|
|
19
11
|
int_or_hash = if already_loaded?(relation)
|
|
20
12
|
relation.size
|
|
@@ -58,7 +58,7 @@ module GraphQL
|
|
|
58
58
|
# @param arguments [Hash] The arguments to the field that returned the collection wrapped by this connection
|
|
59
59
|
# @param max_page_size [Integer, nil] A configured value to cap the result size. Applied as `first` if neither first or last are given and no `default_page_size` is set.
|
|
60
60
|
# @param default_page_size [Integer, nil] A configured value to determine the result size when neither first or last are given.
|
|
61
|
-
def initialize(items, parent: nil, field: nil, context: nil, first: nil, after: nil, max_page_size:
|
|
61
|
+
def initialize(items, parent: nil, field: nil, context: nil, first: nil, after: nil, max_page_size: NOT_CONFIGURED, default_page_size: NOT_CONFIGURED, last: nil, before: nil, edge_class: nil, arguments: nil)
|
|
62
62
|
@items = items
|
|
63
63
|
@parent = parent
|
|
64
64
|
@context = context
|
|
@@ -71,14 +71,14 @@ module GraphQL
|
|
|
71
71
|
@edge_class = edge_class || self.class::Edge
|
|
72
72
|
# This is only true if the object was _initialized_ with an override
|
|
73
73
|
# or if one is assigned later.
|
|
74
|
-
@has_max_page_size_override = max_page_size !=
|
|
75
|
-
@max_page_size = if max_page_size ==
|
|
74
|
+
@has_max_page_size_override = max_page_size != NOT_CONFIGURED
|
|
75
|
+
@max_page_size = if max_page_size == NOT_CONFIGURED
|
|
76
76
|
nil
|
|
77
77
|
else
|
|
78
78
|
max_page_size
|
|
79
79
|
end
|
|
80
|
-
@has_default_page_size_override = default_page_size !=
|
|
81
|
-
@default_page_size = if default_page_size ==
|
|
80
|
+
@has_default_page_size_override = default_page_size != NOT_CONFIGURED
|
|
81
|
+
@default_page_size = if default_page_size == NOT_CONFIGURED
|
|
82
82
|
nil
|
|
83
83
|
else
|
|
84
84
|
default_page_size
|
|
@@ -91,33 +91,44 @@ module GraphQL
|
|
|
91
91
|
end
|
|
92
92
|
|
|
93
93
|
class ScopedContext
|
|
94
|
+
NO_PATH = GraphQL::EmptyObjects::EMPTY_ARRAY
|
|
95
|
+
NO_CONTEXT = GraphQL::EmptyObjects::EMPTY_HASH
|
|
96
|
+
|
|
94
97
|
def initialize(query_context)
|
|
95
98
|
@query_context = query_context
|
|
96
|
-
@
|
|
97
|
-
@
|
|
99
|
+
@scoped_contexts = nil
|
|
100
|
+
@all_keys = nil
|
|
98
101
|
end
|
|
99
102
|
|
|
100
103
|
def merged_context
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
+
if @scoped_contexts.nil?
|
|
105
|
+
NO_CONTEXT
|
|
106
|
+
else
|
|
107
|
+
merged_ctx = {}
|
|
108
|
+
each_present_path_ctx do |path_ctx|
|
|
109
|
+
merged_ctx = path_ctx.merge(merged_ctx)
|
|
110
|
+
end
|
|
111
|
+
merged_ctx
|
|
104
112
|
end
|
|
105
|
-
merged_ctx
|
|
106
113
|
end
|
|
107
114
|
|
|
108
115
|
def merge!(hash)
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
116
|
+
@all_keys ||= Set.new
|
|
117
|
+
@all_keys.merge(hash.keys)
|
|
118
|
+
ctx = @scoped_contexts ||= {}
|
|
119
|
+
current_path.each do |path_part|
|
|
120
|
+
ctx = ctx[path_part] ||= { parent: ctx }
|
|
121
|
+
end
|
|
122
|
+
this_scoped_ctx = ctx[:scoped_context] ||= {}
|
|
123
|
+
this_scoped_ctx.merge!(hash)
|
|
115
124
|
end
|
|
116
125
|
|
|
117
126
|
def key?(key)
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
127
|
+
if @all_keys && @all_keys.include?(key)
|
|
128
|
+
each_present_path_ctx do |path_ctx|
|
|
129
|
+
if path_ctx.key?(key)
|
|
130
|
+
return true
|
|
131
|
+
end
|
|
121
132
|
end
|
|
122
133
|
end
|
|
123
134
|
false
|
|
@@ -132,6 +143,10 @@ module GraphQL
|
|
|
132
143
|
nil
|
|
133
144
|
end
|
|
134
145
|
|
|
146
|
+
def current_path
|
|
147
|
+
@query_context.current_path || NO_PATH
|
|
148
|
+
end
|
|
149
|
+
|
|
135
150
|
def dig(key, *other_keys)
|
|
136
151
|
each_present_path_ctx do |path_ctx|
|
|
137
152
|
if path_ctx.key?(key)
|
|
@@ -151,15 +166,23 @@ module GraphQL
|
|
|
151
166
|
# Start at the current location,
|
|
152
167
|
# but look up the tree for previously-assigned scoped values
|
|
153
168
|
def each_present_path_ctx
|
|
154
|
-
|
|
155
|
-
if
|
|
156
|
-
|
|
157
|
-
|
|
169
|
+
ctx = @scoped_contexts
|
|
170
|
+
if ctx.nil?
|
|
171
|
+
# no-op
|
|
172
|
+
else
|
|
173
|
+
current_path.each do |path_part|
|
|
174
|
+
if ctx.key?(path_part)
|
|
175
|
+
ctx = ctx[path_part]
|
|
176
|
+
else
|
|
177
|
+
break
|
|
178
|
+
end
|
|
179
|
+
end
|
|
158
180
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
181
|
+
while ctx
|
|
182
|
+
if (scoped_ctx = ctx[:scoped_context])
|
|
183
|
+
yield(scoped_ctx)
|
|
184
|
+
end
|
|
185
|
+
ctx = ctx[:parent]
|
|
163
186
|
end
|
|
164
187
|
end
|
|
165
188
|
end
|
|
@@ -189,6 +212,7 @@ module GraphQL
|
|
|
189
212
|
|
|
190
213
|
def_delegators :@query, :trace, :interpreter?
|
|
191
214
|
|
|
215
|
+
RUNTIME_METADATA_KEYS = Set.new([:current_object, :current_arguments, :current_field, :current_path])
|
|
192
216
|
# @!method []=(key, value)
|
|
193
217
|
# Reassign `key` to the hash passed to {Schema#execute} as `context:`
|
|
194
218
|
|
|
@@ -196,11 +220,36 @@ module GraphQL
|
|
|
196
220
|
def [](key)
|
|
197
221
|
if @scoped_context.key?(key)
|
|
198
222
|
@scoped_context[key]
|
|
199
|
-
|
|
223
|
+
elsif @provided_values.key?(key)
|
|
200
224
|
@provided_values[key]
|
|
225
|
+
elsif RUNTIME_METADATA_KEYS.include?(key)
|
|
226
|
+
if key == :current_path
|
|
227
|
+
current_path
|
|
228
|
+
else
|
|
229
|
+
(current_runtime_state = Thread.current[:__graphql_runtime_info]) &&
|
|
230
|
+
(query_runtime_state = current_runtime_state[@query]) &&
|
|
231
|
+
(query_runtime_state.public_send(key))
|
|
232
|
+
end
|
|
233
|
+
else
|
|
234
|
+
# not found
|
|
235
|
+
nil
|
|
201
236
|
end
|
|
202
237
|
end
|
|
203
238
|
|
|
239
|
+
def current_path
|
|
240
|
+
current_runtime_state = Thread.current[:__graphql_runtime_info]
|
|
241
|
+
query_runtime_state = current_runtime_state && current_runtime_state[@query]
|
|
242
|
+
|
|
243
|
+
path = query_runtime_state &&
|
|
244
|
+
(result = query_runtime_state.current_result) &&
|
|
245
|
+
(result.path)
|
|
246
|
+
if path && (rn = query_runtime_state.current_result_name)
|
|
247
|
+
path = path.dup
|
|
248
|
+
path.push(rn)
|
|
249
|
+
end
|
|
250
|
+
path
|
|
251
|
+
end
|
|
252
|
+
|
|
204
253
|
def delete(key)
|
|
205
254
|
if @scoped_context.key?(key)
|
|
206
255
|
@scoped_context.delete(key)
|
|
@@ -212,7 +261,11 @@ module GraphQL
|
|
|
212
261
|
UNSPECIFIED_FETCH_DEFAULT = Object.new
|
|
213
262
|
|
|
214
263
|
def fetch(key, default = UNSPECIFIED_FETCH_DEFAULT)
|
|
215
|
-
if
|
|
264
|
+
if RUNTIME_METADATA_KEYS.include?(key)
|
|
265
|
+
(runtime = Thread.current[:__graphql_runtime_info]) &&
|
|
266
|
+
(query_runtime_state = runtime[@query]) &&
|
|
267
|
+
(query_runtime_state.public_send(key))
|
|
268
|
+
elsif @scoped_context.key?(key)
|
|
216
269
|
scoped_context[key]
|
|
217
270
|
elsif @provided_values.key?(key)
|
|
218
271
|
@provided_values[key]
|
|
@@ -226,7 +279,16 @@ module GraphQL
|
|
|
226
279
|
end
|
|
227
280
|
|
|
228
281
|
def dig(key, *other_keys)
|
|
229
|
-
if
|
|
282
|
+
if RUNTIME_METADATA_KEYS.include?(key)
|
|
283
|
+
(current_runtime_state = Thread.current[:__graphql_runtime_info]) &&
|
|
284
|
+
(query_runtime_state = current_runtime_state[@query]) &&
|
|
285
|
+
(obj = query_runtime_state.public_send(key)) &&
|
|
286
|
+
if other_keys.empty?
|
|
287
|
+
obj
|
|
288
|
+
else
|
|
289
|
+
obj.dig(*other_keys)
|
|
290
|
+
end
|
|
291
|
+
elsif @scoped_context.key?(key)
|
|
230
292
|
@scoped_context.dig(key, *other_keys)
|
|
231
293
|
else
|
|
232
294
|
@provided_values.dig(key, *other_keys)
|
|
@@ -259,7 +321,11 @@ module GraphQL
|
|
|
259
321
|
# @param ns [Object] a usage-specific namespace identifier
|
|
260
322
|
# @return [Hash] namespaced storage
|
|
261
323
|
def namespace(ns)
|
|
262
|
-
|
|
324
|
+
if ns == :interpreter
|
|
325
|
+
self
|
|
326
|
+
else
|
|
327
|
+
@storage[ns]
|
|
328
|
+
end
|
|
263
329
|
end
|
|
264
330
|
|
|
265
331
|
# @return [Boolean] true if this namespace was accessed before
|
|
@@ -3,35 +3,27 @@ module GraphQL
|
|
|
3
3
|
class Query
|
|
4
4
|
# This object can be `ctx` in places where there is no query
|
|
5
5
|
class NullContext
|
|
6
|
-
class NullWarden < GraphQL::Schema::Warden
|
|
7
|
-
def visible_field?(field, ctx); true; end
|
|
8
|
-
def visible_argument?(arg, ctx); true; end
|
|
9
|
-
def visible_type?(type, ctx); true; end
|
|
10
|
-
def visible_enum_value?(ev, ctx); true; end
|
|
11
|
-
def visible_type_membership?(tm, ctx); true; end
|
|
12
|
-
end
|
|
13
|
-
|
|
14
6
|
class NullQuery
|
|
7
|
+
def after_lazy(value)
|
|
8
|
+
yield(value)
|
|
9
|
+
end
|
|
15
10
|
end
|
|
16
11
|
|
|
17
12
|
class NullSchema < GraphQL::Schema
|
|
18
13
|
end
|
|
19
14
|
|
|
15
|
+
extend Forwardable
|
|
16
|
+
|
|
20
17
|
attr_reader :schema, :query, :warden, :dataloader
|
|
18
|
+
def_delegators GraphQL::EmptyObjects::EMPTY_HASH, :[], :fetch, :dig, :key?
|
|
21
19
|
|
|
22
20
|
def initialize
|
|
23
21
|
@query = NullQuery.new
|
|
24
22
|
@dataloader = GraphQL::Dataloader::NullDataloader.new
|
|
25
23
|
@schema = NullSchema
|
|
26
|
-
@warden = NullWarden.new(
|
|
27
|
-
GraphQL::Filter.new,
|
|
28
|
-
context: self,
|
|
29
|
-
schema: @schema,
|
|
30
|
-
)
|
|
24
|
+
@warden = Schema::Warden::NullWarden.new(context: self, schema: @schema)
|
|
31
25
|
end
|
|
32
26
|
|
|
33
|
-
def [](key); end
|
|
34
|
-
|
|
35
27
|
def interpreter?
|
|
36
28
|
true
|
|
37
29
|
end
|
|
@@ -39,13 +31,11 @@ module GraphQL
|
|
|
39
31
|
class << self
|
|
40
32
|
extend Forwardable
|
|
41
33
|
|
|
42
|
-
def [](key); end
|
|
43
|
-
|
|
44
34
|
def instance
|
|
45
35
|
@instance ||= self.new
|
|
46
36
|
end
|
|
47
37
|
|
|
48
|
-
def_delegators :instance, :query, :warden, :schema, :interpreter?, :dataloader
|
|
38
|
+
def_delegators :instance, :query, :warden, :schema, :interpreter?, :dataloader, :[], :fetch, :dig, :key?
|
|
49
39
|
end
|
|
50
40
|
end
|
|
51
41
|
end
|
|
@@ -68,7 +68,8 @@ module GraphQL
|
|
|
68
68
|
elsif @operation_name_error
|
|
69
69
|
@validation_errors << @operation_name_error
|
|
70
70
|
else
|
|
71
|
-
|
|
71
|
+
validator = @query.static_validator || @schema.static_validator
|
|
72
|
+
validation_result = validator.validate(@query, validate: @query.validate, timeout: @schema.validate_timeout, max_errors: @schema.validate_max_errors)
|
|
72
73
|
@validation_errors.concat(validation_result[:errors])
|
|
73
74
|
|
|
74
75
|
if @validation_errors.empty?
|