Module: Mongoid::Criteria::Queryable::Mergeable
| Relationships & Source Files | |
| Extension / Inclusion / Inheritance Descendants | |
| 
       Included In: 
      
     | |
| Defined in: | lib/mongoid/criteria/queryable/mergeable.rb | 
Overview
Contains behavior for merging existing selection with new selection.
Instance Attribute Summary
Instance Method Summary
- 
    
      #and_with_operator(criterion, operator)  ⇒ Criteria 
    
    
Merge criteria with operators using the and operator.
 - 
    
      #intersect  ⇒ Mergeable 
    
    
Instruct the next mergeable call to use intersection.
 - 
    
      #override  ⇒ Mergeable 
    
    
Instruct the next mergeable call to use override.
 - 
    
      #reset_strategies!  ⇒ Criteria 
    
    
Clear the current strategy and negating flag, used after cloning.
 - 
    
      #union  ⇒ Mergeable 
    
    
Instruct the next mergeable call to use union.
 - 
    
      #__add__(criterion, operator)  ⇒ Mergeable 
    
    private
    Internal use only
    Internal use only
    
Adds the criterion to the existing selection.
 - 
    
      #__expanded__(criterion, outer, inner)  ⇒ Mergeable 
    
    private
    Internal use only
    Internal use only
    
Adds the criterion to the existing selection.
 - 
    
      #__intersect__(criterion, operator)  ⇒ Mergeable 
    
    private
    Internal use only
    Internal use only
    
Adds the criterion to the existing selection.
 - 
    
      #__merge__(criterion)  ⇒ Mergeable 
    
    private
    Internal use only
    Internal use only
    
Perform a straight merge of the criterion into the selection and let the symbol overrides do all the work.
 - 
    
      #__multi__(criteria, operator)  ⇒ Mergeable 
    
    private
    Internal use only
    Internal use only
    
Adds $and/$or/$nor criteria to a copy of this selection.
 - 
    
      #__override__(criterion, operator)  ⇒ Mergeable 
    
    private
    Internal use only
    Internal use only
    
Adds the criterion to the existing selection.
 - 
    
      #__union__(criterion, operator)  ⇒ Mergeable 
    
    private
    Internal use only
    Internal use only
    
Adds the criterion to the existing selection.
 - 
    
      #_mongoid_add_top_level_operation(operator, criteria)  
    
    private
    Internal use only
    Internal use only
    
Combines criteria into a MongoDB selector.
 - 
    
      #_mongoid_expand_keys(expr)  ⇒ BSON::Document 
    
    private
    
Takes a criteria hash and expands
Keyobjects into hashes containing MQL corresponding to said key objects. - 
    
      #_mongoid_flatten_arrays(array)  
    
    private
    
Calling .flatten on an array which includes a
::Mongoid::Criteriainstance evaluates the criteria, which we do not want. - 
    
      #prepare(field, operator, value)  ⇒ Object 
    
    private
    Internal use only
    Internal use only
    
Prepare the value for merging.
 - 
    
      #use(strategy)  ⇒ Mergeable 
    
    private
    Internal use only
    Internal use only
    
Use the named strategy for the next operation.
 - 
    
      #with_strategy(strategy, criterion, operator)  ⇒ Mergeable 
    
    private
    Internal use only
    Internal use only
    
Add criterion to the selection with the named strategy.
 
Instance Attribute Details
#strategy (rw)
[ GitHub ]# File 'lib/mongoid/criteria/queryable/mergeable.rb', line 12
attr_accessor :strategy
#strategy The name of the current strategy.(The name of the current strategy.) (rw)
[ GitHub ]# File 'lib/mongoid/criteria/queryable/mergeable.rb', line 12
attr_accessor :strategy
Instance Method Details
    #__add__(criterion, operator)  ⇒ Mergeable  (private)
  
  Adds the criterion to the existing selection.
# File 'lib/mongoid/criteria/queryable/mergeable.rb', line 90
def __add__(criterion, operator) with_strategy(:__add__, criterion, operator) end
    #__expanded__(criterion, outer, inner)  ⇒ Mergeable  (private)
  
  Adds the criterion to the existing selection.
