module OpticsAgent::Normalization::Query

Public Instance Methods

normalize(query_string) click to toggle source

query is a query string

# File lib/optics-agent/normalization/query.rb, line 9
def normalize(query_string)
  document = GraphQL.parse(query_string)

  # to store results
  output = ''
  used_fragment_names = []
  current = {}
  visitor = Visitor.new(document)

  stack = []
  Nodes.constants.each do |constant|
    mod = Nodes.const_get(constant)
    next unless mod.is_a? Module

    visitor[mod].enter << -> (_, _) do
      stack.unshift(
        arguments: [],
        directives: [],
        selections: []
      )
    end

    visitor[mod].leave << -> (_, _) { current = stack.shift }
  end

  visitor[Nodes::Argument].leave << -> (node, parent) do
    stack[0][:arguments] << "#{node.name}:#{genericize_type(node.value)}"
  end

  visitor[Nodes::Directive].leave << -> (node, parent) do
    id = "@#{node.name}"
    arguments = current[:arguments]
    unless arguments.empty?
      id << "(#{arguments.sort.join(', ')})"
    end
    stack[0][:directives] << id
  end

  visitor[Nodes::Field].leave << -> (node, parent) do
    id = node.name
    arguments = current[:arguments]
    unless arguments.empty?
      id << "(#{arguments.sort.join(', ')})"
    end
    directives = current[:directives]
    unless directives.empty?
      id << " #{directives.sort.join(' ')}"
    end
    selections = current[:selections]
    unless selections.empty?
      id << ' ' + block(selections)
    end

    stack[0][:selections] << id
  end

  visitor[Nodes::InlineFragment].leave << -> (node, parent) do
    selections = current[:selections]
    stack[0][:selections] << "... on #{node.type.name} #{block(selections)}"
  end

  visitor[Nodes::FragmentSpread].leave << -> (node, parent) do
    used_fragment_names << node.name
    stack[0][:selections] << "...#{node.name}"
  end

  visitor[Nodes::OperationDefinition].leave << -> (node, parent) do
    # no need to walk this, I don't think anything else can have vars
    vars = nil
    unless node.variables.empty?
      variable_strs = node.variables.sort_by(&:name).map do |variable|
        "$#{variable.name}:#{format_argument_type(variable.type)}"
      end
      vars = "(#{variable_strs.join(',')})"
    end

    query_content = block(current[:selections])
    if (node.name || vars || node.operation_type != 'query')
      parts = [node.operation_type]
      parts << "#{node.name}#{vars}" if (node.name || vars)
      parts << query_content
      output << parts.join(' ')
    else
      output << query_content
    end
  end

  visitor[Nodes::FragmentDefinition].leave << -> (node, parent) do
    selections = current[:selections]
    if (used_fragment_names.include?(node.name))
      output << " fragment #{node.name} on #{node.type.name} " \
        + block(selections)
    end
  end

  visitor.visit
  output
end

Private Instance Methods

block(array) click to toggle source
# File lib/optics-agent/normalization/query.rb, line 123
def block(array)
  if array.empty?
    '{}'
  else
    "{#{array.sort_by{ |x| sort_value(x) }.join(' ')}}"
  end
end
format_argument_type(type) click to toggle source
# File lib/optics-agent/normalization/query.rb, line 131
def format_argument_type(type)
  case type
  when Nodes::ListType
    "[#{format_argument_type(type.of_type)}]"
  when Nodes::NonNullType
    "#{format_argument_type(type.of_type)}!"
  else
    type.name
  end
end
genericize_type(value) click to toggle source
# File lib/optics-agent/normalization/query.rb, line 142
def genericize_type(value)
  case value
  when Nodes::VariableIdentifier
    "$#{value.name}"
  when String
    "\"\""
  when Numeric
    "0"
  when TrueClass, FalseClass
    value.to_s
  when Array
    "[]"
  when Nodes::Enum
    value.name
  when Nodes::InputObject
    "{}"
  end
end
sort_value(a) click to toggle source

See github.com/apollostack/optics-agent/blob/master/docs/signatures.md

# File lib/optics-agent/normalization/query.rb, line 111
def sort_value(a)
  type_value = if a[0..3] == '... '
    2
  elsif a[0..2] == '...'
    1
  else
    0
  end

  [type_value, a]
end