graphql 2.0.16 → 2.0.18
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
|