module Card::Query::CardQuery::Interpretation

Interpret CQL. Once interpreted, SQL can be generated.

Constants

INTERPRET_METHOD

Public Instance Methods

bad_attribute!(attribute) click to toggle source
# File lib/card/query/card_query/interpretation.rb, line 69
def bad_attribute! attribute
  raise Error::BadQuery, "Invalid attribute: #{attribute}"
end
deprecated_attribute(attribute) click to toggle source
# File lib/card/query/card_query/interpretation.rb, line 65
def deprecated_attribute attribute
  Rails.logger.info "Card queries no longer support #{attribute} attribute"
end
interpret(clause) click to toggle source

normalize and extract meaning from a clause @param clause [Hash, String, Integer] statement or chunk thereof

# File lib/card/query/card_query/interpretation.rb, line 14
def interpret clause
  normalize_clause(clause).each do |key, val|
    interpret_item key, val
  end
end
interpret_as_content?(key) click to toggle source
# File lib/card/query/card_query/interpretation.rb, line 30
def interpret_as_content? key
  # eg "match" is both operator and attribute;
  # interpret as attribute when "match" is key
  OPERATORS.key?(key.to_s) && !Query.attributes[key]
end
interpret_as_modifier?(key, val) click to toggle source
# File lib/card/query/card_query/interpretation.rb, line 36
def interpret_as_modifier? key, val
  # eg when "sort" is hash, it can have subqueries
  # and must be interpreted like an attribute
  MODIFIERS.key?(key) && !val.is_a?(Hash)
end
interpret_attributes(attribute, val) click to toggle source
# File lib/card/query/card_query/interpretation.rb, line 46
def interpret_attributes attribute, val
  attribute_type = Query.attributes[attribute]
  if (method = INTERPRET_METHOD[attribute_type])
    send method, attribute, val
  else
    no_method_for_attribute_type attribute, attribute_type
  end
end
interpret_item(key, val) click to toggle source
# File lib/card/query/card_query/interpretation.rb, line 20
def interpret_item key, val
  if interpret_as_content? key
    interpret content: [key, val]
  elsif interpret_as_modifier? key, val
    interpret_modifier key, val
  else
    interpret_attributes key, val
  end
end
interpret_modifier(key, val) click to toggle source
# File lib/card/query/card_query/interpretation.rb, line 42
def interpret_modifier key, val
  @mods[key] = val.is_a?(Array) ? val : val.to_s
end
no_method_for_attribute_type(attribute, type) click to toggle source
# File lib/card/query/card_query/interpretation.rb, line 55
def no_method_for_attribute_type attribute, type
  return if type == :ignore

  if type == :deprecated
    deprecated_attribute attribute
  else
    bad_attribute! attribute
  end
end
relate(key, val, opts={}) click to toggle source
# File lib/card/query/card_query/interpretation.rb, line 80
def relate key, val, opts={}
  multiple = opts[:multiple].nil? ? val.is_a?(Array) : opts[:multiple]
  method = opts[:method] || :send

  if multiple
    relate_multi_value method, key, val
  else
    send method, key, val
  end
end
relate_compound(key, val) click to toggle source
# File lib/card/query/card_query/interpretation.rb, line 73
def relate_compound key, val
  has_multiple_values =
    val.is_a?(Array) &&
    (val.first.is_a?(Array) || conjunction(val.first).present?)
  relate key, val, multiple: has_multiple_values
end

Private Instance Methods

as_list_of_ids?(conj, key, val) click to toggle source

the list_of_ids optimization is intended to avoid unnecessary joins and can probably be applied more broadly, but in the name of caution, we went with an initial implementation that would only apply to reference attributes (because reference_query can handle lists of values)

# File lib/card/query/card_query/interpretation.rb, line 117
def as_list_of_ids? conj, key, val
  (conj == :or) &&
    key.to_s.start_with?(/refer|nest|include|link|member/) &&
    list_of_ids?(val)
end
relate_multi_value(method, key, val) click to toggle source
# File lib/card/query/card_query/interpretation.rb, line 93
def relate_multi_value method, key, val
  conj = conjunction(val.first) ? conjunction(val.shift) : :and
  if as_list_of_ids?(conj, key, val)
    relate key, val, multiple: false
  elsif conj == current_conjunction
    # same conjunction as container, no need for subcondition
    relate_multi_value_without_subcondition method, key, val
  else
    relate_multi_value_with_subcondition key, conj, val
  end
end
relate_multi_value_with_subcondition(key, conj, val) click to toggle source
# File lib/card/query/card_query/interpretation.rb, line 105
def relate_multi_value_with_subcondition key, conj, val
  send conj, (val.map { |v| { key => v } })
end
relate_multi_value_without_subcondition(method, key, val) click to toggle source
# File lib/card/query/card_query/interpretation.rb, line 109
def relate_multi_value_without_subcondition method, key, val
  val.each { |v| send method, key, v }
end