Class: Gitlab::Graphql::QueryAnalyzers::AST::RecursionAnalyzer

Inherits:
GraphQL::Analysis::AST::Analyzer
  • Object
show all
Defined in:
lib/gitlab/graphql/query_analyzers/ast/recursion_analyzer.rb

Constant Summary collapse

IGNORED_FIELDS =
%w[node edges nodes ofType].freeze
RECURSION_THRESHOLD =
2

Instance Method Summary collapse

Constructor Details

#initialize(query) ⇒ RecursionAnalyzer

Returns a new instance of RecursionAnalyzer.



13
14
15
16
17
18
# File 'lib/gitlab/graphql/query_analyzers/ast/recursion_analyzer.rb', line 13

def initialize(query)
  super

  @node_visits = {}
  @recurring_fields = {}
end

Instance Method Details

#on_enter_field(node, _parent, visitor) ⇒ Object



20
21
22
23
24
25
26
27
28
29
# File 'lib/gitlab/graphql/query_analyzers/ast/recursion_analyzer.rb', line 20

def on_enter_field(node, _parent, visitor)
  return if skip_node?(node, visitor)

  node_name = node.name
  node_visits[node_name] ||= 0
  node_visits[node_name] += 1

  times_encountered = @node_visits[node_name]
  recurring_fields[node_name] = times_encountered if recursion_too_deep?(node_name, times_encountered)
end

#on_leave_field(node, _parent, visitor) ⇒ Object

Visitors are all defined on the AST::Analyzer base class We override them for custom analyzers.



33
34
35
36
37
38
39
# File 'lib/gitlab/graphql/query_analyzers/ast/recursion_analyzer.rb', line 33

def on_leave_field(node, _parent, visitor)
  return if skip_node?(node, visitor)

  node_name = node.name
  node_visits[node_name] ||= 0
  node_visits[node_name] -= 1
end

#resultObject



41
42
43
44
45
46
47
48
49
50
# File 'lib/gitlab/graphql/query_analyzers/ast/recursion_analyzer.rb', line 41

def result
  @recurring_fields = @recurring_fields.select { |k, v| recursion_too_deep?(k, v) }

  if @recurring_fields.any?
    GraphQL::AnalysisError.new(<<~MSG)
      Recursive query - too many of fields '#{@recurring_fields}' detected
      in single branch of the query")
    MSG
  end
end