Module: Card::Query::CardQuery::Interpretation

Included in:
Card::Query::CardQuery
Defined in:
card/lib/card/query/card_query/interpretation.rb

Overview

Interpret CQL. Once interpreted, SQL can be generated.

Constant Summary collapse

INTERPRET_METHOD =
{ basic: :add_condition,
relational: :relate,
plus_relational: :relate_compound,
conjunction: :send }.freeze

Instance Method Summary collapse

Instance Method Details

#bad_attribute!(attribute) ⇒ Object

Raises:



68
69
70
# File 'card/lib/card/query/card_query/interpretation.rb', line 68

def bad_attribute! attribute
  raise Error::BadQuery, "Invalid attribute: #{attribute}"
end

#deprecated_attribute(attribute) ⇒ Object



64
65
66
# File 'card/lib/card/query/card_query/interpretation.rb', line 64

def deprecated_attribute attribute
  Rails.logger.info "Card queries no longer support #{attribute} attribute"
end

#interpret(clause) ⇒ Object

normalize and extract meaning from a clause

Parameters:

  • clause (Hash, String, Integer)

    statement or chunk thereof



13
14
15
16
17
# File 'card/lib/card/query/card_query/interpretation.rb', line 13

def interpret clause
  normalize_clause(clause).each do |key, val|
    interpret_item key, val
  end
end

#interpret_as_content?(key) ⇒ Boolean

Returns:

  • (Boolean)


29
30
31
32
33
# File 'card/lib/card/query/card_query/interpretation.rb', line 29

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) ⇒ Boolean

Returns:

  • (Boolean)


35
36
37
38
39
# File 'card/lib/card/query/card_query/interpretation.rb', line 35

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) ⇒ Object



45
46
47
48
49
50
51
52
# File 'card/lib/card/query/card_query/interpretation.rb', line 45

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) ⇒ Object



19
20
21
22
23
24
25
26
27
# File 'card/lib/card/query/card_query/interpretation.rb', line 19

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) ⇒ Object



41
42
43
# File 'card/lib/card/query/card_query/interpretation.rb', line 41

def interpret_modifier key, val
  @mods[key] = val.is_a?(Array) ? val : val.to_s
end

#no_method_for_attribute_type(attribute, type) ⇒ Object



54
55
56
57
58
59
60
61
62
# File 'card/lib/card/query/card_query/interpretation.rb', line 54

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 = {}) ⇒ Object



79
80
81
82
83
84
85
86
87
# File 'card/lib/card/query/card_query/interpretation.rb', line 79

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) ⇒ Object



72
73
74
75
76
77
# File 'card/lib/card/query/card_query/interpretation.rb', line 72

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

#relate_multi_value(method, key, val) ⇒ Object



89
90
91
92
93
94
95
96
97
# File 'card/lib/card/query/card_query/interpretation.rb', line 89

def relate_multi_value method, key, val
  conj = conjunction(val.first) ? conjunction(val.shift) : :and
  if conj == current_conjunction
    # same conjunction as container, no need for subcondition
    val.each { |v| send method, key, v }
  else
    send conj, (val.map { |v| { key => v } })
  end
end