class Activecube::Graphql::ParseTree::Element

Constants

KEY_FIELD_PREFIX
NULLABLE_OPERATORS
TYPENAME

Attributes

arguments[R]
ast_node[R]
children[R]
context_node[R]
cube[R]
definition[R]
dimension[R]
field[R]
key[R]
metric[R]
name[R]
parent[R]

Public Class Methods

new(cube, context_node, parent = nil) click to toggle source
# File lib/activecube/graphql/parse_tree.rb, line 13
def initialize cube, context_node, parent = nil

  @cube = cube
  @parent = parent

  @name = context_node.name
  @key = parent ? (parent.key ? "#{parent.key}.#{name}" : KEY_FIELD_PREFIX+name ) : nil

  @context_node = context_node
  @ast_node = context_node.ast_node

  @arguments =  sort_node_arguments ast_node, context_node.arguments.to_h


  if parent
    @definition = context_node.definitions.first.name
    if parent.dimension
      @dimension = parent.dimension
      @field = (parent.field || dimension)[definition.to_sym]
      raise Activecube::InputArgumentError, "#{definition} not implemented for #{key} in cube #{cube.name}" unless @field
    elsif !parent.metric
      if !(@metric = (cube.metrics && cube.metrics[definition.to_sym])) && !(@dimension = (cube.dimensions && cube.dimensions[definition.to_sym]))
        raise Activecube::InputArgumentError, "Metric or dimension #{definition} for #{key} not defined for cube #{cube.name}"
      end
    end
  end

  @children = context_node.typed_children.values.map(&:values).flatten.uniq(&:name).
      select{|child| child.name!=TYPENAME || union? }.
      collect do |child|
    Element.new cube, child, self
  end

end

Public Instance Methods

append_query(query) click to toggle source
# File lib/activecube/graphql/parse_tree.rb, line 68
def append_query query
  if parent

    if metric
      query = query.measure({key => apply_args(metric)})
    elsif dimension
      if children.empty?
        query = query.slice({key => apply_args(field || dimension)})
      elsif !arguments.empty?
        query = apply_args query
      end
    end

  else
    query = apply_args query, ( arguments && arguments.except('options'))
    query = apply_args query, ( arguments && arguments['options'] )
  end

  children.each do |child|
    query = child.append_query query
  end

  query
end
sort_node_arguments(ast_node, arguments) click to toggle source
# File lib/activecube/graphql/parse_tree.rb, line 48
def sort_node_arguments ast_node, arguments
  if (options = arguments['options']).kind_of?(Hash)
    options_keys = context_node.ast_node.arguments.detect{|x| x.name=='options'}.value.arguments.map{|x|
      x.name.underscore.to_sym
    }
    arguments['options'] = Hash[
        options_keys.collect{|key|
          raise "Unmatched key #{key}" unless options[key]
          [key, options[key]]
        }

    ]
  end
  arguments
end
union?() click to toggle source
# File lib/activecube/graphql/parse_tree.rb, line 64
def union?
  context_node.return_type.kind_of? GraphQL::UnionType
end

Private Instance Methods

applicable_operator?(operator, arg) click to toggle source
# File lib/activecube/graphql/parse_tree.rb, line 140
def applicable_operator? operator, arg
  !arg.nil? || NULLABLE_OPERATORS.include?(operator)
end
apply_args(element, args = self.arguments) click to toggle source
# File lib/activecube/graphql/parse_tree.rb, line 95
def apply_args element, args = self.arguments
  args && args.each_pair do |key, value|
    k = key.to_sym
    has_selectors = element.respond_to?(:selectors)
    if has_selectors && k==:any
      element = apply_or_selector element, value
    elsif has_selectors && (selector =  cube.selectors[k])
      if value.kind_of? Hash
        element = apply_selector element, k, value
      elsif value.kind_of? Array
        element = apply_to_array(element, k, selector, value)
      elsif !value.nil?
        element = element.when( selector.eq(value) )
      end
    elsif element.respond_to? k
      element = element.send(k, *converted_field_array(k, value))
    else
      raise Activecube::InputArgumentError, "Field #{k} is not implemented for #{element}"
    end

  end
  element
end
apply_or_selector(element, value) click to toggle source
# File lib/activecube/graphql/parse_tree.rb, line 144
def apply_or_selector element, value
  selectors = value.collect{|v| make_selector v }.compact
  element.when( Activecube::Query::Selector.or(selectors) )
end
apply_selector(element, k, hash) click to toggle source
# File lib/activecube/graphql/parse_tree.rb, line 131
def apply_selector element, k, hash
  hash.each_pair do |operator, arg|
    selector = cube.selectors[k]
    raise Activecube::InputArgumentError, "#{selector} does not handle method '#{operator}' for #{element} '#{k}'" unless selector.respond_to?(operator)
    element = element.when( selector.send(operator, arg) ) if applicable_operator?(operator, arg)
  end
  element
end
apply_to_array(element, k, selector, value) click to toggle source
# File lib/activecube/graphql/parse_tree.rb, line 167
def apply_to_array(element, k, selector, value)

  if !value.detect { |e| !e.kind_of? Hash }
    value.each { |v|
      element = apply_selector element, k, v
    }
  else
    element = element.when(selector.in(value))
  end
  element
end
converted_field_array(method, values) click to toggle source
# File lib/activecube/graphql/parse_tree.rb, line 120
def converted_field_array method, values
  case method
    when :desc,:asc
      values.collect{|v| KEY_FIELD_PREFIX + v}
    when :limit_by
      values.merge({each: KEY_FIELD_PREFIX + values[:each]})
    else
      values
    end
end
make_selector(hash) click to toggle source
# File lib/activecube/graphql/parse_tree.rb, line 149
def make_selector hash
  raise Activecube::InputArgumentError,  "Hash expected for selector, #{v} found instead" unless hash.kind_of?(Hash)
  selectors = hash.to_a.collect{|attr, expressions|
    k = attr.to_s.camelize(:lower).to_sym
    (expressions.kind_of?(Array) ? expressions : [expressions]).collect{|expression|
      expression.to_a.collect{|c|
        operator, arg  = c
        selector = cube.selectors[k]
        raise Activecube::InputArgumentError, "Selector not found for '#{k}'" unless selector
        raise Activecube::InputArgumentError, "#{selector} does not handle method '#{operator}' '#{k}'" unless selector.respond_to?(operator)
        selector.send(operator, arg) unless arg.nil?
        selector
      }
    }
  }.flatten
  Activecube::Query::Selector.and(selectors)
end