Class: GraphQL::Analysis::Visitor
- Inherits:
-
Language::StaticVisitor
- Object
- Language::StaticVisitor
- GraphQL::Analysis::Visitor
- Defined in:
- lib/graphql/analysis/visitor.rb
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
-
#object_types ⇒ Array<GraphQL::ObjectType>
readonly
Types whose scope we’ve entered.
-
#query ⇒ GraphQL::Query
readonly
The query being visited.
-
#rescued_errors ⇒ Array<GraphQL::AnalysisError]
readonly
Array<GraphQL::AnalysisError].
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:) ⇒ Visitor
constructor
A new instance of Visitor.
-
#on_argument(node, parent) ⇒ Object
-
#on_directive(node, parent) ⇒ Object
-
#on_field(node, parent) ⇒ Object
-
#on_fragment_definition(node, parent) ⇒ Object
-
#on_fragment_spread(node, parent) ⇒ Object
-
#on_inline_fragment(node, parent) ⇒ Object
-
#on_operation_definition(node, parent) ⇒ Object
-
#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
The current object type.
-
#visit ⇒ Object
-
#visiting_fragment_definition? ⇒ Boolean
If the visitor is currently inside a fragment definition.
Methods inherited from Language::StaticVisitor
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:) ⇒ Visitor
Returns a new instance of Visitor.
13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
# File 'lib/graphql/analysis/visitor.rb', line 13 def initialize(query:, analyzers:) @analyzers = analyzers @path = [] @object_types = [] @directives = [] @field_definitions = [] @argument_definitions = [] @directive_definitions = [] @rescued_errors = [] @query = query @schema = query.schema @response_path = [] @skip_stack = [false] super(query.selected_operation) end |
Instance Attribute Details
#object_types ⇒ Array<GraphQL::ObjectType> (readonly)
Returns Types whose scope we’ve entered.
33 34 35 |
# File 'lib/graphql/analysis/visitor.rb', line 33 def object_types @object_types end |
#query ⇒ GraphQL::Query (readonly)
Returns the query being visited.
30 31 32 |
# File 'lib/graphql/analysis/visitor.rb', line 30 def query @query end |
#rescued_errors ⇒ Array<GraphQL::AnalysisError] (readonly)
Returns Array<GraphQL::AnalysisError].
36 37 38 |
# File 'lib/graphql/analysis/visitor.rb', line 36 def rescued_errors @rescued_errors end |
Instance Method Details
#argument_definition ⇒ GraphQL::Argument?
Returns The most-recently-entered GraphQL::Argument, if currently inside one.
231 232 233 |
# File 'lib/graphql/analysis/visitor.rb', line 231 def argument_definition @argument_definitions.last end |
#arguments_for(ast_node, field_definition) ⇒ GraphQL::Execution::Interpreter::Arguments
Returns Arguments for this node, merging default values, literal values and query variables.
47 48 49 |
# File 'lib/graphql/analysis/visitor.rb', line 47 def arguments_for(ast_node, field_definition) @query.arguments_for(ast_node, field_definition) end |
#directive_definition ⇒ GraphQL::Directive?
Returns The most-recently-entered GraphQL::Directive, if currently inside one.
226 227 228 |
# File 'lib/graphql/analysis/visitor.rb', line 226 def directive_definition @directive_definitions.last end |
#field_definition ⇒ GraphQL::Field?
Returns The most-recently-entered GraphQL::Field, if currently inside one.
216 217 218 |
# File 'lib/graphql/analysis/visitor.rb', line 216 def field_definition @field_definitions.last end |
#on_argument(node, parent) ⇒ Object
166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 |
# File 'lib/graphql/analysis/visitor.rb', line 166 def on_argument(node, parent) argument_defn = if (arg = @argument_definitions.last) arg_type = arg.type.unwrap if arg_type.kind.input_object? arg_type.get_argument(node.name, @query.context) else nil end elsif (directive_defn = @directive_definitions.last) directive_defn.get_argument(node.name, @query.context) elsif (field_defn = @field_definitions.last) field_defn.get_argument(node.name, @query.context) 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
157 158 159 160 161 162 163 164 |
# File 'lib/graphql/analysis/visitor.rb', line 157 def on_directive(node, parent) 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 |
# File 'lib/graphql/analysis/visitor.rb', line 130 def on_field(node, parent) @response_path.push(node.alias || node.name) parent_type = @object_types.last # This could be nil if the previous field wasn't found: field_definition = parent_type && @schema.get_field(parent_type, node.name, @query.context) @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_definition(node, parent) ⇒ Object
106 107 108 109 110 111 112 113 114 115 |
# File 'lib/graphql/analysis/visitor.rb', line 106 def on_fragment_definition(node, parent) on_fragment_with_type(node) do @path.push("fragment #{node.name}") @in_fragment_def = false call_on_enter_fragment_definition(node, parent) super @in_fragment_def = false call_on_leave_fragment_definition(node, parent) end end |
#on_fragment_spread(node, parent) ⇒ Object
191 192 193 194 195 196 197 198 199 200 201 202 203 |
# File 'lib/graphql/analysis/visitor.rb', line 191 def on_fragment_spread(node, parent) @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
117 118 119 120 121 122 123 124 125 126 127 128 |
# File 'lib/graphql/analysis/visitor.rb', line 117 def on_inline_fragment(node, parent) on_fragment_with_type(node) do @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) end end |
#on_operation_definition(node, parent) ⇒ Object
95 96 97 98 99 100 101 102 103 104 |
# File 'lib/graphql/analysis/visitor.rb', line 95 def on_operation_definition(node, parent) 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
Returns The type which the current type came from.
211 212 213 |
# File 'lib/graphql/analysis/visitor.rb', line 211 def parent_type_definition @object_types[-2] end |
#previous_argument_definition ⇒ GraphQL::Argument?
Returns The previous GraphQL argument.
236 237 238 |
# File 'lib/graphql/analysis/visitor.rb', line 236 def previous_argument_definition @argument_definitions[-2] end |
#previous_field_definition ⇒ GraphQL::Field?
Returns The GraphQL field which returned the object that the current field belongs to.
221 222 223 |
# File 'lib/graphql/analysis/visitor.rb', line 221 def previous_field_definition @field_definitions[-2] end |
#response_path ⇒ Array<String>
Returns The path to the response key for the current field.
62 63 64 |
# File 'lib/graphql/analysis/visitor.rb', line 62 def response_path @response_path.dup end |
#skipping? ⇒ Boolean
Returns If the current node should be skipped because of a skip or include directive.
57 58 59 |
# File 'lib/graphql/analysis/visitor.rb', line 57 def skipping? @skipping end |
#type_definition ⇒ GraphQL::BaseType
Returns The current object type.
206 207 208 |
# File 'lib/graphql/analysis/visitor.rb', line 206 def type_definition @object_types.last end |
#visit ⇒ Object
38 39 40 41 |
# File 'lib/graphql/analysis/visitor.rb', line 38 def visit return unless @document super end |
#visiting_fragment_definition? ⇒ Boolean
Returns If the visitor is currently inside a fragment definition.
52 53 54 |
# File 'lib/graphql/analysis/visitor.rb', line 52 def visiting_fragment_definition? @in_fragment_def end |