def analyze_query(query, analyzers, multiplex_states: [])
      query.trace("analyze_query", { query: query }) do
        analyzers_to_run = analyzers.select do |analyzer|
          if analyzer.respond_to?(:analyze?)
            analyzer.analyze?(query)
          else
            true
          end
        end

        reducer_states = analyzers_to_run.map { |r| ReducerState.new(r, query) } + multiplex_states

        irep = query.internal_representation

        irep.operation_definitions.each do |name, op_node|
          reduce_node(op_node, reducer_states)
        end

        reducer_states.map(&:finalize_reducer)
      end
    end
def analyze_query(query, analyzers, multiplex_states: [])
      query.trace("analyze_query", { query: query }) do
        analyzers_to_run = analyzers.select do |analyzer|
          if analyzer.respond_to?(:analyze?)
            analyzer.analyze?(query)
          else
            true
          end
        end

        reducer_states = analyzers_to_run.map { |r| ReducerState.new(r, query) } + multiplex_states

        irep = query.internal_representation

        irep.operation_definitions.each do |name, op_node|
          reduce_node(op_node, reducer_states)
        end

        reducer_states.map(&:finalize_reducer)
      end
    end
Visit `query`'s internal representation, calling `analyzers` along the way.

 - First, query analyzers are filtered down by calling `.analyze?(query)`, if they respond to that method
 - Then, query analyzers are initialized by calling `.initial_value(query)`, if they respond to that method.
 - Then, they receive `.call(memo, visit_type, irep_node)`, where visit type is `:enter` or `:leave`.
 - Last, they receive `.final_value(memo)`, if they respond to that method.

 It returns an array of final `memo` values in the order that `analyzers` were passed in.

 @param query [GraphQL::Query]
 @param analyzers [Array<#call>] Objects that respond to `#call(memo, visit_type, irep_node)`
 @return [Array<Any>] Results from those analyzers