graphql 2.0.16 → 2.0.18
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.
Potentially problematic release.
This version of graphql might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/lib/graphql/analysis/ast/visitor.rb +42 -35
- data/lib/graphql/analysis/ast.rb +2 -2
- data/lib/graphql/backtrace/tracer.rb +1 -1
- data/lib/graphql/execution/interpreter/resolve.rb +19 -0
- data/lib/graphql/execution/interpreter/runtime.rb +106 -88
- data/lib/graphql/execution/interpreter.rb +14 -9
- data/lib/graphql/execution/lazy.rb +6 -12
- data/lib/graphql/execution/multiplex.rb +2 -1
- data/lib/graphql/graphql_ext.bundle +0 -0
- data/lib/graphql/introspection/directive_type.rb +2 -2
- 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/language/lexer.rb +216 -1505
- data/lib/graphql/language/lexer.ri +744 -0
- data/lib/graphql/language/nodes.rb +39 -31
- data/lib/graphql/language/parser.rb +9 -9
- data/lib/graphql/language/parser.y +9 -9
- data/lib/graphql/language/visitor.rb +191 -83
- data/lib/graphql/pagination/active_record_relation_connection.rb +0 -8
- data/lib/graphql/query/context.rb +45 -11
- data/lib/graphql/query.rb +15 -2
- data/lib/graphql/schema/argument.rb +0 -4
- data/lib/graphql/schema/directive.rb +12 -2
- data/lib/graphql/schema/enum.rb +24 -17
- data/lib/graphql/schema/enum_value.rb +5 -3
- data/lib/graphql/schema/field.rb +53 -45
- data/lib/graphql/schema/interface.rb +0 -10
- data/lib/graphql/schema/late_bound_type.rb +2 -0
- data/lib/graphql/schema/member/base_dsl_methods.rb +15 -14
- data/lib/graphql/schema/member/has_arguments.rb +104 -57
- data/lib/graphql/schema/member/has_deprecation_reason.rb +3 -4
- data/lib/graphql/schema/member/has_fields.rb +14 -2
- data/lib/graphql/schema/member/has_interfaces.rb +49 -8
- data/lib/graphql/schema/member/has_validators.rb +31 -5
- data/lib/graphql/schema/member/type_system_helpers.rb +17 -0
- data/lib/graphql/schema/object.rb +2 -4
- data/lib/graphql/schema/resolver/has_payload_type.rb +9 -9
- data/lib/graphql/schema/timeout.rb +23 -27
- data/lib/graphql/schema/warden.rb +26 -4
- data/lib/graphql/schema.rb +37 -19
- data/lib/graphql/static_validation/literal_validator.rb +15 -1
- data/lib/graphql/static_validation/validator.rb +1 -1
- data/lib/graphql/subscriptions/event.rb +2 -7
- data/lib/graphql/tracing/active_support_notifications_trace.rb +16 -0
- data/lib/graphql/tracing/appoptics_trace.rb +231 -0
- data/lib/graphql/tracing/appsignal_trace.rb +66 -0
- data/lib/graphql/tracing/data_dog_trace.rb +148 -0
- data/lib/graphql/tracing/new_relic_trace.rb +75 -0
- data/lib/graphql/tracing/notifications_trace.rb +41 -0
- data/lib/graphql/tracing/platform_trace.rb +107 -0
- data/lib/graphql/tracing/platform_tracing.rb +15 -3
- data/lib/graphql/tracing/prometheus_trace.rb +89 -0
- data/lib/graphql/tracing/prometheus_tracing.rb +3 -3
- data/lib/graphql/tracing/scout_trace.rb +72 -0
- data/lib/graphql/tracing/statsd_trace.rb +56 -0
- data/lib/graphql/tracing.rb +136 -39
- data/lib/graphql/type_kinds.rb +6 -3
- data/lib/graphql/types/relay/connection_behaviors.rb +0 -4
- data/lib/graphql/types/relay/edge_behaviors.rb +0 -4
- data/lib/graphql/types/string.rb +1 -1
- data/lib/graphql/version.rb +1 -1
- data/lib/graphql.rb +7 -8
- metadata +15 -4
- data/lib/graphql/language/lexer.rl +0 -280
@@ -141,18 +141,26 @@ module GraphQL
|
|
141
141
|
.gsub(/([a-z])([A-Z])/,'\1_\2') # insert underscores
|
142
142
|
.downcase # remove caps
|
143
143
|
|
144
|
-
child_class.module_eval <<-RUBY
|
144
|
+
child_class.module_eval <<-RUBY, __FILE__, __LINE__
|
145
145
|
def visit_method
|
146
146
|
:on_#{name_underscored}
|
147
147
|
end
|
148
148
|
|
149
149
|
class << self
|
150
150
|
attr_accessor :children_method_name
|
151
|
+
|
152
|
+
def visit_method
|
153
|
+
:on_#{name_underscored}
|
154
|
+
end
|
151
155
|
end
|
152
156
|
self.children_method_name = :#{name_underscored}s
|
153
157
|
RUBY
|
154
158
|
end
|
155
159
|
|
160
|
+
def children_of_type
|
161
|
+
@children_methods
|
162
|
+
end
|
163
|
+
|
156
164
|
private
|
157
165
|
|
158
166
|
# Name accessors which return lists of nodes,
|
@@ -300,7 +308,7 @@ module GraphQL
|
|
300
308
|
# @return [String] the key for this argument
|
301
309
|
|
302
310
|
# @!attribute value
|
303
|
-
# @return [String, Float, Integer, Boolean, Array, InputObject] The value passed for this key
|
311
|
+
# @return [String, Float, Integer, Boolean, Array, InputObject, VariableIdentifier] The value passed for this key
|
304
312
|
|
305
313
|
def children
|
306
314
|
@children ||= Array(value).flatten.select { |v| v.is_a?(AbstractNode) }
|
@@ -325,35 +333,6 @@ module GraphQL
|
|
325
333
|
)
|
326
334
|
end
|
327
335
|
|
328
|
-
# This is the AST root for normal queries
|
329
|
-
#
|
330
|
-
# @example Deriving a document by parsing a string
|
331
|
-
# document = GraphQL.parse(query_string)
|
332
|
-
#
|
333
|
-
# @example Creating a string from a document
|
334
|
-
# document.to_query_string
|
335
|
-
# # { ... }
|
336
|
-
#
|
337
|
-
# @example Creating a custom string from a document
|
338
|
-
# class VariableScrubber < GraphQL::Language::Printer
|
339
|
-
# def print_argument(arg)
|
340
|
-
# "#{arg.name}: <HIDDEN>"
|
341
|
-
# end
|
342
|
-
# end
|
343
|
-
#
|
344
|
-
# document.to_query_string(printer: VariableScrubber.new)
|
345
|
-
#
|
346
|
-
class Document < AbstractNode
|
347
|
-
scalar_methods false
|
348
|
-
children_methods(definitions: nil)
|
349
|
-
# @!attribute definitions
|
350
|
-
# @return [Array<OperationDefinition, FragmentDefinition>] top-level GraphQL units: operations or fragments
|
351
|
-
|
352
|
-
def slice_definition(name)
|
353
|
-
GraphQL::Language::DefinitionSlice.slice(self, name)
|
354
|
-
end
|
355
|
-
end
|
356
|
-
|
357
336
|
# An enum value. The string is available as {#name}.
|
358
337
|
class Enum < NameOnlyNode
|
359
338
|
end
|
@@ -526,6 +505,35 @@ module GraphQL
|
|
526
505
|
self.children_method_name = :definitions
|
527
506
|
end
|
528
507
|
|
508
|
+
# This is the AST root for normal queries
|
509
|
+
#
|
510
|
+
# @example Deriving a document by parsing a string
|
511
|
+
# document = GraphQL.parse(query_string)
|
512
|
+
#
|
513
|
+
# @example Creating a string from a document
|
514
|
+
# document.to_query_string
|
515
|
+
# # { ... }
|
516
|
+
#
|
517
|
+
# @example Creating a custom string from a document
|
518
|
+
# class VariableScrubber < GraphQL::Language::Printer
|
519
|
+
# def print_argument(arg)
|
520
|
+
# "#{arg.name}: <HIDDEN>"
|
521
|
+
# end
|
522
|
+
# end
|
523
|
+
#
|
524
|
+
# document.to_query_string(printer: VariableScrubber.new)
|
525
|
+
#
|
526
|
+
class Document < AbstractNode
|
527
|
+
scalar_methods false
|
528
|
+
children_methods(definitions: nil)
|
529
|
+
# @!attribute definitions
|
530
|
+
# @return [Array<OperationDefinition, FragmentDefinition>] top-level GraphQL units: operations or fragments
|
531
|
+
|
532
|
+
def slice_definition(name)
|
533
|
+
GraphQL::Language::DefinitionSlice.slice(self, name)
|
534
|
+
end
|
535
|
+
end
|
536
|
+
|
529
537
|
# A type name, used for variable definitions
|
530
538
|
class TypeName < NameOnlyNode
|
531
539
|
end
|
@@ -16,22 +16,22 @@ module_eval(<<'...end parser.y/module_eval...', 'parser.y', 448)
|
|
16
16
|
|
17
17
|
EMPTY_ARRAY = [].freeze
|
18
18
|
|
19
|
-
def initialize(query_string, filename:,
|
19
|
+
def initialize(query_string, filename:, trace: Tracing::NullTrace)
|
20
20
|
raise GraphQL::ParseError.new("No query string was present", nil, nil, query_string) if query_string.nil?
|
21
21
|
@query_string = query_string
|
22
22
|
@filename = filename
|
23
|
-
@
|
23
|
+
@trace = trace
|
24
24
|
@reused_next_token = [nil, nil]
|
25
25
|
end
|
26
26
|
|
27
27
|
def parse_document
|
28
28
|
@document ||= begin
|
29
29
|
# Break the string into tokens
|
30
|
-
@
|
30
|
+
@trace.lex(query_string: @query_string) do
|
31
31
|
@tokens ||= GraphQL.scan(@query_string)
|
32
32
|
end
|
33
33
|
# From the tokens, build an AST
|
34
|
-
@
|
34
|
+
@trace.parse(query_string: @query_string) do
|
35
35
|
if @tokens.empty?
|
36
36
|
raise GraphQL::ParseError.new("Unexpected end of document", nil, nil, @query_string)
|
37
37
|
else
|
@@ -44,17 +44,17 @@ end
|
|
44
44
|
class << self
|
45
45
|
attr_accessor :cache
|
46
46
|
|
47
|
-
def parse(query_string, filename: nil,
|
48
|
-
new(query_string, filename: filename,
|
47
|
+
def parse(query_string, filename: nil, trace: GraphQL::Tracing::NullTrace)
|
48
|
+
new(query_string, filename: filename, trace: trace).parse_document
|
49
49
|
end
|
50
50
|
|
51
|
-
def parse_file(filename,
|
51
|
+
def parse_file(filename, trace: GraphQL::Tracing::NullTrace)
|
52
52
|
if cache
|
53
53
|
cache.fetch(filename) do
|
54
|
-
parse(File.read(filename), filename: filename,
|
54
|
+
parse(File.read(filename), filename: filename, trace: trace)
|
55
55
|
end
|
56
56
|
else
|
57
|
-
parse(File.read(filename), filename: filename,
|
57
|
+
parse(File.read(filename), filename: filename, trace: trace)
|
58
58
|
end
|
59
59
|
end
|
60
60
|
end
|
@@ -448,22 +448,22 @@ end
|
|
448
448
|
|
449
449
|
EMPTY_ARRAY = [].freeze
|
450
450
|
|
451
|
-
def initialize(query_string, filename:,
|
451
|
+
def initialize(query_string, filename:, trace: Tracing::NullTrace)
|
452
452
|
raise GraphQL::ParseError.new("No query string was present", nil, nil, query_string) if query_string.nil?
|
453
453
|
@query_string = query_string
|
454
454
|
@filename = filename
|
455
|
-
@
|
455
|
+
@trace = trace
|
456
456
|
@reused_next_token = [nil, nil]
|
457
457
|
end
|
458
458
|
|
459
459
|
def parse_document
|
460
460
|
@document ||= begin
|
461
461
|
# Break the string into tokens
|
462
|
-
@
|
462
|
+
@trace.lex(query_string: @query_string) do
|
463
463
|
@tokens ||= GraphQL.scan(@query_string)
|
464
464
|
end
|
465
465
|
# From the tokens, build an AST
|
466
|
-
@
|
466
|
+
@trace.parse(query_string: @query_string) do
|
467
467
|
if @tokens.empty?
|
468
468
|
raise GraphQL::ParseError.new("Unexpected end of document", nil, nil, @query_string)
|
469
469
|
else
|
@@ -476,17 +476,17 @@ end
|
|
476
476
|
class << self
|
477
477
|
attr_accessor :cache
|
478
478
|
|
479
|
-
def parse(query_string, filename: nil,
|
480
|
-
new(query_string, filename: filename,
|
479
|
+
def parse(query_string, filename: nil, trace: GraphQL::Tracing::NullTrace)
|
480
|
+
new(query_string, filename: filename, trace: trace).parse_document
|
481
481
|
end
|
482
482
|
|
483
|
-
def parse_file(filename,
|
483
|
+
def parse_file(filename, trace: GraphQL::Tracing::NullTrace)
|
484
484
|
if cache
|
485
485
|
cache.fetch(filename) do
|
486
|
-
parse(File.read(filename), filename: filename,
|
486
|
+
parse(File.read(filename), filename: filename, trace: trace)
|
487
487
|
end
|
488
488
|
else
|
489
|
-
parse(File.read(filename), filename: filename,
|
489
|
+
parse(File.read(filename), filename: filename, trace: trace)
|
490
490
|
end
|
491
491
|
end
|
492
492
|
end
|
@@ -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,210 @@ module GraphQL
|
|
74
76
|
end
|
75
77
|
end
|
76
78
|
|
77
|
-
#
|
78
|
-
def
|
79
|
-
|
80
|
-
|
79
|
+
# We don't use `alias` here because it breaks `super`
|
80
|
+
def self.make_visit_methods(ast_node_class)
|
81
|
+
node_method = ast_node_class.visit_method
|
82
|
+
children_of_type = ast_node_class.children_of_type
|
83
|
+
child_visit_method = :"#{node_method}_children"
|
81
84
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
85
|
+
class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
|
86
|
+
# The default implementation for visiting an AST node.
|
87
|
+
# It doesn't _do_ anything, but it continues to visiting the node's children.
|
88
|
+
# To customize this hook, override one of its make_visit_methods (or the base method?)
|
89
|
+
# in your subclasses.
|
90
|
+
#
|
91
|
+
# For compatibility, it calls hook procs, too.
|
92
|
+
# @param node [GraphQL::Language::Nodes::AbstractNode] the node being visited
|
93
|
+
# @param parent [GraphQL::Language::Nodes::AbstractNode, nil] the previously-visited node, or `nil` if this is the root node.
|
94
|
+
# @return [Array, nil] If there were modifications, it returns an array of new nodes, otherwise, it returns `nil`.
|
95
|
+
def #{node_method}(node, parent)
|
96
|
+
if node.equal?(DELETE_NODE)
|
97
|
+
# This might be passed to `super(DELETE_NODE, ...)`
|
98
|
+
# by a user hook, don't want to keep visiting in that case.
|
99
|
+
[node, parent]
|
100
|
+
else
|
101
|
+
# Run hooks if there are any
|
102
|
+
new_node = node
|
103
|
+
no_hooks = !@visitors.key?(node.class)
|
104
|
+
if no_hooks || begin_visit(new_node, parent)
|
105
|
+
#{
|
106
|
+
if method_defined?(child_visit_method)
|
107
|
+
"new_node = #{child_visit_method}(new_node)"
|
108
|
+
elsif children_of_type
|
109
|
+
children_of_type.map do |child_accessor, child_class|
|
110
|
+
"node.#{child_accessor}.each do |child_node|
|
111
|
+
new_child_and_node = #{child_class.visit_method}_with_modifications(child_node, new_node)
|
112
|
+
# Reassign `node` in case the child hook makes a modification
|
113
|
+
if new_child_and_node.is_a?(Array)
|
114
|
+
new_node = new_child_and_node[1]
|
115
|
+
end
|
116
|
+
end"
|
117
|
+
end.join("\n")
|
118
|
+
else
|
119
|
+
""
|
120
|
+
end
|
121
|
+
}
|
122
|
+
end
|
123
|
+
end_visit(new_node, parent) unless no_hooks
|
124
|
+
|
125
|
+
if new_node.equal?(node)
|
126
|
+
[node, parent]
|
127
|
+
else
|
128
|
+
[new_node, parent]
|
106
129
|
end
|
107
130
|
end
|
108
131
|
end
|
109
|
-
end_visit(new_node, parent) unless no_hooks
|
110
132
|
|
111
|
-
|
112
|
-
|
133
|
+
def #{node_method}_with_modifications(node, parent)
|
134
|
+
new_node_and_new_parent = #{node_method}(node, parent)
|
135
|
+
apply_modifications(node, parent, new_node_and_new_parent)
|
136
|
+
end
|
137
|
+
RUBY
|
138
|
+
end
|
139
|
+
|
140
|
+
def on_document_children(document_node)
|
141
|
+
new_node = document_node
|
142
|
+
document_node.children.each do |child_node|
|
143
|
+
visit_method = :"#{child_node.visit_method}_with_modifications"
|
144
|
+
new_child_and_node = public_send(visit_method, child_node, new_node)
|
145
|
+
# Reassign `node` in case the child hook makes a modification
|
146
|
+
if new_child_and_node.is_a?(Array)
|
147
|
+
new_node = new_child_and_node[1]
|
148
|
+
end
|
149
|
+
end
|
150
|
+
new_node
|
151
|
+
end
|
152
|
+
|
153
|
+
def on_field_children(new_node)
|
154
|
+
new_node.arguments.each do |arg_node| # rubocop:disable Development/ContextIsPassedCop
|
155
|
+
new_child_and_node = on_argument_with_modifications(arg_node, new_node)
|
156
|
+
# Reassign `node` in case the child hook makes a modification
|
157
|
+
if new_child_and_node.is_a?(Array)
|
158
|
+
new_node = new_child_and_node[1]
|
159
|
+
end
|
160
|
+
end
|
161
|
+
new_node = visit_directives(new_node)
|
162
|
+
new_node = visit_selections(new_node)
|
163
|
+
new_node
|
164
|
+
end
|
165
|
+
|
166
|
+
def visit_directives(new_node)
|
167
|
+
new_node.directives.each do |dir_node|
|
168
|
+
new_child_and_node = on_directive_with_modifications(dir_node, new_node)
|
169
|
+
# Reassign `node` in case the child hook makes a modification
|
170
|
+
if new_child_and_node.is_a?(Array)
|
171
|
+
new_node = new_child_and_node[1]
|
172
|
+
end
|
173
|
+
end
|
174
|
+
new_node
|
175
|
+
end
|
176
|
+
|
177
|
+
def visit_selections(new_node)
|
178
|
+
new_node.selections.each do |selection|
|
179
|
+
new_child_and_node = case selection
|
180
|
+
when GraphQL::Language::Nodes::Field
|
181
|
+
on_field_with_modifications(selection, new_node)
|
182
|
+
when GraphQL::Language::Nodes::InlineFragment
|
183
|
+
on_inline_fragment_with_modifications(selection, new_node)
|
184
|
+
when GraphQL::Language::Nodes::FragmentSpread
|
185
|
+
on_fragment_spread_with_modifications(selection, new_node)
|
113
186
|
else
|
114
|
-
|
187
|
+
raise ArgumentError, "Invariant: unexpected field selection #{selection.class} (#{selection.inspect})"
|
188
|
+
end
|
189
|
+
# Reassign `node` in case the child hook makes a modification
|
190
|
+
if new_child_and_node.is_a?(Array)
|
191
|
+
new_node = new_child_and_node[1]
|
115
192
|
end
|
116
193
|
end
|
194
|
+
new_node
|
117
195
|
end
|
118
196
|
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
197
|
+
def on_fragment_definition_children(new_node)
|
198
|
+
new_node = visit_directives(new_node)
|
199
|
+
new_node = visit_selections(new_node)
|
200
|
+
new_node
|
201
|
+
end
|
202
|
+
|
203
|
+
alias :on_inline_fragment_children :on_fragment_definition_children
|
204
|
+
|
205
|
+
def on_operation_definition_children(new_node)
|
206
|
+
new_node.variables.each do |arg_node|
|
207
|
+
new_child_and_node = on_variable_definition_with_modifications(arg_node, new_node)
|
208
|
+
# Reassign `node` in case the child hook makes a modification
|
209
|
+
if new_child_and_node.is_a?(Array)
|
210
|
+
new_node = new_child_and_node[1]
|
126
211
|
end
|
127
|
-
|
212
|
+
end
|
213
|
+
new_node = visit_directives(new_node)
|
214
|
+
new_node = visit_selections(new_node)
|
215
|
+
new_node
|
216
|
+
end
|
217
|
+
|
218
|
+
def on_argument_children(new_node)
|
219
|
+
new_node.children.each do |value_node|
|
220
|
+
new_child_and_node = case value_node
|
221
|
+
when Language::Nodes::VariableIdentifier
|
222
|
+
on_variable_identifier_with_modifications(value_node, new_node)
|
223
|
+
when Language::Nodes::InputObject
|
224
|
+
on_input_object_with_modifications(value_node, new_node)
|
225
|
+
when Language::Nodes::Enum
|
226
|
+
on_enum_with_modifications(value_node, new_node)
|
227
|
+
when Language::Nodes::NullValue
|
228
|
+
on_null_value_with_modifications(value_node, new_node)
|
229
|
+
else
|
230
|
+
raise ArgumentError, "Invariant: unexpected argument value node #{value_node.class} (#{value_node.inspect})"
|
231
|
+
end
|
232
|
+
# Reassign `node` in case the child hook makes a modification
|
233
|
+
if new_child_and_node.is_a?(Array)
|
234
|
+
new_node = new_child_and_node[1]
|
235
|
+
end
|
236
|
+
end
|
237
|
+
new_node
|
128
238
|
end
|
129
239
|
|
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
|
-
|
240
|
+
[
|
241
|
+
Language::Nodes::Argument,
|
242
|
+
Language::Nodes::Directive,
|
243
|
+
Language::Nodes::DirectiveDefinition,
|
244
|
+
Language::Nodes::DirectiveLocation,
|
245
|
+
Language::Nodes::Document,
|
246
|
+
Language::Nodes::Enum,
|
247
|
+
Language::Nodes::EnumTypeDefinition,
|
248
|
+
Language::Nodes::EnumTypeExtension,
|
249
|
+
Language::Nodes::EnumValueDefinition,
|
250
|
+
Language::Nodes::Field,
|
251
|
+
Language::Nodes::FieldDefinition,
|
252
|
+
Language::Nodes::FragmentDefinition,
|
253
|
+
Language::Nodes::FragmentSpread,
|
254
|
+
Language::Nodes::InlineFragment,
|
255
|
+
Language::Nodes::InputObject,
|
256
|
+
Language::Nodes::InputObjectTypeDefinition,
|
257
|
+
Language::Nodes::InputObjectTypeExtension,
|
258
|
+
Language::Nodes::InputValueDefinition,
|
259
|
+
Language::Nodes::InterfaceTypeDefinition,
|
260
|
+
Language::Nodes::InterfaceTypeExtension,
|
261
|
+
Language::Nodes::ListType,
|
262
|
+
Language::Nodes::NonNullType,
|
263
|
+
Language::Nodes::NullValue,
|
264
|
+
Language::Nodes::ObjectTypeDefinition,
|
265
|
+
Language::Nodes::ObjectTypeExtension,
|
266
|
+
Language::Nodes::OperationDefinition,
|
267
|
+
Language::Nodes::ScalarTypeDefinition,
|
268
|
+
Language::Nodes::ScalarTypeExtension,
|
269
|
+
Language::Nodes::SchemaDefinition,
|
270
|
+
Language::Nodes::SchemaExtension,
|
271
|
+
Language::Nodes::TypeName,
|
272
|
+
Language::Nodes::UnionTypeDefinition,
|
273
|
+
Language::Nodes::UnionTypeExtension,
|
274
|
+
Language::Nodes::VariableDefinition,
|
275
|
+
Language::Nodes::VariableIdentifier,
|
276
|
+
].each do |ast_node_class|
|
277
|
+
make_visit_methods(ast_node_class)
|
278
|
+
end
|
165
279
|
|
166
280
|
private
|
167
281
|
|
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)
|
282
|
+
def apply_modifications(node, parent, new_node_and_new_parent)
|
175
283
|
if new_node_and_new_parent.is_a?(Array)
|
176
284
|
new_node = new_node_and_new_parent[0]
|
177
285
|
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
|
@@ -72,6 +72,18 @@ module GraphQL
|
|
72
72
|
# @return [Array<String, Integer>] The current position in the result
|
73
73
|
attr_reader :path
|
74
74
|
|
75
|
+
module EmptyScopedContext
|
76
|
+
EMPTY_HASH = {}.freeze
|
77
|
+
|
78
|
+
def self.key?(k)
|
79
|
+
false
|
80
|
+
end
|
81
|
+
|
82
|
+
def self.merged_context
|
83
|
+
EMPTY_HASH
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
75
87
|
# Make a new context which delegates key lookup to `values`
|
76
88
|
# @param query [GraphQL::Query] the query who owns this context
|
77
89
|
# @param values [Hash] A hash of arbitrary values which will be accessible at query-time
|
@@ -87,13 +99,14 @@ module GraphQL
|
|
87
99
|
@path = []
|
88
100
|
@value = nil
|
89
101
|
@context = self # for SharedMethods TODO delete sharedmethods
|
90
|
-
@scoped_context =
|
102
|
+
@scoped_context = EmptyScopedContext
|
91
103
|
end
|
92
104
|
|
93
105
|
class ScopedContext
|
94
106
|
def initialize(query_context)
|
95
107
|
@query_context = query_context
|
96
108
|
@scoped_contexts = {}
|
109
|
+
@all_keys = Set.new
|
97
110
|
@no_path = [].freeze
|
98
111
|
end
|
99
112
|
|
@@ -106,6 +119,7 @@ module GraphQL
|
|
106
119
|
end
|
107
120
|
|
108
121
|
def merge!(hash)
|
122
|
+
@all_keys.merge(hash.keys)
|
109
123
|
ctx = @scoped_contexts
|
110
124
|
current_path.each do |path_part|
|
111
125
|
ctx = ctx[path_part] ||= { parent: ctx }
|
@@ -114,15 +128,12 @@ module GraphQL
|
|
114
128
|
this_scoped_ctx.merge!(hash)
|
115
129
|
end
|
116
130
|
|
117
|
-
def current_path
|
118
|
-
thread_info = Thread.current[:__graphql_runtime_info]
|
119
|
-
(thread_info && thread_info[:current_path]) || @no_path
|
120
|
-
end
|
121
|
-
|
122
131
|
def key?(key)
|
123
|
-
|
124
|
-
|
125
|
-
|
132
|
+
if @all_keys.include?(key)
|
133
|
+
each_present_path_ctx do |path_ctx|
|
134
|
+
if path_ctx.key?(key)
|
135
|
+
return true
|
136
|
+
end
|
126
137
|
end
|
127
138
|
end
|
128
139
|
false
|
@@ -137,6 +148,10 @@ module GraphQL
|
|
137
148
|
nil
|
138
149
|
end
|
139
150
|
|
151
|
+
def current_path
|
152
|
+
@query_context.current_path || @no_path
|
153
|
+
end
|
154
|
+
|
140
155
|
def dig(key, *other_keys)
|
141
156
|
each_present_path_ctx do |path_ctx|
|
142
157
|
if path_ctx.key?(key)
|
@@ -209,14 +224,30 @@ module GraphQL
|
|
209
224
|
elsif @provided_values.key?(key)
|
210
225
|
@provided_values[key]
|
211
226
|
elsif RUNTIME_METADATA_KEYS.include?(key)
|
212
|
-
|
213
|
-
|
227
|
+
if key == :current_path
|
228
|
+
current_path
|
229
|
+
else
|
230
|
+
thread_info = Thread.current[:__graphql_runtime_info]
|
231
|
+
thread_info && thread_info[key]
|
232
|
+
end
|
214
233
|
else
|
215
234
|
# not found
|
216
235
|
nil
|
217
236
|
end
|
218
237
|
end
|
219
238
|
|
239
|
+
def current_path
|
240
|
+
thread_info = Thread.current[:__graphql_runtime_info]
|
241
|
+
path = thread_info &&
|
242
|
+
(result = thread_info[:current_result]) &&
|
243
|
+
(result.path)
|
244
|
+
if path && (rn = thread_info[:current_result_name])
|
245
|
+
path = path.dup
|
246
|
+
path.push(rn)
|
247
|
+
end
|
248
|
+
path
|
249
|
+
end
|
250
|
+
|
220
251
|
def delete(key)
|
221
252
|
if @scoped_context.key?(key)
|
222
253
|
@scoped_context.delete(key)
|
@@ -298,6 +329,9 @@ module GraphQL
|
|
298
329
|
end
|
299
330
|
|
300
331
|
def scoped_merge!(hash)
|
332
|
+
if @scoped_context == EmptyScopedContext
|
333
|
+
@scoped_context = ScopedContext.new(self)
|
334
|
+
end
|
301
335
|
@scoped_context.merge!(hash)
|
302
336
|
end
|
303
337
|
|