# File 'lib/mongoid/criteria/queryable/mergeable.rb', line 106
def (criterion, outer, inner) selection(criterion) do |selector, field, value| selector.store(field, { outer => { inner => value }}) end end
    #__intersect__(criterion, operator)  ⇒ Mergeable  (private)
  
  Adds the criterion to the existing selection.
# File 'lib/mongoid/criteria/queryable/mergeable.rb', line 140
def __intersect__(criterion, operator) with_strategy(:__intersect__, criterion, operator) end
    #__merge__(criterion)  ⇒ Mergeable  (private)
  
  Perform a straight merge of the criterion into the selection and let the symbol overrides do all the work.
# File 'lib/mongoid/criteria/queryable/mergeable.rb', line 123
def __merge__(criterion) selection(criterion) do |selector, field, value| selector.merge!(field.__expr_part__(value)) end end
    #__multi__(criteria, operator)  ⇒ Mergeable  (private)
  
  Adds $and/$or/$nor criteria to a copy of this selection.
Each of the criteria can be a ::Hash of key/value pairs or MongoDB operators (keys beginning with $), or a Selectable object (which typically will be a ::Mongoid::Criteria instance).
# File 'lib/mongoid/criteria/queryable/mergeable.rb', line 160
def __multi__(criteria, operator) clone.tap do |query| sel = query.selector criteria.flatten.each do |expr| next unless expr result_criteria = sel[operator] || [] if expr.is_a?(Selectable) expr = expr.selector end normalized = (expr) sel.store(operator, result_criteria.push(normalized)) end end end
    #__override__(criterion, operator)  ⇒ Mergeable  (private)
  
  Adds the criterion to the existing selection.
# File 'lib/mongoid/criteria/queryable/mergeable.rb', line 343
def __override__(criterion, operator) if criterion.is_a?(Selectable) criterion = criterion.selector end selection(criterion) do |selector, field, value| expression = prepare(field, operator, value) existing = selector[field] if existing.respond_to?(:merge!) selector.store(field, existing.merge!(expression)) else selector.store(field, expression) end end end
    #__union__(criterion, operator)  ⇒ Mergeable  (private)
  
  Adds the criterion to the existing selection.
# File 'lib/mongoid/criteria/queryable/mergeable.rb', line 369
def __union__(criterion, operator) with_strategy(:__union__, criterion, operator) end
#_mongoid_add_top_level_operation(operator, criteria) (private)
Combines criteria into a MongoDB selector.
::Mongoid::Criteria is an array of criterion objects which will be flattened.
Each criterion can be:
- 
A hash
 - 
A Criteria instance
 - 
nil, in which case it is ignored
 
# File 'lib/mongoid/criteria/queryable/mergeable.rb', line 185
private def _mongoid_add_top_level_operation(operator, criteria) # Flatten the criteria. The idea is that predicates in MongoDB # are always hashes and are never arrays. This method additionally # allows Criteria instances as predicates. # The flattening is existing Mongoid behavior but we could possibly # get rid of it as applications can splat their predicates, or # flatten if needed. clone.tap do |query| sel = query.selector _mongoid_flatten_arrays(criteria).each do |criterion| if criterion.is_a?(Selectable) expr = (criterion.selector) else expr = (criterion) end if sel.empty? sel.store(operator, [expr]) elsif sel.keys == [operator] sel.store(operator, sel[operator] + [expr]) else operands = [sel.dup] + [expr] sel.clear sel.store(operator, operands) end end end end
    #_mongoid_expand_keys(expr)  ⇒ BSON::Document  (private)
  
