Class: GraphQL::Analysis::Visitor
Overview
Depth first traversal through a query AST, calling AST analyzers
along the way.
The visitor is a special case of GraphQL::Language::StaticVisitor, visiting
only the selected operation, providing helpers for common use cases such
as skipped fields and visiting fragment spreads.
Instance Attribute Summary collapse
Instance Method Summary
collapse
-
#argument_definition ⇒ GraphQL::Argument?
The most-recently-entered GraphQL::Argument, if currently inside one.
-
#arguments_for(ast_node, field_definition) ⇒ GraphQL::Execution::Interpreter::Arguments
Arguments for this node, merging default values, literal values and query variables.
-
#directive_definition ⇒ GraphQL::Directive?
The most-recently-entered GraphQL::Directive, if currently inside one.
-
#field_definition ⇒ GraphQL::Field?
The most-recently-entered GraphQL::Field, if currently inside one.
-
#initialize(query:, analyzers:, timeout:) ⇒ Visitor
constructor
A new instance of Visitor.
-
#on_argument(node, parent) ⇒ Object
-
#on_directive(node, parent) ⇒ Object
-
#on_field(node, parent) ⇒ Object
-
#on_fragment_spread(node, parent) ⇒ Object
-
#on_inline_fragment(node, parent) ⇒ Object
-
#on_operation_definition(node, parent) ⇒ Object
rubocop:enable Development/NoEvalCop.
-
#parent_type_definition ⇒ GraphQL::BaseType
The type which the current type came from.
-
#previous_argument_definition ⇒ GraphQL::Argument?
The previous GraphQL argument.
-
#previous_field_definition ⇒ GraphQL::Field?
The GraphQL field which returned the object that the current field belongs to.
-
#response_path ⇒ Array<String>
The path to the response key for the current field.
-
#skipping? ⇒ Boolean
If the current node should be skipped because of a skip or include directive.
-
#type_definition ⇒ GraphQL::BaseType
-
#visit ⇒ Object
-
#visiting_fragment_definition? ⇒ Boolean
If the visitor is currently inside a fragment definition.
make_visit_methods, #on_argument_children, #on_document_children, #on_field_children, #on_fragment_definition_children, #on_operation_definition_children, #visit_directives, #visit_selections
Constructor Details
#initialize(query:, analyzers:, timeout:) ⇒ Visitor
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
# File 'lib/graphql/analysis/visitor.rb', line 13
def initialize(query:, analyzers:, timeout:)
@analyzers = analyzers
@path = []
@object_types = []
@directives = []
@field_definitions = []
@argument_definitions = []
@directive_definitions = []
@rescued_errors = []
@query = query
@schema = query.schema
@types = query.types
@response_path = []
@skip_stack = [false]
@timeout_time = if timeout
Process.clock_gettime(Process::CLOCK_MONOTONIC, :float_second) + timeout
else
Float::INFINITY
end
super(query.selected_operation)
end
|
Instance Attribute Details
#object_types ⇒ Array<GraphQL::ObjectType>
39
40
41
|
# File 'lib/graphql/analysis/visitor.rb', line 39
def object_types
@object_types
end
|
36
37
38
|
# File 'lib/graphql/analysis/visitor.rb', line 36
def query
@query
end
|
42
43
44
|
# File 'lib/graphql/analysis/visitor.rb', line 42
def rescued_errors
@rescued_errors
end
|
Instance Method Details
#argument_definition ⇒ GraphQL::Argument?
235
236
237
|
# File 'lib/graphql/analysis/visitor.rb', line 235
def argument_definition
@argument_definitions.last
end
|
Returns Arguments for this node, merging default values, literal values and query variables.
53
54
55
|
# File 'lib/graphql/analysis/visitor.rb', line 53
def arguments_for(ast_node, field_definition)
@query.arguments_for(ast_node, field_definition)
end
|
#directive_definition ⇒ GraphQL::Directive?
230
231
232
|
# File 'lib/graphql/analysis/visitor.rb', line 230
def directive_definition
@directive_definitions.last
end
|
#field_definition ⇒ GraphQL::Field?
220
221
222
|
# File 'lib/graphql/analysis/visitor.rb', line 220
def field_definition
@field_definitions.last
end
|
#on_argument(node, parent) ⇒ Object
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
|
# File 'lib/graphql/analysis/visitor.rb', line 168
def on_argument(node, parent)
check_timeout
argument_defn = if (arg = @argument_definitions.last)
arg_type = arg.type.unwrap
if arg_type.kind.input_object?
@types.argument(arg_type, node.name)
else
nil
end
elsif (directive_defn = @directive_definitions.last)
@types.argument(directive_defn, node.name)
elsif (field_defn = @field_definitions.last)
@types.argument(field_defn, node.name)
else
nil
end
@argument_definitions.push(argument_defn)
@path.push(node.name)
call_on_enter_argument(node, parent)
super
call_on_leave_argument(node, parent)
@argument_definitions.pop
@path.pop
end
|
#on_directive(node, parent) ⇒ Object
158
159
160
161
162
163
164
165
166
|
# File 'lib/graphql/analysis/visitor.rb', line 158
def on_directive(node, parent)
check_timeout
directive_defn = @schema.directives[node.name]
@directive_definitions.push(directive_defn)
call_on_enter_directive(node, parent)
super
call_on_leave_directive(node, parent)
@directive_definitions.pop
end
|
#on_field(node, parent) ⇒ Object
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
|
# File 'lib/graphql/analysis/visitor.rb', line 130
def on_field(node, parent)
check_timeout
@response_path.push(node.alias || node.name)
parent_type = @object_types.last
field_definition = parent_type && @types.field(parent_type, node.name)
@field_definitions.push(field_definition)
if !field_definition.nil?
next_object_type = field_definition.type.unwrap
@object_types.push(next_object_type)
else
@object_types.push(nil)
end
@path.push(node.alias || node.name)
@skipping = @skip_stack.last || skip?(node)
@skip_stack << @skipping
call_on_enter_field(node, parent)
super
@skipping = @skip_stack.pop
call_on_leave_field(node, parent)
@response_path.pop
@field_definitions.pop
@object_types.pop
@path.pop
end
|
#on_fragment_spread(node, parent) ⇒ Object
194
195
196
197
198
199
200
201
202
203
204
205
206
207
|
# File 'lib/graphql/analysis/visitor.rb', line 194
def on_fragment_spread(node, parent)
check_timeout
@path.push("... #{node.name}")
@skipping = @skip_stack.last || skip?(node)
@skip_stack << @skipping
call_on_enter_fragment_spread(node, parent)
enter_fragment_spread_inline(node)
super
@skipping = @skip_stack.pop
leave_fragment_spread_inline(node)
call_on_leave_fragment_spread(node, parent)
@path.pop
end
|
#on_inline_fragment(node, parent) ⇒ Object
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
|
# File 'lib/graphql/analysis/visitor.rb', line 111
def on_inline_fragment(node, parent)
check_timeout
object_type = if node.type
@types.type(node.type.name)
else
@object_types.last
end
@object_types.push(object_type)
@path.push("...#{node.type ? " on #{node.type.name}" : ""}")
@skipping = @skip_stack.last || skip?(node)
@skip_stack << @skipping
call_on_enter_inline_fragment(node, parent)
super
@skipping = @skip_stack.pop
call_on_leave_inline_fragment(node, parent)
@object_types.pop
@path.pop
end
|
#on_operation_definition(node, parent) ⇒ Object
rubocop:enable Development/NoEvalCop
99
100
101
102
103
104
105
106
107
108
109
|
# File 'lib/graphql/analysis/visitor.rb', line 99
def on_operation_definition(node, parent)
check_timeout
object_type = @schema.root_type_for_operation(node.operation_type)
@object_types.push(object_type)
@path.push("#{node.operation_type}#{node.name ? " #{node.name}" : ""}")
call_on_enter_operation_definition(node, parent)
super
call_on_leave_operation_definition(node, parent)
@object_types.pop
@path.pop
end
|
#parent_type_definition ⇒ GraphQL::BaseType
215
216
217
|
# File 'lib/graphql/analysis/visitor.rb', line 215
def parent_type_definition
@object_types[-2]
end
|
#previous_argument_definition ⇒ GraphQL::Argument?
240
241
242
|
# File 'lib/graphql/analysis/visitor.rb', line 240
def previous_argument_definition
@argument_definitions[-2]
end
|
#previous_field_definition ⇒ GraphQL::Field?
225
226
227
|
# File 'lib/graphql/analysis/visitor.rb', line 225
def previous_field_definition
@field_definitions[-2]
end
|
#response_path ⇒ Array<String>
68
69
70
|
# File 'lib/graphql/analysis/visitor.rb', line 68
def response_path
@response_path.dup
end
|
#skipping? ⇒ Boolean
63
64
65
|
# File 'lib/graphql/analysis/visitor.rb', line 63
def skipping?
@skipping
end
|
#type_definition ⇒ GraphQL::BaseType
210
211
212
|
# File 'lib/graphql/analysis/visitor.rb', line 210
def type_definition
@object_types.last
end
|
#visit ⇒ Object
44
45
46
47
|
# File 'lib/graphql/analysis/visitor.rb', line 44
def visit
return unless @document
super
end
|
#visiting_fragment_definition? ⇒ Boolean
58
59
60
|
# File 'lib/graphql/analysis/visitor.rb', line 58
def visiting_fragment_definition?
@in_fragment_def
end
|