card/lib/card/query/value.rb
class Card
module Query
# handling for CQL value clauses, eg [operator, value]
class Value
include Clause
include MatchValue
SQL_FIELD = { name: "key", content: "db_content" }.freeze
attr_reader :query, :operator, :value
def initialize rawvalue, query
@query = query
@operator, @value = parse_value rawvalue
canonicalize_operator
end
def to_sql field
if @operator == "~"
match_sql field
else
standard_sql field
end
end
private
def standard_sql field
@value = Array.wrap(@value).map { |v| v.to_name.key } if field.to_sym == :name
"#{field_sql field} #{@operator} #{sqlize @value}"
end
def parse_value value
case value
when Array then parse_array_value value.clone
when ActiveRecord::Relation then ["in", value]
when nil then ["is", nil]
else ["=", parse_simple_value(value)]
end
end
def parse_array_value array
operator = operator?(array.first) ? array.shift : :in
[operator, array.flatten.map { |i| parse_simple_value i }]
end
def parse_simple_value value
case value
when String, Integer then value
when Symbol then value.to_s
when nil then nil
else
raise Error::BadQuery, "Invalid property value: #{value.inspect}"
end
end
def canonicalize_operator
unless (target = OPERATORS[@operator.to_s])
raise Error::BadQuery, "Invalid operator: #{@operator}"
end
@operator = target
end
def operator? key
OPERATORS.key? key.to_s
end
def sqlize v
case v
when Query then v.to_sql
when ActiveRecord::Relation then "(#{v.to_sql})"
when Array then sqlize_array v
when nil then "NULL"
else quote(v.to_s)
end
end
def sqlize_array array
array.flatten!
if array.size == 1 && !@operator.in?(["in", "not in"])
sqlize array.first
else
"(#{array.map { |x| sqlize(x) }.join(',')})"
end
end
def field_sql field
"#{@query.table_alias}.#{standardize_field field}"
end
def standardize_field field
SQL_FIELD[field.to_sym] || safe_sql(field.to_s)
end
end
end
end