Skip to content

MONGOID-5408 .evolve should support wrapper class #5448

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Feb 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 48 additions & 34 deletions docs/reference/queries.txt
Original file line number Diff line number Diff line change
Expand Up @@ -168,58 +168,45 @@ name, as follows:
# class: Band
# embedded: false>

Embedded Documents
==================

To match values of fields of embedded documents, use the dot notation:

.. code-block:: ruby

Band.where('manager.name' => 'Smith')
# => #<Mongoid::Criteria
# selector: {"manager.name"=>"Smith"}
# options: {}
# class: Band
# embedded: false>

Band.where(:'manager.name'.ne => 'Smith')
# => #<Mongoid::Criteria
# selector: {"manager.name"=>{"$ne"=>"Smith"}}
# options: {}
# class: Band
# embedded: false>

.. note::
Fields
======

Queries always return top-level model instances, even if all of the
conditions are referencing embedded documents.

Field Types
===========
Querying on Defined Fields
--------------------------

In order to query on a field, it is not necessary to add the field to
:ref:`the model class definition <fields>`. However, if a field is defined in
the model class, the type of the field is taken into account when constructing
the query:
the model class, Mongoid will coerce query values to match defined field types
when constructing the query:

.. code-block:: ruby

Band.where(name: 2020)
Band.where(name: 2020, founded: "2020")
# => #<Mongoid::Criteria
# selector: {"name"=>"2020"}
# selector: {"name"=>"2020", "founded"=>2020}
# options: {}
# class: Band
# embedded: false>

Band.where(founded: 2020)
Querying for Raw Values
-----------------------

If you'd like to bypass Mongoid's query type coercion behavior and query
directly for the raw-typed value in the database, wrap the query value in
``Mongoid::RawValue`` class. This can be useful when working with legacy data.

.. code-block:: ruby

Band.where(founded: Mongoid::RawValue("2020"))
# => #<Mongoid::Criteria
# selector: {"founded"=>2020}
# selector: {"founded"=>"2020"}
# options: {}
# class: Band
# embedded: false>

Aliases
=======
Field Aliases
-------------

Queries take into account :ref:`storage field names <storage-field-names>`
and :ref:`field aliases <field-aliases>`:
Expand All @@ -245,6 +232,33 @@ Since ``id`` and ``_id`` fields are aliases, either one can be used for queries:
# embedded: false>


Embedded Documents
Copy link
Contributor Author

@johnnyshields johnnyshields Oct 6, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here I copy-pasted the "Embedded Documents" section to be after "Fields" w/out edits to it, as I felt it made more sense order-wise vis-a-vis additions to Fields section in this PR.

==================

To match values of fields of embedded documents, use the dot notation:

.. code-block:: ruby

Band.where('manager.name' => 'Smith')
# => #<Mongoid::Criteria
# selector: {"manager.name"=>"Smith"}
# options: {}
# class: Band
# embedded: false>

Band.where(:'manager.name'.ne => 'Smith')
# => #<Mongoid::Criteria
# selector: {"manager.name"=>{"$ne"=>"Smith"}}
# options: {}
# class: Band
# embedded: false>

.. note::

Queries always return top-level model instances, even if all of the
conditions are referencing embedded documents.


.. _logical-operations:

Logical Operations
Expand Down
18 changes: 18 additions & 0 deletions docs/release-notes/mongoid-9.0.txt
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,24 @@ ignored for embedded documents; an embedded document now always uses the persist
context of its parent.


Support for Passing Raw Values into Queries
-------------------------------------------

When performing queries, it is now possible skip Mongoid's type coercion logic
using the ``Mongoid::RawValue`` wrapper class. This can be useful when legacy
data in the database is of a different type than the field definition.

.. code-block:: ruby

class Person
include Mongoid::Document
field :age, type: Integer
end

# Query for the string "42", not the integer 42
Person.where(age: Mongoid::RawValue("42"))


Raise AttributeNotLoaded error when accessing fields omitted from query projection
----------------------------------------------------------------------------------

Expand Down
6 changes: 4 additions & 2 deletions lib/mongoid/criteria/queryable/selector.rb
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ def to_pipeline

# 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 evole method.
# therefore, we cannot just use the evolve method.
#
# @param [ String ] name The name of the field.
# @param [ Object ] serializer The optional serializer for the field.
Expand Down Expand Up @@ -151,6 +151,8 @@ def evolve_multi(specs)
# @return [ Object ] The serialized object.
def evolve(serializer, value)
case value
when Mongoid::RawValue
value.raw_value
when Hash
evolve_hash(serializer, value)
when Array
Expand Down Expand Up @@ -228,7 +230,7 @@ def evolve_hash(serializer, value)
#
# @api private
#
# @param [ String ] key The to store the range for.
# @param [ String ] key The key at which to store the range.
# @param [ Object ] serializer The optional serializer for the field.
# @param [ Range ] value The Range to serialize.
#
Expand Down
1 change: 1 addition & 0 deletions lib/mongoid/extensions.rb
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ def transform_keys
require "mongoid/extensions/object"
require "mongoid/extensions/object_id"
require "mongoid/extensions/range"
require "mongoid/extensions/raw_value"
require "mongoid/extensions/regexp"
require "mongoid/extensions/set"
require "mongoid/extensions/string"
Expand Down
32 changes: 32 additions & 0 deletions lib/mongoid/extensions/raw_value.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# frozen_string_literal: true

# Wrapper class used when a value cannot be casted in evolve method.
module Mongoid

# Instantiates a new Mongoid::RawValue object. Used as a syntax shortcut.
#
# @example Create a Mongoid::RawValue object.
# Mongoid::RawValue("Beagle")
#
# @return [ Mongoid::RawValue ] The object.
def RawValue(*args)
RawValue.new(*args)
end

class RawValue

attr_reader :raw_value

def initialize(raw_value)
@raw_value = raw_value
end

# Returns a string containing a human-readable representation of
# the object, including the inspection of the underlying value.
#
# @return [ String ] The object inspection.
def inspect
"RawValue: #{raw_value.inspect}"
end
end
end
Loading