Takes a criteria hash and expands Key objects into hashes containing MQL corresponding to said key objects. Also converts the input to BSON::Document to permit indifferent access.
The argument must be a hash containing key-value pairs of the following forms:
- 
value - 
=> value - 
value - 
=> operator_value_expression - 
=> operator_value_expression 
Ruby does not permit multiple symbol operators. For example, => 1,  is collapsed to :foo.gt => 2=> 2 by the language. Therefore this method never has to deal with multiple identical operators.
Similarly, this method should never need to expand a literal value and an operator at the same time.
This method effectively converts symbol keys to string keys in the input expr, such that the downstream code can assume that conditions always contain string keys.
# File 'lib/mongoid/criteria/queryable/mergeable.rb', line 259
private def (expr) unless expr.is_a?(Hash) raise ArgumentError, 'Argument must be a Hash' end result = BSON::Document.new expr.each do |field, value| field.__expr_part__(value., negating?).each do |k, v| if existing = result[k] if existing.is_a?(Hash) # Existing value is an operator. # If new value is also an operator, ensure there are no # conflicts and add if v.is_a?(Hash) # The new value is also an operator. # If there are no conflicts, combine the hashes, otherwise # add new conditions to top level with $and. if (v.keys & existing.keys).empty? existing.update(v) else raise NotImplementedError, 'Ruby does not allow same symbol operator with different values' result['$and'] ||= [] result['$and'] << {k => v} end else # The new value is a simple value. # Transform the implicit equality to either $eq or $regexp # depending on the type of the argument. See # https://www.mongodb.com/docs/manual/reference/operator/query/eq/#std-label-eq-usage-examples # for the description of relevant server behavior. op = case v when Regexp, BSON::Regexp::Raw '$regex' else '$eq' end # If there isn't an $eq/$regex operator already in the # query, transform the new value into an operator # expression and add it to the existing hash. Otherwise # add the new condition with $and to the top level. if existing.key?(op) raise NotImplementedError, 'Ruby does not allow same symbol operator with different values' result['$and'] ||= [] result['$and'] << {k => v} else existing.update(op => v) end end else # Existing value is a simple value. # See the notes above about transformations to $eq/$regex. op = case existing when Regexp, BSON::Regexp::Raw '$regex' else '$eq' end if v.is_a?(Hash) && !v.key?(op) result[k] = {op => existing}.update(v) else raise NotImplementedError, 'Ruby does not allow same symbol operator with different values' result['$and'] ||= [] result['$and'] << {k => v} end end else result[k] = v end end end result end
#_mongoid_flatten_arrays(array) (private)
Calling .flatten on an array which includes a ::Mongoid::Criteria instance evaluates the criteria, which we do not want. Hence this method explicitly only expands ::Array objects and ::Array subclasses.
# File 'lib/mongoid/criteria/queryable/mergeable.rb', line 216
private def _mongoid_flatten_arrays(array) out = [] pending = array.dup until pending.empty? item = pending.shift if item.nil? # skip elsif item.is_a?(Array) pending += item else out << item end end out end
#and_with_operator(criterion, operator) ⇒ Criteria
Merge criteria with operators using the and operator.
# File 'lib/mongoid/criteria/queryable/mergeable.rb', line 62
def and_with_operator(criterion, operator) crit = self if criterion criterion.each_pair do |field, value| val = prepare(field, operator, value) # The prepare method already takes the negation into account. We # set negating to false here so that ``and`` doesn't also apply # negation and we have a double negative. crit.negating = false crit = crit.and(field => val) end end crit end
    #intersect  ⇒ Mergeable 
  
Instruct the next mergeable call to use intersection.
# File 'lib/mongoid/criteria/queryable/mergeable.rb', line 20
def intersect use(:__intersect__) end
    #override  ⇒ Mergeable 
  
Instruct the next mergeable call to use override.
# File 'lib/mongoid/criteria/queryable/mergeable.rb', line 30
def override use(:__override__) end
    #prepare(field, operator, value)  ⇒ Object  (private)
  
  Prepare the value for merging.
# File 'lib/mongoid/criteria/queryable/mergeable.rb', line 421
def prepare(field, operator, value) unless operator =~ /exists|type|size/ value = value. field = field.to_s name = aliases[field] || field serializer = serializers[name] value = serializer ? serializer.evolve(value) : value end selection = { operator => value } negating? ? { "$not" => selection } : selection end
#reset_strategies! ⇒ Criteria
Clear the current strategy and negating flag, used after cloning.
# File 'lib/mongoid/criteria/queryable/mergeable.rb', line 50
def reset_strategies! self.strategy = nil self.negating = nil self end
    #union  ⇒ Mergeable 
  
Instruct the next mergeable call to use union.
    #use(strategy)  ⇒ Mergeable  (private)
  
  Use the named strategy for the next operation.
    #with_strategy(strategy, criterion, operator)  ⇒ Mergeable  (private)
  
  Add criterion to the selection with the named strategy.