module NoBrainer::Criteria::Where
Public Class Methods
merge_where_ast(a, b)
click to toggle source
# File lib/no_brainer/criteria/where.rb, line 18 def self.merge_where_ast(a, b) (a ? MultiOperator.new(:and, [a, b]) : b).simplify end
Public Instance Methods
_where(*args, &block)
click to toggle source
# File lib/no_brainer/criteria/where.rb, line 14 def _where(*args, &block) chain(:where_ast => parse_clause([*args, block].compact, :unsafe => true)) end
where(*args, &block)
click to toggle source
# File lib/no_brainer/criteria/where.rb, line 10 def where(*args, &block) chain(:where_ast => parse_clause([*args, block].compact)) end
where_index_name()
click to toggle source
# File lib/no_brainer/criteria/where.rb, line 30 def where_index_name index = where_index_finder.strategy.try(:index) index.is_a?(Array) ? index.map(&:name) : index.try(:name) end
where_index_type()
click to toggle source
# File lib/no_brainer/criteria/where.rb, line 35 def where_index_type where_index_finder.strategy.try(:rql_op) end
where_indexed?()
click to toggle source
# File lib/no_brainer/criteria/where.rb, line 26 def where_indexed? where_index_name.present? end
where_present?()
click to toggle source
# File lib/no_brainer/criteria/where.rb, line 22 def where_present? finalized_criteria.options[:where_ast].try(:clauses).present? end
without_distinct(value = true)
click to toggle source
# File lib/no_brainer/criteria/where.rb, line 39 def without_distinct(value = true) # helper for delete_all which can't operate on distinct chain(:without_distinct => value) end
Private Instance Methods
compile_rql_pass1()
click to toggle source
Calls superclass method
# File lib/no_brainer/criteria/where.rb, line 548 def compile_rql_pass1 rql = super rql = where_index_finder.strategy.rql_proc.call(rql) if where_indexed? rql end
compile_rql_pass2()
click to toggle source
Calls superclass method
# File lib/no_brainer/criteria/where.rb, line 554 def compile_rql_pass2 rql = super ast = where_indexed? ? where_index_finder.strategy.ast : @options[:where_ast] rql = rql.filter { |doc| ast.to_rql(doc) } if ast.try(:clauses).present? rql end
instantiate_binary_op(key, op, value, options={})
click to toggle source
# File lib/no_brainer/criteria/where.rb, line 351 def instantiate_binary_op(key, op, value, options={}) op, value = case value when Range then [:between, value] when Regexp then [:match, translate_regexp_to_re2_syntax(value)] else [:eq, value] end if op == :eq nested_prefix = options[:nested_prefix] || [] tail_args = [op, value, self.model, !!options[:unsafe]] case key when Symbol::Decoration raise "Use only one .not, .all or .any modifiers in the query" if key.symbol.is_a?(Symbol::Decoration) case key.decorator when :any, :all then BinaryOperator.new(nested_prefix + [key.symbol], key.decorator, *tail_args) when :not then UnaryOperator.new(:not, BinaryOperator.new(nested_prefix + [key.symbol], :scalar, *tail_args)) end else BinaryOperator.new(nested_prefix + [key], :scalar, *tail_args) end end
parse_clause(clause, options={})
click to toggle source
# File lib/no_brainer/criteria/where.rb, line 283 def parse_clause(clause, options={}) clause = sanitize_for_mass_assignment(clause) case clause when Array then MultiOperator.new(:and, clause.map { |c| parse_clause(c, options) }) when Hash then MultiOperator.new(:and, clause.map { |k,v| parse_clause_stub(k, v, options) }) when Proc then Lambda.new(clause) when Symbol::Decoration case clause.args.size when 1 then parse_clause_stub(clause, clause.args.first, options) when 2 then parse_clause_stub(clause, clause.args, options) else raise "Invalid argument: #{clause}" end else raise "Invalid clause: #{clause}" end end
parse_clause_stub(key, value, options={})
click to toggle source
# File lib/no_brainer/criteria/where.rb, line 299 def parse_clause_stub(key, value, options={}) case key when :and then parse_multi_value(:and, value, false, options) when :or then parse_multi_value(:or, value, false, options) when :_and then parse_multi_value(:and, value, true, options) when :_or then parse_multi_value(:or, value, true, options) when :not then UnaryOperator.new(:not, parse_clause(value, options)) when String, Symbol then case value when Hash then parse_clause(value, options.merge(:nested_prefix => (options[:nested_prefix] || []) + [key.to_sym])) else instantiate_binary_op(key.to_sym, :eq, value, options) end when Symbol::Decoration then # The :eq operator can have only one arg if key.decorator == :eq && value.is_a?(Array) && value.size > 1 raise "Invalid key: #{key}" end case key.decorator when :any, :all, :not then instantiate_binary_op(key, :eq, value, options) when :gte then instantiate_binary_op(key.symbol, :ge, value, options) when :lte then instantiate_binary_op(key.symbol, :le, value, options) else instantiate_binary_op(key.symbol, key.decorator, value, options) end else raise "Invalid key: #{key}" end end
parse_multi_value(op, value, multi_safe, options={})
click to toggle source
# File lib/no_brainer/criteria/where.rb, line 327 def parse_multi_value(op, value, multi_safe, options={}) raise "The `#{op}' operator takes an array as argument" unless value.is_a?(Array) if value.size == 1 && value.first.is_a?(Hash) && !multi_safe raise "The `#{op}' operator was provided an array with a single hash element.\n" + "In Ruby, [:a => :b, :c => :d] means [{:a => :b, :c => :d}] which is not the same as [{:a => :b}, {:c => :d}].\n" + "To prevent mistakes, the former construct is prohibited as you probably mean the latter.\n" + "However, if you know what you are doing, you can use the `_#{op}' operator instead." end MultiOperator.new(op, value.map { |v| parse_clause(v, options) }) end
translate_regexp_to_re2_syntax(value)
click to toggle source
# File lib/no_brainer/criteria/where.rb, line 338 def translate_regexp_to_re2_syntax(value) # Ruby always uses what RE2 calls "multiline mode" (the "m" flag), # meaning that "foo\nbar" matches /^bar$/. # # Ruby's /m modifier means that . matches \n and corresponds to RE2's "s" flag. flags = "m" flags << "s" if value.options & Regexp::MULTILINE != 0 flags << "i" if value.options & Regexp::IGNORECASE != 0 "(?#{flags})#{value.source}" end
where_index_finder()
click to toggle source
# File lib/no_brainer/criteria/where.rb, line 543 def where_index_finder return finalized_criteria.__send__(:where_index_finder) unless finalized? @where_index_finder ||= IndexFinder.new(self, @options[:where_ast]).tap(&:find_strategy!) end