Skip to content

Commit 19f97ec

Browse files
committed
Add Mongoid::RawValue wrapper which can be passed into queries
1 parent 6407218 commit 19f97ec

File tree

17 files changed

+1097
-69
lines changed

17 files changed

+1097
-69
lines changed

docs/reference/queries.txt

+48-34
Original file line numberDiff line numberDiff line change
@@ -168,58 +168,45 @@ name, as follows:
168168
# class: Band
169169
# embedded: false>
170170

171-
Embedded Documents
172-
==================
173-
174-
To match values of fields of embedded documents, use the dot notation:
175-
176-
.. code-block:: ruby
177-
178-
Band.where('manager.name' => 'Smith')
179-
# => #<Mongoid::Criteria
180-
# selector: {"manager.name"=>"Smith"}
181-
# options: {}
182-
# class: Band
183-
# embedded: false>
184-
185-
Band.where(:'manager.name'.ne => 'Smith')
186-
# => #<Mongoid::Criteria
187-
# selector: {"manager.name"=>{"$ne"=>"Smith"}}
188-
# options: {}
189-
# class: Band
190-
# embedded: false>
191171

192-
.. note::
172+
Fields
173+
======
193174

194-
Queries always return top-level model instances, even if all of the
195-
conditions are referencing embedded documents.
196-
197-
Field Types
198-
===========
175+
Querying on Defined Fields
176+
--------------------------
199177

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

205183
.. code-block:: ruby
206184

207-
Band.where(name: 2020)
185+
Band.where(name: 2020, founded: "2020")
208186
# => #<Mongoid::Criteria
209-
# selector: {"name"=>"2020"}
187+
# selector: {"name"=>"2020", "founded"=>2020}
210188
# options: {}
211189
# class: Band
212190
# embedded: false>
213191

214-
Band.where(founded: 2020)
192+
Querying for Raw Values
193+
-----------------------
194+
195+
If you'd like to bypass Mongoid's query type coercion behavior and query
196+
directly for the raw-typed value in the database, wrap the query value in
197+
``Mongoid::RawValue`` class. This can be useful when working with legacy data.
198+
199+
.. code-block:: ruby
200+
201+
Band.where(founded: Mongoid::RawValue("2020"))
215202
# => #<Mongoid::Criteria
216-
# selector: {"founded"=>2020}
203+
# selector: {"founded"=>"2020"}
217204
# options: {}
218205
# class: Band
219206
# embedded: false>
220207

221-
Aliases
222-
=======
208+
Field Aliases
209+
-------------
223210

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

247234

235+
Embedded Documents
236+
==================
237+
238+
To match values of fields of embedded documents, use the dot notation:
239+
240+
.. code-block:: ruby
241+
242+
Band.where('manager.name' => 'Smith')
243+
# => #<Mongoid::Criteria
244+
# selector: {"manager.name"=>"Smith"}
245+
# options: {}
246+
# class: Band
247+
# embedded: false>
248+
249+
Band.where(:'manager.name'.ne => 'Smith')
250+
# => #<Mongoid::Criteria
251+
# selector: {"manager.name"=>{"$ne"=>"Smith"}}
252+
# options: {}
253+
# class: Band
254+
# embedded: false>
255+
256+
.. note::
257+
258+
Queries always return top-level model instances, even if all of the
259+
conditions are referencing embedded documents.
260+
261+
248262
.. _logical-operations:
249263

250264
Logical Operations

docs/release-notes/mongoid-8.1.txt

+18
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,24 @@ See the section on :ref:`Localize :present Field Option <present-fields>` for
187187
more details on how these are used.
188188

189189

