class GraphQL::Analysis::Visitor
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.
See GraphQL::Analysis::Analyzer AST Analyzers for queries
Attributes
Returns
-
Array<GraphQL::ObjectType>—Typeswhose scope we’ve entered
Returns
-
GraphQL::Query— the query being visited
Returns
-
Array<GraphQL::AnalysisError>— Array of errors rescued during analysis
Public Class Methods
# File lib/graphql/analysis/visitor.rb, line 14 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
GraphQL::Language::StaticVisitor::new
Public Instance Methods
# File lib/graphql/analysis/visitor.rb, line 293 def argument_definition @argument_definitions.last end
Returns
-
GraphQL::Argument, nil— The most-recently-entered GraphQL::Argument, if currently inside one
# File lib/graphql/analysis/visitor.rb, line 66 def arguments_for(ast_node, field_definition) @query.arguments_for(ast_node, field_definition) end
See GraphQL::Query#arguments_for
Returns
-
GraphQL::Execution::Interpreter::Arguments— Arguments for this node, merging default values, literal values and query variables
# File lib/graphql/analysis/visitor.rb, line 283 def directive_definition @directive_definitions.last end
Returns
-
GraphQL::Directive, nil— The most-recently-entered GraphQL::Directive, if currently inside one
# File lib/graphql/analysis/visitor.rb, line 263 def field_definition @field_definitions.last end
Returns
-
GraphQL::Field, nil— The most-recently-entered GraphQL::Field, if currently inside one
Source
# File lib/graphql/analysis/visitor.rb, line 196 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
Source
# File lib/graphql/analysis/visitor.rb, line 186 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
Source
# File lib/graphql/analysis/visitor.rb, line 158 def on_field(node, parent) check_timeout @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 && @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
# File lib/graphql/analysis/visitor.rb, line 222 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
# File lib/graphql/analysis/visitor.rb, line 139 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
# File lib/graphql/analysis/visitor.rb, line 127 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
rubocop:enable Development/NoEvalCop
# File lib/graphql/analysis/visitor.rb, line 253 def parent_type_definition @object_types[-2] end
Returns
-
GraphQL::BaseType— The type which the current type came from
# File lib/graphql/analysis/visitor.rb, line 303 def previous_argument_definition @argument_definitions[-2] end
Returns
-
GraphQL::Argument, nil— The previousGraphQLargument
# File lib/graphql/analysis/visitor.rb, line 273 def previous_field_definition @field_definitions[-2] end
Returns
-
GraphQL::Field, nil— TheGraphQLfield which returned the object that the current field belongs to
# File lib/graphql/analysis/visitor.rb, line 96 def response_path @response_path.dup end
Returns
-
Array<String>— The path to the response key for the current field
Source
# File lib/graphql/analysis/visitor.rb, line 86 def skipping? @skipping end
Returns
-
Boolean— If the current node should be skipped because of a skip or include directive
# File lib/graphql/analysis/visitor.rb, line 243 def type_definition @object_types.last end
Returns
-
GraphQL::BaseType— The current object type
Source
# File lib/graphql/analysis/visitor.rb, line 51 def visit return unless @document super end
GraphQL::Language::StaticVisitor#visit
# File lib/graphql/analysis/visitor.rb, line 76 def visiting_fragment_definition? @in_fragment_def end
Returns
-
Boolean— If the visitor is currently inside a fragment definition