Skip to content

Commit f672984

Browse files
authored
MONGOID-5122 Mongoize embedded fields in the criteria selector (#5184)
* MONGOID-5122 mongoize embedded fields on query * MONGOID-5122 add comment for get_serializer * MONGOID-5122 fix tests * MONGOID-5122 fix matcher and optional tests * MONGOID-5122 evolve object on else * MONGOID-5122 add evolve_range method * MONGOID-5122 refactors + comments * add comment * MONGOID-5122 change to key arg * MONGOID-5122 add @api private
1 parent 257b61c commit f672984

File tree

8 files changed

+93
-23
lines changed

8 files changed

+93
-23
lines changed

lib/mongoid/criteria.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,7 @@ def initialize(klass)
230230
@klass = klass
231231
@embedded = nil
232232
@none = nil
233-
klass ? super(klass.aliased_fields, klass.fields) : super({}, {})
233+
klass ? super(klass.aliased_fields, klass.fields, klass.relations) : super({}, {}, {})
234234
end
235235

236236
# Merges another object with this +Criteria+ and returns a new criteria.

lib/mongoid/criteria/queryable.rb

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,11 +59,14 @@ def ==(other)
5959
#
6060
# @param [ Hash ] aliases The optional field aliases.
6161
# @param [ Hash ] serializers The optional field serializers.
62+
# @param [ Hash ] associations The optional associations.
6263
# @param [ Symbol ] driver The driver being used.
63-
def initialize(aliases = {}, serializers = {}, driver = :mongo)
64+
#
65+
# @api private
66+
def initialize(aliases = {}, serializers = {}, associations = {}, driver = :mongo)
6467
@aliases, @driver, @serializers = aliases, driver.to_sym, serializers
6568
@options = Options.new(aliases, serializers)
66-
@selector = Selector.new(aliases, serializers)
69+
@selector = Selector.new(aliases, serializers, associations)
6770
@pipeline = Pipeline.new(aliases)
6871
@aggregating = nil
6972
yield(self) if block_given?

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

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,13 +43,21 @@ def __evolve_time__
4343
# @example Evolve the range.
4444
# (11231312..213123131).__evolve_range__
4545
#
46+
# @param [ Object ] serializer The optional serializer for the field.
47+
#
4648
# @return [ Hash ] The $gte/$lte range query.
47-
def __evolve_range__
49+
#
50+
# @api private
51+
def __evolve_range__(serializer: nil)
4852
__evolve_range_naive__.transform_values! do |value|
49-
case value
50-
when Time, DateTime then value.__evolve_time__
51-
when Date then value.__evolve_date__
52-
else value
53+
if serializer
54+
serializer.evolve(value)
55+
else
56+
case value
57+
when Time, DateTime then value.__evolve_time__
58+
when Date then value.__evolve_date__
59+
else value
60+
end
5361
end
5462
end
5563
end

lib/mongoid/criteria/queryable/selector.rb

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,8 @@ def evolve(serializer, value)
139139
evolve_hash(serializer, value)
140140
when Array
141141
evolve_array(serializer, value)
142+
when Range
143+
evolve_range(serializer, value)
142144
else
143145
(serializer || value.class).evolve(value)
144146
end
@@ -182,6 +184,18 @@ def evolve_hash(serializer, value)
182184
end
183185
end
184186

187+
# Evolve a single key selection with range values.
188+
#
189+
# @param [ Object ] serializer The optional serializer for the field.
190+
# @param [ Range ] value The Range to serialize.
191+
#
192+
# @return [ Range ] The serialized Range.
193+
#
194+
# @api private
195+
def evolve_range(serializer, value)
196+
value.__evolve_range__(serializer: serializer)
197+
end
198+
185199
# Determines if the selection is a multi-select, like an $and or $or or $nor
186200
# selection.
187201
#

lib/mongoid/criteria/queryable/smash.rb

Lines changed: 42 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,13 @@ module Queryable
88
class Smash < Hash
99

1010
# @attribute [r] aliases The aliases.
11+
attr_reader :aliases
12+
1113
# @attribute [r] serializers The serializers.
12-
attr_reader :aliases, :serializers
14+
attr_reader :serializers
15+
16+
# @attribute [r] associations The associations.
17+
attr_reader :associations
1318

1419
# Perform a deep copy of the smash.
1520
#
@@ -18,7 +23,7 @@ class Smash < Hash
1823
#
1924
# @return [ Smash ] The copied hash.
2025
def __deep_copy__
21-
self.class.new(aliases, serializers) do |copy|
26+
self.class.new(aliases, serializers, associations) do |copy|
2227
each_pair do |key, value|
2328
copy.store(key, value.__deep_copy__)
2429
end
@@ -36,8 +41,8 @@ def __deep_copy__
3641
# responsible for serializing values. The keys of the hash must be
3742
# strings that match the field name, and the values must respond to
3843
# #localized? and #evolve(object).
39-
def initialize(aliases = {}, serializers = {})
40-
@aliases, @serializers = aliases, serializers
44+
def initialize(aliases = {}, serializers = {}, associations = {})
45+
@aliases, @serializers, @associations = aliases, serializers, associations
4146
yield(self) if block_given?
4247
end
4348

@@ -87,7 +92,39 @@ def localized_key(name, serializer)
8792
def storage_pair(key)
8893
field = key.to_s
8994
name = aliases[field] || field
90-
[ name, serializers[name] ]
95+
[ name, get_serializer(name) ]
96+
end
97+
98+
private
99+
100+
# Retrieves the serializer for the given name. If the name exists in
101+
# the serializers hash then return that immediately, otherwise
102+
# recursively look through the associations and find the appropriate
103+
# field.
104+
#
105+
# @param [ String ] name The name of the db field.
106+
#
107+
# @return [ Object ] The serializer.
108+
def get_serializer(name)
109+
if s = serializers[name]
110+
s
111+
else
112+
klass = nil
113+
serializer = nil
114+
name.split('.').each do |meth|
115+
fs = klass ? klass.fields : serializers
116+
if field = fs[meth]
117+
serializer = field
118+
else
119+
serializer = nil
120+
rs = klass ? klass.associations : associations
121+
if rel = rs[meth]
122+
klass = rel.klass
123+
end
124+
end
125+
end
126+
serializer
127+
end
91128
end
92129
end
93130
end

spec/integration/matcher_examples_spec.rb

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -652,10 +652,12 @@
652652

653653
describe 'range match on array element' do
654654

655+
let(:record) do
656+
Record.new(producers: [123, 456])
657+
end
658+
655659
let!(:band) do
656-
Band.create!(records: [
657-
Record.new(producers: [123, 456]),
658-
])
660+
Band.create!(records: [ record ])
659661
end
660662

661663
describe 'MongoDB query' do
@@ -687,10 +689,8 @@
687689
band.records.where(producers: 100..200).first
688690
end
689691

690-
it 'raises InvalidQuery' do
691-
lambda do
692-
found_record
693-
end.should raise_error(Mongoid::Errors::InvalidQuery)
692+
it 'finds' do
693+
expect(found_record).to eq(record)
694694
end
695695
end
696696
end

spec/mongoid/criteria/queryable/optional_spec.rb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@
146146
context "when using the mongo-1.x driver syntax" do
147147

148148
let(:query) do
149-
Mongoid::Query.new({}, {}, :mongo1x)
149+
Mongoid::Query.new({}, {}, {}, :mongo1x)
150150
end
151151

152152
context "when provided symbols" do
@@ -419,7 +419,7 @@
419419
context "when using the mongo-1.x driver syntax" do
420420

421421
let(:query) do
422-
Mongoid::Query.new({}, {}, :mongo1x)
422+
Mongoid::Query.new({}, {}, {}, :mongo1x)
423423
end
424424

425425
context "when provided symbols" do
@@ -1176,7 +1176,7 @@
11761176
context "when using the mongo-1.x driver syntax" do
11771177

11781178
let(:query) do
1179-
Mongoid::Query.new({}, {}, :mongo1x)
1179+
Mongoid::Query.new({}, {}, {}, :mongo1x)
11801180
end
11811181

11821182
context "when provided a hash" do

spec/mongoid/criteria_spec.rb

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3967,6 +3967,14 @@ def self.ages; self; end
39673967
expect(dup_criteria.selector).to eq({ "_id" => _id })
39683968
end
39693969
end
3970+
3971+
context "when querying an embedded field" do
3972+
let(:criteria) { Band.where("label.name": 12345) }
3973+
3974+
it "mongoizes the embedded field in the selector" do
3975+
expect(criteria.selector).to eq("label.name" => "12345")
3976+
end
3977+
end
39703978
end
39713979

39723980
describe "#for_js" do

0 commit comments

Comments
 (0)