190+
Support for Passing Raw Values into Queries
191+
-------------------------------------------
192+
193+
When performing queries, it is now possible skip Mongoid's type coercion logic
194+
using the ``Mongoid::RawValue`` wrapper class. This can be useful when legacy
195+
data in the database is of a different type than the field definition.
196+
197+
.. code-block:: ruby
198+
199+
class Person
200+
include Mongoid::Document
201+
field :age, type: Integer
202+
end
203+
204+
# Query for the string "42", not the integer 42
205+
Person.where(age: Mongoid::RawValue("42"))
206+
207+
190208
Added ``:to`` and ``:from`` options to ``attribute_changed?``
191209
-------------------------------------------------------------
192210

lib/mongoid/criteria/queryable/extensions/big_decimal.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ def evolve(object)
3333
end
3434
# Always return on string for backwards compatibility with querying
3535
# string-backed BigDecimal fields.
36-
when BSON::Decimal128, String then obj
36+
when BSON::Decimal128 then obj
3737
else
3838
if obj.numeric?
3939
if Mongoid.map_big_decimal_to_decimal128

lib/mongoid/criteria/queryable/extensions/date.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ def __evolve_date__
2525
#
2626
# @return [ Time ] The date as a local time.
2727
def __evolve_time__
28-
::Time.local(year, month, day)
28+
::Time.configured.local(year, month, day).to_time
2929
end
3030

3131
module ClassMethods

lib/mongoid/criteria/queryable/extensions/numeric.rb

+2
Original file line numberDiff line numberDiff line change
@@ -79,3 +79,5 @@ def evolve(object)
7979

8080
::Float.__send__(:include, Mongoid::Criteria::Queryable::Extensions::Numeric)
8181
::Float.__send__(:extend, Mongoid::Criteria::Queryable::Extensions::Numeric::ClassMethods)
82+
83+
::BigDecimal.__send__(:include, Mongoid::Criteria::Queryable::Extensions::Numeric)

lib/mongoid/criteria/queryable/selector.rb

+4-2
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ def to_pipeline
7575

7676
# Get the store name and store value. If the value is of type range,
7777
# we need may need to change the store_name as well as the store_value,
78-
# therefore, we cannot just use the evole method.
78+
# therefore, we cannot just use the evolve method.
7979
#
8080
# @param [ String ] name The name of the field.
8181
# @param [ Object ] serializer The optional serializer for the field.
@@ -150,6 +150,8 @@ def evolve_multi(specs)
150150
#
151151
# @return [ Object ] The serialized object.
152152
def evolve(serializer, value)
153+
return value.raw_value if value.is_a?(Mongoid::RawValue)
154+
153155
case value
154156
when Hash
155157
evolve_hash(serializer, value)
@@ -228,7 +230,7 @@ def evolve_hash(serializer, value)
228230
#
229231
# @api private
230232
#
231-
# @param [ String ] key The to store the range for.
233+
# @param [ String ] key The key at which to store the range.
232234
# @param [ Object ] serializer The optional serializer for the field.
233235
# @param [ Range ] value The Range to serialize.
234236
#

lib/mongoid/extensions.rb

+1
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ def transform_keys
4848
require "mongoid/extensions/object"
4949
require "mongoid/extensions/object_id"
5050
require "mongoid/extensions/range"
51+
require "mongoid/extensions/raw_value"
5152
require "mongoid/extensions/regexp"
5253
require "mongoid/extensions/set"
5354
require "mongoid/extensions/string"

lib/mongoid/extensions/raw_value.rb

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# frozen_string_literal: true
2+
3+
# Wrapper class used when a value cannot be casted in evolve method.
4+
module Mongoid
5+
def RawValue(*args)
6+
RawValue.new(*args)
7+
end
8+
9+
class RawValue
10+
11+
attr_reader :raw_value
12+
13+
def initialize(raw_value)
14+
@raw_value = raw_value
15+
end
16+
17+
# Returns a string containing a human-readable representation of
18+
# the object, including the inspection of the underlying value.
19+
#
20+
# @return [ String ] The object inspection.
21+
def inspect
22+
"RawValue: #{raw_value.inspect}"
23+
end
24+
end
25+
end

0 commit comments

Comments
 (0)