class Mongomery::Query
Constants
- OPERATOR_MAP
Attributes
custom_operators[R]
mapped_properties[R]
schema[R]
table[R]
Public Class Methods
new(table, schema, mapped_properties, custom_operators)
click to toggle source
# File lib/mongomery.rb, line 53 def initialize(table, schema, mapped_properties, custom_operators) @table = table @schema = schema @mapped_properties = mapped_properties @custom_operators = custom_operators @condition = nil end
Public Instance Methods
arel()
click to toggle source
# File lib/mongomery.rb, line 66 def arel @arel ||= build_arel end
condition()
click to toggle source
# File lib/mongomery.rb, line 147 def condition @condition ||= translate(@where) end
count()
click to toggle source
# File lib/mongomery.rb, line 119 def count table.project('COUNT(*)').tap do |t| t.where(condition) if condition end end
delete()
click to toggle source
# File lib/mongomery.rb, line 140 def delete Arel::DeleteManager.new(table.engine).tap do |manager| manager.from(table) manager.where(condition) if condition end end
index(col)
click to toggle source
# File lib/mongomery.rb, line 105 def index(col) Arel.sql(%Q[CREATE INDEX "#{table.name}_#{col}_idx" ON "#{table.name}" ((#{sql_json_exp(col)}))]) end
insert(args)
click to toggle source
# File lib/mongomery.rb, line 125 def insert(args) Arel::InsertManager.new(table.engine).tap do |manager| manager.into(table) manager.insert(Hash[args.map {|k, v| [table[k], v] }].to_a) end end
limit(number)
click to toggle source
# File lib/mongomery.rb, line 78 def limit(number) arel.take(number) self end
skip(number)
click to toggle source
# File lib/mongomery.rb, line 83 def skip(number) arel.skip(number) self end
sort(params)
click to toggle source
# File lib/mongomery.rb, line 88 def sort(params) params.each do |col, val| order = val > 0 ? :asc : :desc case col.to_s when "_id" arel.order(table[:id].send(order)) else arel.order(sql_json_path(col).send(order)) end end self end
sql_json_exp(col)
click to toggle source
# File lib/mongomery.rb, line 101 def sql_json_exp(col) sql_json_path(col) end
to_arel()
click to toggle source
# File lib/mongomery.rb, line 70 def to_arel arel end
to_sql()
click to toggle source
# File lib/mongomery.rb, line 74 def to_sql to_arel.to_sql end
update(args)
click to toggle source
# File lib/mongomery.rb, line 132 def update(args) Arel::UpdateManager.new(table.engine).tap do |manager| manager.table(table) manager.set(Hash[args.map {|k, v| [table[k], v] }].to_a) manager.where(condition) if condition end end
where(args)
click to toggle source
# File lib/mongomery.rb, line 61 def where(args) @where = args self end
Private Instance Methods
build_arel()
click to toggle source
# File lib/mongomery.rb, line 157 def build_arel table.project("*").tap do |t| t.where(condition) if condition end end
chain(op, conditions)
click to toggle source
# File lib/mongomery.rb, line 338 def chain(op, conditions) result = nil conditions.each do |cond| result = result ? result.send(op, cond) : cond end result end
compare(col, val, op)
click to toggle source
# File lib/mongomery.rb, line 282 def compare(col, val, op) operator(wrap(col, val), op, val) end
compare_schema(col, val, type, op)
click to toggle source
# File lib/mongomery.rb, line 302 def compare_schema(col, val, type, op) case type when "string" operator(Arel.sql("(#{col})"), op, val) else case val when Numeric operator(Arel.sql("(#{col})"), op, val.to_s) else operator(Arel.sql("(#{col})"), op, val) end end end
has_operator?(value)
click to toggle source
# File lib/mongomery.rb, line 278 def has_operator?(value) value.keys.any? {|key| key =~ /^\$/ } end
json_pathize(paths)
click to toggle source
# File lib/mongomery.rb, line 329 def json_pathize(paths) quote("{#{paths.join(',')}}") end
mapped_keys()
click to toggle source
# File lib/mongomery.rb, line 153 def mapped_keys mapped_properties.keys end
mapped_values(args)
click to toggle source
# File lib/mongomery.rb, line 109 def mapped_values(args) pairs = [] mapped_properties.each do |key, column| pairs.push([table[column], args[key]]) if args.key?(key) end pairs end
numeric?(col)
click to toggle source
# File lib/mongomery.rb, line 297 def numeric?(col) type = schema.column_type(col.to_s) ["number", "integer"].include?(type) end
operator(col, op, val)
click to toggle source
# File lib/mongomery.rb, line 316 def operator(col, op, val) case op when Symbol col.send(op, val) else op.call(col, val) end end
quote(str)
click to toggle source
# File lib/mongomery.rb, line 333 def quote(str) # FIXME there should be a better way to do this table.engine.connection.quote(str) end
sql_json_path(col)
click to toggle source
# File lib/mongomery.rb, line 325 def sql_json_path(col) Arel.sql("#{col.to_s}") end
translate(query)
click to toggle source
# File lib/mongomery.rb, line 163 def translate(query) chain(:and, query.map {|col, value| translate_cv(col, value) }) end
translate_cv(col, value)
click to toggle source
# File lib/mongomery.rb, line 167 def translate_cv(col, value) case col.to_s when "$or" chain(:or, value.map {|q| translate(q) }) when "$and" chain(:and, value.map {|q| translate(q) }) when /^\$/ raise UnsupportedQuery, "Unsupported operator #{col}" when "_id" translate_value(table[:id], value) when *mapped_keys translate_value(table[mapped_properties[col.to_s]], value) else if schema translate_value_schema(col, sql_json_path(col), value) else translate_value_dynamic(sql_json_path(col), value) end end end
translate_value(col, value)
click to toggle source
# File lib/mongomery.rb, line 193 def translate_value(col, value) case value when Hash if has_operator?(value) chain(:and, value.map {|op, val| if custom_operators[op] operator(col, custom_operators[op], val) elsif OPERATOR_MAP.key?(op) col.send(OPERATOR_MAP[op], val) else raise UnsupportedQuery, "Unknown operator #{op}" end }) else col.eq(value.to_json) end else col.eq(value) end end
translate_value_dynamic(col, value)
click to toggle source
# File lib/mongomery.rb, line 246 def translate_value_dynamic(col, value) case value when String, TrueClass, FalseClass col.eq(value.to_s) when Numeric, NilClass compare(col, value, :eq) when Hash if has_operator?(value) chain(:and, value.map {|op, val| case op when "$in" if val.all? {|v| v.is_a? Numeric } wrap(col, val.first).in(val) else col.in(val.map(&:to_s)) end when *(custom_operators.keys) compare(col, val, custom_operators[op]) when "$eq", "$ne", "$gt", "$gte", "$lt", "$lte" compare(col, val, OPERATOR_MAP[op]) else raise UnsupportedQuery, "Unknown operator #{op}" end }) else col.eq(value.to_json) end else col.eq(value.to_json) end end
translate_value_schema(column, col, value)
click to toggle source
# File lib/mongomery.rb, line 214 def translate_value_schema(column, col, value) type = schema.column_type(column.to_s) case value when Hash if has_operator?(value) chain(:and, value.map {|op, val| case op when "$in" case type when "array" chain(:or, val.map { |v| col.matches(%Q[%"#{v}"%]) }) else compare_schema(col, val, type, :in) end when *(custom_operators.keys) compare_schema(col, val, type, custom_operators[op]) when "$eq", "$ne", "$gt", "$gte", "$lt", "$lte" compare_schema(col, val, type, OPERATOR_MAP[op]) else raise UnsupportedQuery, "Unknown operator #{op}" end }) else col.eq(value.to_json) end when String, Numeric, NilClass compare_schema(col, value, type, :eq) else compare_schema(col, value.to_json, type, :eq) end end
wrap(col, val)
click to toggle source
# File lib/mongomery.rb, line 286 def wrap(col, val) case val when NilClass # data#>>'{foo}' IS NULL is invalid # (data#>>'{foo}') IS NULL is valid Arel.sql("(#{col})") else col end end