Class: Mongoid::Criteria::Queryable::Selector
Relationships & Source Files | |
Super Chains via Extension / Inclusion / Inheritance | |
Class Chain:
|
|
Instance Chain:
|
|
Inherits: |
Mongoid::Criteria::Queryable::Smash
|
Defined in: | lib/mongoid/criteria/queryable/selector.rb |
Overview
The selector is a special kind of hash that knows how to serialize values coming into it as well as being alias and locale aware for key names.
Class Attribute Summary
::Mongoid::Extensions::Hash::ClassMethods
- Extended
resizable? | Can the size of this object change? |
Class Method Summary
Smash
- Inherited
.new | Initialize the new selector. |
::Mongoid::Extensions::Hash::ClassMethods
- Extended
mongoize | Turn the object from the ruby type we deal with to a Mongo friendly type. |
Instance Attribute Summary
Smash
- Inherited
#aliased_associations, #aliased_associations The aliased_associations., #aliases, #aliases The aliases., #associations, #associations The associations., #serializers, #serializers The serializers. |
::Mongoid::Extensions::Hash
- Included
#resizable? | Can the size of this object change? |
Instance Method Summary
-
#[]=(key, value)
Alias for #store.
-
#merge!(other) ⇒ Selector
Merges another selector into this one.
-
#store(key, value) ⇒ Object
(also: #[]=)
Store the value in the selector for the provided key.
-
#to_pipeline ⇒ Array<Hash>
Convert the selector to an aggregation pipeline entry.
-
#evolve(serializer, value) ⇒ Object
private
Internal use only
Internal use only
Evolve a single key selection with various types of values.
-
#evolve_array(serializer, value) ⇒ Object
private
Internal use only
Internal use only
Evolve a single key selection with array values.
-
#evolve_hash(serializer, value) ⇒ Object
private
Internal use only
Internal use only
Evolve a single key selection with hash values.
-
#evolve_multi(specs) ⇒ Array<Hash>
private
Internal use only
Internal use only
Evolves a multi-list selection, like an $and or $or criterion, and performs the necessary serialization.
-
#evolve_range(key, serializer, value) ⇒ Array<String, Hash>
private
Internal use only
Internal use only
Evolve a single key selection with range values.
-
#multi_selection?(key) ⇒ true | false
private
Internal use only
Internal use only
Determines if the selection is a multi-select, like an $and or $or or $nor selection.
-
#store_creds(name, serializer, value) ⇒ Array<String, String>
private
Get the store name and store value.
Smash
- Inherited
#[] | Get an item from the smart hash by the provided key. |
#__deep_copy__ | Perform a deep copy of the smash. |
#get_serializer | Retrieves the serializer for the given name. |
#localized_key | Get the localized value for the key if needed. |
#storage_pair | Get the pair of objects needed to store the value in a hash by the provided key. |
::Mongoid::Extensions::Hash
- Included
#__consolidate__ | Consolidate the key/values in the hash under an atomic $set. |
#__evolve_object_id__ | Evolves each value in the hash to an object id if it is convertable. |
#__mongoize_object_id__ | Mongoizes each value in the hash to an object id if it is convertable. |
#delete_id | Deletes an id value from the hash. |
#extract_id | Get the id attribute from this hash, whether it’s prefixed with an underscore or is a symbol. |
#mongoize | Turn the object from the ruby type we deal with to a Mongo friendly type. |
#to_criteria | Convert this hash to a criteria. |
Constructor Details
This class inherits a constructor from Mongoid::Criteria::Queryable::Smash
Instance Method Details
#[]=(key, value)
Alias for #store.
# File 'lib/mongoid/criteria/queryable/selector.rb', line 61
alias :[]= :store
#evolve(serializer, value) ⇒ Object
(private)
Evolve a single key selection with various types of values.
# File 'lib/mongoid/criteria/queryable/selector.rb', line 153
def evolve(serializer, value) case value when Mongoid::RawValue value.raw_value when Hash evolve_hash(serializer, value) when Array evolve_array(serializer, value) when Range value.__evolve_range__(serializer: serializer) else (serializer || value.class).evolve(value) end end
#evolve_array(serializer, value) ⇒ Object
(private)
Evolve a single key selection with array values.
# File 'lib/mongoid/criteria/queryable/selector.rb', line 179
def evolve_array(serializer, value) value.map do |_value| evolve(serializer, _value) end end
#evolve_hash(serializer, value) ⇒ Object
(private)
Evolve a single key selection with hash values.
# File 'lib/mongoid/criteria/queryable/selector.rb', line 196
def evolve_hash(serializer, value) value.each_pair do |operator, _value| if operator =~ /exists|type|size/ value[operator] = _value else value[operator] = evolve(serializer, _value) end end end
#evolve_multi(specs) ⇒ Array<Hash> (private)
Evolves a multi-list selection, like an $and or $or criterion, and performs the necessary serialization.
# File 'lib/mongoid/criteria/queryable/selector.rb', line 106
def evolve_multi(specs) unless specs.is_a?(Array) raise ArgumentError, "specs is not an array: #{specs.inspect}" end specs.map do |spec| Hash[spec.map do |key, value| # If an application nests conditionals, e.g. # {'$or' => [{'$or' => {...}}]}, # when evolve_multi is called for the top level hash, # this call recursively transforms the bottom level $or. if multi_selection?(key) value = evolve_multi(value) end # storage_pair handles field aliases but not localization for # some reason, although per its documentation Smash supposedly # owns both. name, serializer = storage_pair(key) # This performs type conversions on the value and transformations # that depend on the type of the field that the value is stored # in, but not transformations that have to do with query shape. final_key, evolved_value = store_creds(name, serializer, value) # This builds a query shape around the value, when the query # involves complex keys. For example, {:foo.lt => 5} produces # {'foo' => {'$lt' => 5}}. This step should be done after all # value-based processing is complete. if key.is_a?(Key) evolved_value = key.transform_value(evolved_value) end [ final_key, evolved_value ] end] end.uniq end
#evolve_range(key, serializer, value) ⇒ Array<String, Hash> (private)
Evolve a single key selection with range values. This method traverses the association tree to build a query for the given value and serializer. There are three parts to the query here:
(1) “klass.child.gchild” => {
"$elemMatch" => {
(2) "ggchild.field" => (3) { "$gte" => 6, "$lte" => 10 }
}
}
(1) The first n fields are dotted together until the last
or field of type array. In the above case, gchild
would be an or Array, and ggchild would be an
or a hash.
(2) The last fields are used inside the $elemMatch. This one is
actually optional, and will be ignored if the last field is an
array or . If the last field is an array (1), (2) and
(3) will look like:
"klass.child.gchild.ggchild.field" => {
{ "$elemMatch" => { "$gte" => 6, "$lte" => 10 } }
}
(3) This is calculated by:
value.__evolve_range__(serializer: serializer).
# File 'lib/mongoid/criteria/queryable/selector.rb', line 239
def evolve_range(key, serializer, value) v = value.__evolve_range__(serializer: serializer) assocs = [] Fields.traverse_association_tree(key, serializers, associations, aliased_associations) do |meth, obj, is_field| assocs.push([meth, obj, is_field]) end # Iterate backwards until you get a field with type # Array or an embeds_many association. inner_key = "" loop do # If there are no arrays or embeds_many associations, just return # the key and value without $elemMatch. return [ key, v ] if assocs.empty? meth, obj, is_field = assocs.last break if (is_field && obj.type == Array) || (!is_field && obj.is_a?(Association::Embedded::EmbedsMany)) assocs.pop inner_key = "#{meth}.#{inner_key}" end # If the last array or embeds_many association is the last field, # the inner key (2) is ignored, and the outer key (1) is the original # key. if inner_key.blank? [ key, { "$elemMatch" => v }] else store_key = assocs.map(&:first).join('.') store_value = { "$elemMatch" => { inner_key.chop => v } } [ store_key, store_value ] end end
#merge!(other) ⇒ Selector
Merges another selector into this one.
# File 'lib/mongoid/criteria/queryable/selector.rb', line 20
def merge!(other) other.each_pair do |key, value| if value.is_a?(Hash) && self[key.to_s].is_a?(Hash) value = self[key.to_s].merge(value) do |_key, old_val, new_val| case _key.to_s when '$in' new_val & old_val when '$nin' (old_val + new_val).uniq else new_val end end end if multi_selection?(key) value = (self[key.to_s] || []).concat(value) end store(key, value) end end
#multi_selection?(key) ⇒ true
| false
(private)
Determines if the selection is a multi-select, like an $and or $or or $nor selection.
# File 'lib/mongoid/criteria/queryable/selector.rb', line 284
def multi_selection?(key) %w($and $or $nor).include?(key) end
#store(key, value) ⇒ Object
Also known as: #[]=
Store the value in the selector for the provided key. The selector will handle all necessary serialization and localization in this step.
# File 'lib/mongoid/criteria/queryable/selector.rb', line 51
def store(key, value) name, serializer = storage_pair(key) if multi_selection?(name) store_name = name store_value = evolve_multi(value) else store_name, store_value = store_creds(name, serializer, value) end super(store_name, store_value) end
#store_creds(name, serializer, value) ⇒ Array<String, String> (private)
Get the store name and store value. If the value is of type range, we need may need to change the store_name as well as the store_value, therefore, we cannot just use the evolve method.
# File 'lib/mongoid/criteria/queryable/selector.rb', line 86
def store_creds(name, serializer, value) store_name = localized_key(name, serializer) if Range === value evolve_range(store_name, serializer, value) else [ store_name, evolve(serializer, value) ] end end
#to_pipeline ⇒ Array<Hash>
Convert the selector to an aggregation pipeline entry.
# File 'lib/mongoid/criteria/queryable/selector.rb', line 69
def to_pipeline pipeline = [] pipeline.push({ "$match" => self }) unless empty? pipeline end