Module: Card::Query::Interpretation

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

Instance Method Summary collapse

Instance Method Details

#add_condition(*args) ⇒ Object



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

def add_condition *args
  @conditions <<
    if args.size > 1
      [args.shift, Value.new(args.shift, self)]
    else
      args[0]
    end
end

#all_joinsObject



120
121
122
123
# File 'lib/card/query/interpretation.rb', line 120

def all_joins
  @all_joins ||=
    (joins + subqueries.select(&:unjoined).map(&:all_joins)).flatten
end

#clause_to_hash(clause) ⇒ Object



51
52
53
54
55
56
57
58
# File 'lib/card/query/interpretation.rb', line 51

def clause_to_hash clause
  case clause
  when Hash              then clause
  when String, SmartName then { key: clause.to_name.key }
  when Integer           then { id: clause }
  else raise Card::Error::BadQuery, "Invalid query args #{clause.inspect}"
  end
end

#current_conjunctionObject



116
117
118
# File 'lib/card/query/interpretation.rb', line 116

def current_conjunction
  @mods[:conj].blank? ? :and : @mods[:conj]
end

#interpret(clause) ⇒ Object

normalize and extract meaning from a clause

Parameters:

  • clause (Hash, String, Integer)

    statement or chunk thereof



6
7
8
# File 'lib/card/query/interpretation.rb', line 6

def interpret clause
  interpret_by_key normalize_clause(clause)
end

#interpret_attributes(key, val) ⇒ Object



27
28
29
30
31
32
33
34
35
36
37
38
39
# File 'lib/card/query/interpretation.rb', line 27

def interpret_attributes key, val
  case ATTRIBUTES[key]
  when :basic            then add_condition key, val
  when :conjunction      then send key, val
  when :relational       then relate key, val
  when :special          then relate key, val
  when :ref_relational   then relate key, val, method: :join_references
  when :plus_relational  then relate_compound key, val
  when :ignore           then # noop
  else
    raise Card::Error::BadQuery, "Invalid attribute #{key}"
  end
end

#interpret_by_key(clause) ⇒ Object



10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# File 'lib/card/query/interpretation.rb', line 10

def interpret_by_key clause
  clause.each do |key, val|
    case
    when OPERATORS.key?(key.to_s) && !ATTRIBUTES[key]
      # eg "match" is both operator and attribute;
      # interpret as attribute when "match" is key
      interpret content: [key, val]
    when MODIFIERS.key?(key) && !clause[key].is_a?(Hash)
      # eg when "sort" is hash, it can have subqueries
      # and must be interpreted like an attribute
      @mods[key] = val.is_a?(Array) ? val : val.to_s
    else
      interpret_attributes key, val
    end
  end
end

#normalize_clause(clause) ⇒ Object



41
42
43
44
45
46
47
48
49
# File 'lib/card/query/interpretation.rb', line 41

def normalize_clause clause
  clause = clause_to_hash clause
  clause.symbolize_keys!
  clause.each do |key, val|
    next if key.to_sym == :return
    clause[key] = normalize_value val
  end
  clause
end

#normalize_string_value(val) ⇒ Object



69
70
71
72
73
74
75
76
77
78
# File 'lib/card/query/interpretation.rb', line 69

def normalize_string_value val
  case val.to_s
  when /^\$(\w+)$/                       # replace from @vars
    @vars[Regexp.last_match[1].to_sym].to_s.strip
  when /\b_/                             # absolutize based on @context
    val.to_name.to_absolute(context)
  else
    val
  end
end

#normalize_value(val) ⇒ Object



60
61
62
63
64
65
66
67
# File 'lib/card/query/interpretation.rb', line 60

def normalize_value val
  case val
  when Integer, Float, Symbol, Hash then val
  when String, SmartName            then normalize_string_value val
  when Array                        then val.map { |v| normalize_value v }
  else raise Card::Error::BadQuery, "unknown WQL value type: #{val.class}"
  end
end

#relate(key, val, opts = {}) ⇒ Object



96
97
98
99
100
101
102
103
104
# File 'lib/card/query/interpretation.rb', line 96

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



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

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



106
107
108
109
110
111
112
113
114
# File 'lib/card/query/interpretation.rb', line 106

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