mongoid 7.0.3 → 7.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +2 -0
- data.tar.gz.sig +1 -0
- data/LICENSE +1 -0
- data/README.md +3 -2
- data/Rakefile +12 -0
- data/lib/mongoid.rb +2 -1
- data/lib/mongoid/association/embedded/embeds_many.rb +2 -1
- data/lib/mongoid/association/embedded/embeds_one.rb +2 -1
- data/lib/mongoid/association/proxy.rb +1 -1
- data/lib/mongoid/association/relatable.rb +23 -21
- data/lib/mongoid/atomic.rb +13 -3
- data/lib/mongoid/atomic/paths/embedded.rb +1 -1
- data/lib/mongoid/attributes.rb +28 -20
- data/lib/mongoid/attributes/dynamic.rb +15 -14
- data/lib/mongoid/config/environment.rb +21 -8
- data/lib/mongoid/copyable.rb +5 -1
- data/lib/mongoid/criteria.rb +7 -1
- data/lib/mongoid/criteria/modifiable.rb +13 -2
- data/lib/mongoid/criteria/queryable/extensions/numeric.rb +1 -1
- data/lib/mongoid/criteria/queryable/extensions/regexp.rb +3 -3
- data/lib/mongoid/criteria/queryable/key.rb +67 -8
- data/lib/mongoid/criteria/queryable/mergeable.rb +5 -4
- data/lib/mongoid/criteria/queryable/selectable.rb +3 -4
- data/lib/mongoid/criteria/queryable/selector.rb +9 -31
- data/lib/mongoid/extensions/hash.rb +4 -2
- data/lib/mongoid/extensions/regexp.rb +1 -1
- data/lib/mongoid/extensions/string.rb +5 -3
- data/lib/mongoid/fields.rb +2 -1
- data/lib/mongoid/matchable.rb +14 -15
- data/lib/mongoid/matchable/all.rb +4 -3
- data/lib/mongoid/matchable/default.rb +71 -24
- data/lib/mongoid/matchable/regexp.rb +2 -2
- data/lib/mongoid/persistable/pushable.rb +11 -2
- data/lib/mongoid/persistence_context.rb +6 -6
- data/lib/mongoid/positional.rb +1 -1
- data/lib/mongoid/query_cache.rb +3 -2
- data/lib/mongoid/validatable/macros.rb +1 -1
- data/lib/mongoid/validatable/uniqueness.rb +1 -1
- data/lib/mongoid/version.rb +2 -1
- data/lib/rails/generators/mongoid/model/templates/model.rb.tt +1 -1
- data/spec/README.md +18 -0
- data/spec/app/models/delegating_patient.rb +16 -0
- data/spec/app/models/other_owner_object.rb +2 -0
- data/spec/integration/app_spec.rb +192 -0
- data/spec/integration/associations/embedded_spec.rb +62 -0
- data/spec/integration/criteria/time_with_zone_spec.rb +32 -0
- data/spec/integration/document_spec.rb +22 -0
- data/spec/integration/matchable_spec.rb +680 -0
- data/spec/lite_spec_helper.rb +15 -5
- data/spec/mongoid/association/embedded/embedded_in_spec.rb +58 -0
- data/spec/mongoid/association/embedded/embeds_many_models.rb +53 -0
- data/spec/mongoid/association/embedded/embeds_many_spec.rb +10 -0
- data/spec/mongoid/association/embedded/embeds_one_dnl_models.rb +6 -0
- data/spec/mongoid/association/embedded/embeds_one_models.rb +51 -0
- data/spec/mongoid/association/embedded/embeds_one_spec.rb +46 -0
- data/spec/mongoid/association/referenced/belongs_to_spec.rb +23 -6
- data/spec/mongoid/association/referenced/has_and_belongs_to_many/proxy_spec.rb +2 -1
- data/spec/mongoid/association/referenced/has_many/proxy_spec.rb +2 -1
- data/spec/mongoid/association/referenced/has_one_spec.rb +12 -2
- data/spec/mongoid/attributes/dynamic_spec.rb +153 -0
- data/spec/mongoid/attributes_spec.rb +19 -7
- data/spec/mongoid/clients/factory_spec.rb +2 -2
- data/spec/mongoid/clients/options_spec.rb +4 -4
- data/spec/mongoid/clients/sessions_spec.rb +20 -7
- data/spec/mongoid/clients/transactions_spec.rb +36 -15
- data/spec/mongoid/clients_spec.rb +2 -2
- data/spec/mongoid/contextual/atomic_spec.rb +20 -10
- data/spec/mongoid/contextual/geo_near_spec.rb +1 -0
- data/spec/mongoid/contextual/map_reduce_spec.rb +20 -5
- data/spec/mongoid/contextual/mongo_spec.rb +76 -53
- data/spec/mongoid/criteria/modifiable_spec.rb +59 -10
- data/spec/mongoid/criteria/queryable/extensions/numeric_spec.rb +54 -0
- data/spec/mongoid/criteria/queryable/extensions/regexp_spec.rb +7 -7
- data/spec/mongoid/criteria/queryable/extensions/string_spec.rb +1 -1
- data/spec/mongoid/criteria/queryable/key_spec.rb +48 -6
- data/spec/mongoid/criteria/queryable/selectable_logical_spec.rb +762 -0
- data/spec/mongoid/criteria/queryable/selectable_spec.rb +5 -224
- data/spec/mongoid/criteria/queryable/selector_spec.rb +37 -0
- data/spec/mongoid/criteria_spec.rb +7 -2
- data/spec/mongoid/document_fields_spec.rb +88 -0
- data/spec/mongoid/document_persistence_context_spec.rb +33 -0
- data/spec/mongoid/extensions/string_spec.rb +35 -7
- data/spec/mongoid/indexable_spec.rb +6 -4
- data/spec/mongoid/matchable/default_spec.rb +10 -3
- data/spec/mongoid/matchable/regexp_spec.rb +2 -2
- data/spec/mongoid/matchable_spec.rb +2 -2
- data/spec/mongoid/persistable/pushable_spec.rb +55 -1
- data/spec/mongoid/query_cache_spec.rb +2 -1
- data/spec/mongoid/relations/proxy_spec.rb +1 -1
- data/spec/mongoid/scopable_spec.rb +2 -1
- data/spec/mongoid/tasks/database_rake_spec.rb +13 -13
- data/spec/mongoid/tasks/database_spec.rb +1 -1
- data/spec/mongoid/validatable/uniqueness_spec.rb +33 -6
- data/spec/spec_helper.rb +4 -37
- data/spec/support/child_process_helper.rb +76 -0
- data/spec/support/cluster_config.rb +158 -0
- data/spec/support/constraints.rb +29 -19
- data/spec/support/expectations.rb +17 -3
- data/spec/support/spec_config.rb +12 -4
- metadata +525 -464
- metadata.gz.sig +2 -0
|
@@ -23,16 +23,58 @@ describe Mongoid::Criteria::Queryable::Key do
|
|
|
23
23
|
|
|
24
24
|
describe "#__expr_part__" do
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
|
|
26
|
+
context 'operator only' do
|
|
27
|
+
let(:key) do
|
|
28
|
+
described_class.new("field", :__union__, "$all")
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
let(:specified) do
|
|
32
|
+
key.__expr_part__([ 1, 2 ])
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
it "returns the name plus operator and value" do
|
|
36
|
+
expect(specified).to eq({ "field" => { "$all" => [ 1, 2 ] }})
|
|
37
|
+
end
|
|
28
38
|
end
|
|
29
39
|
|
|
30
|
-
|
|
31
|
-
key
|
|
40
|
+
context 'operator and expanded only' do
|
|
41
|
+
let(:key) do
|
|
42
|
+
described_class.new("field", :__override__, "$geoIntersects", '$geometry')
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
let(:specified) do
|
|
46
|
+
key.__expr_part__([ 1, 10 ])
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
it "returns the query expression" do
|
|
50
|
+
expect(specified).to eq({ "field" => {
|
|
51
|
+
'$geoIntersects' => {
|
|
52
|
+
'$geometry' => [1, 10],
|
|
53
|
+
},
|
|
54
|
+
}})
|
|
55
|
+
end
|
|
32
56
|
end
|
|
33
57
|
|
|
34
|
-
|
|
35
|
-
|
|
58
|
+
context 'operator, expanded and block' do
|
|
59
|
+
let(:key) do
|
|
60
|
+
described_class.new("field", :__override__, "$geoIntersects", '$geometry') do |value|
|
|
61
|
+
{ "type" => 'Point', "coordinates" => value }
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
let(:specified) do
|
|
66
|
+
key.__expr_part__([ 1, 10 ])
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
it "returns the query expression" do
|
|
70
|
+
expect(specified).to eq({ "field" => {
|
|
71
|
+
'$geoIntersects' => {
|
|
72
|
+
'$geometry' => {
|
|
73
|
+
'type' => 'Point', 'coordinates' => [1, 10],
|
|
74
|
+
},
|
|
75
|
+
},
|
|
76
|
+
}})
|
|
77
|
+
end
|
|
36
78
|
end
|
|
37
79
|
end
|
|
38
80
|
|
|
@@ -0,0 +1,762 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# encoding: utf-8
|
|
3
|
+
|
|
4
|
+
require "spec_helper"
|
|
5
|
+
|
|
6
|
+
describe Mongoid::Criteria::Queryable::Selectable do
|
|
7
|
+
|
|
8
|
+
let(:query) do
|
|
9
|
+
Mongoid::Query.new("id" => "_id")
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
describe "#and" do
|
|
13
|
+
|
|
14
|
+
context "when provided no criterion" do
|
|
15
|
+
|
|
16
|
+
let(:selection) do
|
|
17
|
+
query.and
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
it "does not add any criterion" do
|
|
21
|
+
expect(selection.selector).to eq({})
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
it "returns the query" do
|
|
25
|
+
expect(selection).to eq(query)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
it "returns a cloned query" do
|
|
29
|
+
expect(selection).to_not equal(query)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
context "when provided nil" do
|
|
34
|
+
|
|
35
|
+
let(:selection) do
|
|
36
|
+
query.and(nil)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
it "does not add any criterion" do
|
|
40
|
+
expect(selection.selector).to eq({})
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
it "returns the query" do
|
|
44
|
+
expect(selection).to eq(query)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
it "returns a cloned query" do
|
|
48
|
+
expect(selection).to_not equal(query)
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
context "when provided a single criterion" do
|
|
53
|
+
|
|
54
|
+
let(:selection) do
|
|
55
|
+
query.and(field: [ 1, 2 ])
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
it "adds the $and selector" do
|
|
59
|
+
expect(selection.selector).to eq({
|
|
60
|
+
"$and" => [{ "field" => [ 1, 2 ] }]
|
|
61
|
+
})
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
it "returns a cloned query" do
|
|
65
|
+
expect(selection).to_not equal(query)
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
context "when provided a nested criterion" do
|
|
70
|
+
|
|
71
|
+
let(:selection) do
|
|
72
|
+
query.and(:test.elem_match => { :field.in => [ 1, 2 ] })
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
it "adds the $and selector" do
|
|
76
|
+
expect(selection.selector).to eq({
|
|
77
|
+
"$and" => [{ "test" => { "$elemMatch" => { "field" => { "$in" => [ 1, 2 ] }}}}]
|
|
78
|
+
})
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
it "returns a cloned query" do
|
|
82
|
+
expect(selection).to_not equal(query)
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
context "when provided multiple criterion" do
|
|
87
|
+
|
|
88
|
+
context "when the criterion is already included" do
|
|
89
|
+
|
|
90
|
+
let(:selection) do
|
|
91
|
+
query.and({ first: [ 1, 2 ] }).and({ first: [ 1, 2 ] })
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
it "does not duplicate the $and selector" do
|
|
95
|
+
expect(selection.selector).to eq({
|
|
96
|
+
"$and" => [
|
|
97
|
+
{ "first" => [ 1, 2 ] }
|
|
98
|
+
]
|
|
99
|
+
})
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
it "returns a cloned query" do
|
|
103
|
+
expect(selection).to_not equal(query)
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
context "when the criterion are for different fields" do
|
|
108
|
+
|
|
109
|
+
let(:selection) do
|
|
110
|
+
query.and({ first: [ 1, 2 ] }, { second: [ 3, 4 ] })
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
it "adds the $and selector" do
|
|
114
|
+
expect(selection.selector).to eq({
|
|
115
|
+
"$and" => [
|
|
116
|
+
{ "first" => [ 1, 2 ] },
|
|
117
|
+
{ "second" => [ 3, 4 ] }
|
|
118
|
+
]
|
|
119
|
+
})
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
it "returns a cloned query" do
|
|
123
|
+
expect(selection).to_not equal(query)
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
context "when the criterion are on the same field" do
|
|
128
|
+
|
|
129
|
+
let(:selection) do
|
|
130
|
+
query.and({ first: [ 1, 2 ] }, { first: [ 3, 4 ] })
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
it "appends both $and expressions" do
|
|
134
|
+
expect(selection.selector).to eq({
|
|
135
|
+
"$and" => [
|
|
136
|
+
{ "first" => [ 1, 2 ] },
|
|
137
|
+
{ "first" => [ 3, 4 ] }
|
|
138
|
+
]
|
|
139
|
+
})
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
it "returns a cloned query" do
|
|
143
|
+
expect(selection).to_not equal(query)
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
context "when chaining the criterion" do
|
|
149
|
+
|
|
150
|
+
context "when the criterion are for different fields" do
|
|
151
|
+
|
|
152
|
+
let(:selection) do
|
|
153
|
+
query.and(first: [ 1, 2 ]).and(second: [ 3, 4 ])
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
it "adds the $and selectors" do
|
|
157
|
+
expect(selection.selector).to eq({
|
|
158
|
+
"$and" => [
|
|
159
|
+
{ "first" => [ 1, 2 ] },
|
|
160
|
+
{ "second" => [ 3, 4 ] }
|
|
161
|
+
]
|
|
162
|
+
})
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
it "returns a cloned query" do
|
|
166
|
+
expect(selection).to_not equal(query)
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
context "when the criterion are on the same field" do
|
|
171
|
+
|
|
172
|
+
let(:selection) do
|
|
173
|
+
query.and(first: [ 1, 2 ]).and(first: [ 3, 4 ])
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
it "appends both $and expressions" do
|
|
177
|
+
expect(selection.selector).to eq({
|
|
178
|
+
"$and" => [
|
|
179
|
+
{ "first" => [ 1, 2 ] },
|
|
180
|
+
{ "first" => [ 3, 4 ] }
|
|
181
|
+
]
|
|
182
|
+
})
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
it "returns a cloned query" do
|
|
186
|
+
expect(selection).to_not equal(query)
|
|
187
|
+
end
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
describe "#or" do
|
|
193
|
+
|
|
194
|
+
context "when provided no criterion" do
|
|
195
|
+
|
|
196
|
+
let(:selection) do
|
|
197
|
+
query.or
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
it "does not add any criterion" do
|
|
201
|
+
expect(selection.selector).to eq({})
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
it "returns the query" do
|
|
205
|
+
expect(selection).to eq(query)
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
it "returns a cloned query" do
|
|
209
|
+
expect(selection).to_not equal(query)
|
|
210
|
+
end
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
context "when provided nil" do
|
|
214
|
+
|
|
215
|
+
let(:selection) do
|
|
216
|
+
query.or(nil)
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
it "does not add any criterion" do
|
|
220
|
+
expect(selection.selector).to eq({})
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
it "returns the query" do
|
|
224
|
+
expect(selection).to eq(query)
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
it "returns a cloned query" do
|
|
228
|
+
expect(selection).to_not equal(query)
|
|
229
|
+
end
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
context "when provided a single criterion" do
|
|
233
|
+
|
|
234
|
+
let(:selection) do
|
|
235
|
+
query.or(field: [ 1, 2 ])
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
it "adds the $or selector" do
|
|
239
|
+
expect(selection.selector).to eq({
|
|
240
|
+
"$or" => [{ "field" => [ 1, 2 ] }]
|
|
241
|
+
})
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
it "returns a cloned query" do
|
|
245
|
+
expect(selection).to_not equal(query)
|
|
246
|
+
end
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
context "when provided multiple criterion" do
|
|
250
|
+
|
|
251
|
+
context "when the criterion are for different fields" do
|
|
252
|
+
|
|
253
|
+
let(:selection) do
|
|
254
|
+
query.or({ first: [ 1, 2 ] }, { second: [ 3, 4 ] })
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
it "adds the $or selector" do
|
|
258
|
+
expect(selection.selector).to eq({
|
|
259
|
+
"$or" => [
|
|
260
|
+
{ "first" => [ 1, 2 ] },
|
|
261
|
+
{ "second" => [ 3, 4 ] }
|
|
262
|
+
]
|
|
263
|
+
})
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
it "returns a cloned query" do
|
|
267
|
+
expect(selection).to_not equal(query)
|
|
268
|
+
end
|
|
269
|
+
end
|
|
270
|
+
|
|
271
|
+
context "when a criterion has a selectable key" do
|
|
272
|
+
|
|
273
|
+
let(:selection) do
|
|
274
|
+
query.or({ first: [ 1, 2 ] }, { :second.gt => 3 })
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
it "adds the $or selector" do
|
|
278
|
+
expect(selection.selector).to eq({
|
|
279
|
+
"$or" => [
|
|
280
|
+
{ "first" => [ 1, 2 ] },
|
|
281
|
+
{ "second" => { "$gt" => 3 }}
|
|
282
|
+
]
|
|
283
|
+
})
|
|
284
|
+
end
|
|
285
|
+
|
|
286
|
+
it "returns a cloned query" do
|
|
287
|
+
expect(selection).to_not equal(query)
|
|
288
|
+
end
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
context "when the criterion has an aliased field" do
|
|
292
|
+
|
|
293
|
+
let(:selection) do
|
|
294
|
+
query.or({ id: 1 })
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
it "adds the $or selector and aliases the field" do
|
|
298
|
+
expect(selection.selector).to eq({
|
|
299
|
+
"$or" => [ { "_id" => 1 } ]
|
|
300
|
+
})
|
|
301
|
+
end
|
|
302
|
+
|
|
303
|
+
it "returns a cloned query" do
|
|
304
|
+
expect(selection).to_not equal(query)
|
|
305
|
+
end
|
|
306
|
+
end
|
|
307
|
+
|
|
308
|
+
context "when a criterion is wrapped in an array" do
|
|
309
|
+
|
|
310
|
+
let(:selection) do
|
|
311
|
+
query.or([{ first: [ 1, 2 ] }, { :second.gt => 3 }])
|
|
312
|
+
end
|
|
313
|
+
|
|
314
|
+
it "adds the $or selector" do
|
|
315
|
+
expect(selection.selector).to eq({
|
|
316
|
+
"$or" => [
|
|
317
|
+
{ "first" => [ 1, 2 ] },
|
|
318
|
+
{ "second" => { "$gt" => 3 }}
|
|
319
|
+
]
|
|
320
|
+
})
|
|
321
|
+
end
|
|
322
|
+
|
|
323
|
+
it "returns a cloned query" do
|
|
324
|
+
expect(selection).to_not equal(query)
|
|
325
|
+
end
|
|
326
|
+
end
|
|
327
|
+
|
|
328
|
+
context "when the criterion are on the same field" do
|
|
329
|
+
|
|
330
|
+
let(:selection) do
|
|
331
|
+
query.or({ first: [ 1, 2 ] }, { first: [ 3, 4 ] })
|
|
332
|
+
end
|
|
333
|
+
|
|
334
|
+
it "appends both $or expressions" do
|
|
335
|
+
expect(selection.selector).to eq({
|
|
336
|
+
"$or" => [
|
|
337
|
+
{ "first" => [ 1, 2 ] },
|
|
338
|
+
{ "first" => [ 3, 4 ] }
|
|
339
|
+
]
|
|
340
|
+
})
|
|
341
|
+
end
|
|
342
|
+
|
|
343
|
+
it "returns a cloned query" do
|
|
344
|
+
expect(selection).to_not equal(query)
|
|
345
|
+
end
|
|
346
|
+
end
|
|
347
|
+
end
|
|
348
|
+
|
|
349
|
+
context "when chaining the criterion" do
|
|
350
|
+
|
|
351
|
+
context "when the criterion are for different fields" do
|
|
352
|
+
|
|
353
|
+
let(:selection) do
|
|
354
|
+
query.or(first: [ 1, 2 ]).or(second: [ 3, 4 ])
|
|
355
|
+
end
|
|
356
|
+
|
|
357
|
+
it "adds the $or selectors" do
|
|
358
|
+
expect(selection.selector).to eq({
|
|
359
|
+
"$or" => [
|
|
360
|
+
{ "first" => [ 1, 2 ] },
|
|
361
|
+
{ "second" => [ 3, 4 ] }
|
|
362
|
+
]
|
|
363
|
+
})
|
|
364
|
+
end
|
|
365
|
+
|
|
366
|
+
it "returns a cloned query" do
|
|
367
|
+
expect(selection).to_not equal(query)
|
|
368
|
+
end
|
|
369
|
+
end
|
|
370
|
+
|
|
371
|
+
context "when the criterion are on the same field" do
|
|
372
|
+
|
|
373
|
+
let(:selection) do
|
|
374
|
+
query.or(first: [ 1, 2 ]).or(first: [ 3, 4 ])
|
|
375
|
+
end
|
|
376
|
+
|
|
377
|
+
it "appends both $or expressions" do
|
|
378
|
+
expect(selection.selector).to eq({
|
|
379
|
+
"$or" => [
|
|
380
|
+
{ "first" => [ 1, 2 ] },
|
|
381
|
+
{ "first" => [ 3, 4 ] }
|
|
382
|
+
]
|
|
383
|
+
})
|
|
384
|
+
end
|
|
385
|
+
|
|
386
|
+
it "returns a cloned query" do
|
|
387
|
+
expect(selection).to_not equal(query)
|
|
388
|
+
end
|
|
389
|
+
end
|
|
390
|
+
end
|
|
391
|
+
end
|
|
392
|
+
|
|
393
|
+
describe "#nor" do
|
|
394
|
+
|
|
395
|
+
context "when provided no criterion" do
|
|
396
|
+
|
|
397
|
+
let(:selection) do
|
|
398
|
+
query.nor
|
|
399
|
+
end
|
|
400
|
+
|
|
401
|
+
it "does not add any criterion" do
|
|
402
|
+
expect(selection.selector).to eq({})
|
|
403
|
+
end
|
|
404
|
+
|
|
405
|
+
it "returns the query" do
|
|
406
|
+
expect(selection).to eq(query)
|
|
407
|
+
end
|
|
408
|
+
|
|
409
|
+
it "returns a cloned query" do
|
|
410
|
+
expect(selection).to_not equal(query)
|
|
411
|
+
end
|
|
412
|
+
end
|
|
413
|
+
|
|
414
|
+
context "when provided nil" do
|
|
415
|
+
|
|
416
|
+
let(:selection) do
|
|
417
|
+
query.nor(nil)
|
|
418
|
+
end
|
|
419
|
+
|
|
420
|
+
it "does not add any criterion" do
|
|
421
|
+
expect(selection.selector).to eq({})
|
|
422
|
+
end
|
|
423
|
+
|
|
424
|
+
it "returns the query" do
|
|
425
|
+
expect(selection).to eq(query)
|
|
426
|
+
end
|
|
427
|
+
|
|
428
|
+
it "returns a cloned query" do
|
|
429
|
+
expect(selection).to_not equal(query)
|
|
430
|
+
end
|
|
431
|
+
end
|
|
432
|
+
|
|
433
|
+
context "when provided a single criterion" do
|
|
434
|
+
|
|
435
|
+
let(:selection) do
|
|
436
|
+
query.nor(field: [ 1, 2 ])
|
|
437
|
+
end
|
|
438
|
+
|
|
439
|
+
it "adds the $nor selector" do
|
|
440
|
+
expect(selection.selector).to eq({
|
|
441
|
+
"$nor" => [{"field" => [ 1, 2 ] }]
|
|
442
|
+
})
|
|
443
|
+
end
|
|
444
|
+
|
|
445
|
+
it "returns a cloned query" do
|
|
446
|
+
expect(selection).to_not equal(query)
|
|
447
|
+
end
|
|
448
|
+
end
|
|
449
|
+
|
|
450
|
+
context "when provided multiple criterion" do
|
|
451
|
+
|
|
452
|
+
context "when the criterion are fnor different fields" do
|
|
453
|
+
|
|
454
|
+
let(:selection) do
|
|
455
|
+
query.nor({ first: [ 1, 2 ] }, { second: [ 3, 4 ] })
|
|
456
|
+
end
|
|
457
|
+
|
|
458
|
+
it "adds the $nor selector" do
|
|
459
|
+
expect(selection.selector).to eq({
|
|
460
|
+
"$nor" => [
|
|
461
|
+
{ "first" => [ 1, 2 ] },
|
|
462
|
+
{ "second" => [ 3, 4 ] }
|
|
463
|
+
]
|
|
464
|
+
})
|
|
465
|
+
end
|
|
466
|
+
|
|
467
|
+
it "returns a cloned query" do
|
|
468
|
+
expect(selection).to_not equal(query)
|
|
469
|
+
end
|
|
470
|
+
end
|
|
471
|
+
|
|
472
|
+
context "when the criterion are on the same field" do
|
|
473
|
+
|
|
474
|
+
let(:selection) do
|
|
475
|
+
query.nor({ first: [ 1, 2 ] }, { first: [ 3, 4 ] })
|
|
476
|
+
end
|
|
477
|
+
|
|
478
|
+
it "appends both $nor expressions" do
|
|
479
|
+
expect(selection.selector).to eq({
|
|
480
|
+
"$nor" => [
|
|
481
|
+
{ "first" => [ 1, 2 ] },
|
|
482
|
+
{ "first" => [ 3, 4 ] }
|
|
483
|
+
]
|
|
484
|
+
})
|
|
485
|
+
end
|
|
486
|
+
|
|
487
|
+
it "returns a cloned query" do
|
|
488
|
+
expect(selection).to_not equal(query)
|
|
489
|
+
end
|
|
490
|
+
end
|
|
491
|
+
end
|
|
492
|
+
|
|
493
|
+
context "when chaining the criterion" do
|
|
494
|
+
|
|
495
|
+
context "when the criterion are fnor different fields" do
|
|
496
|
+
|
|
497
|
+
let(:selection) do
|
|
498
|
+
query.nor(first: [ 1, 2 ]).nor(second: [ 3, 4 ])
|
|
499
|
+
end
|
|
500
|
+
|
|
501
|
+
it "adds the $nor selectors" do
|
|
502
|
+
expect(selection.selector).to eq({
|
|
503
|
+
"$nor" => [
|
|
504
|
+
{ "first" => [ 1, 2 ] },
|
|
505
|
+
{ "second" => [ 3, 4 ] }
|
|
506
|
+
]
|
|
507
|
+
})
|
|
508
|
+
end
|
|
509
|
+
|
|
510
|
+
it "returns a cloned query" do
|
|
511
|
+
expect(selection).to_not equal(query)
|
|
512
|
+
end
|
|
513
|
+
end
|
|
514
|
+
|
|
515
|
+
context "when the criterion are on the same field" do
|
|
516
|
+
|
|
517
|
+
let(:selection) do
|
|
518
|
+
query.nor(first: [ 1, 2 ]).nor(first: [ 3, 4 ])
|
|
519
|
+
end
|
|
520
|
+
|
|
521
|
+
it "appends both $nor expressions" do
|
|
522
|
+
expect(selection.selector).to eq({
|
|
523
|
+
"$nor" => [
|
|
524
|
+
{ "first" => [ 1, 2 ] },
|
|
525
|
+
{ "first" => [ 3, 4 ] }
|
|
526
|
+
]
|
|
527
|
+
})
|
|
528
|
+
end
|
|
529
|
+
|
|
530
|
+
it "returns a cloned query" do
|
|
531
|
+
expect(selection).to_not equal(query)
|
|
532
|
+
end
|
|
533
|
+
end
|
|
534
|
+
end
|
|
535
|
+
end
|
|
536
|
+
|
|
537
|
+
describe "#not" do
|
|
538
|
+
|
|
539
|
+
context "when provided no criterion" do
|
|
540
|
+
|
|
541
|
+
let(:selection) do
|
|
542
|
+
query.not
|
|
543
|
+
end
|
|
544
|
+
|
|
545
|
+
it "does not add any criterion" do
|
|
546
|
+
expect(selection.selector).to eq({})
|
|
547
|
+
end
|
|
548
|
+
|
|
549
|
+
it "returns the query" do
|
|
550
|
+
expect(selection).to eq(query)
|
|
551
|
+
end
|
|
552
|
+
|
|
553
|
+
it "returns a cloned query" do
|
|
554
|
+
expect(selection).not_to equal(query)
|
|
555
|
+
end
|
|
556
|
+
|
|
557
|
+
it 'does not mutate receiver' do
|
|
558
|
+
expect(query.negating).to be nil
|
|
559
|
+
|
|
560
|
+
selection
|
|
561
|
+
expect(query.negating).to be nil
|
|
562
|
+
end
|
|
563
|
+
|
|
564
|
+
context "when the following criteria is a query method" do
|
|
565
|
+
|
|
566
|
+
let(:selection) do
|
|
567
|
+
query.not.all(field: [ 1, 2 ])
|
|
568
|
+
end
|
|
569
|
+
|
|
570
|
+
it "negates the all selection" do
|
|
571
|
+
expect(selection.selector).to eq(
|
|
572
|
+
{ "field" => { "$not" => { "$all" => [ 1, 2 ] }}}
|
|
573
|
+
)
|
|
574
|
+
end
|
|
575
|
+
|
|
576
|
+
it "returns a cloned query" do
|
|
577
|
+
expect(selection).to_not equal(query)
|
|
578
|
+
end
|
|
579
|
+
|
|
580
|
+
it "removes the negation on the clone" do
|
|
581
|
+
expect(selection).to_not be_negating
|
|
582
|
+
end
|
|
583
|
+
end
|
|
584
|
+
|
|
585
|
+
context "when the following criteria is a gt method" do
|
|
586
|
+
|
|
587
|
+
let(:selection) do
|
|
588
|
+
query.not.gt(age: 50)
|
|
589
|
+
end
|
|
590
|
+
|
|
591
|
+
it "negates the gt selection" do
|
|
592
|
+
expect(selection.selector).to eq(
|
|
593
|
+
{ "age" => { "$not" => { "$gt" => 50 }}}
|
|
594
|
+
)
|
|
595
|
+
end
|
|
596
|
+
|
|
597
|
+
it "returns a coned query" do
|
|
598
|
+
expect(selection).to_not eq(query)
|
|
599
|
+
end
|
|
600
|
+
|
|
601
|
+
it "removes the negation on the clone" do
|
|
602
|
+
expect(selection).to_not be_negating
|
|
603
|
+
end
|
|
604
|
+
end
|
|
605
|
+
|
|
606
|
+
context "when the following criteria is a where" do
|
|
607
|
+
|
|
608
|
+
let(:selection) do
|
|
609
|
+
query.not.where(field: 1, :other.in => [ 1, 2 ])
|
|
610
|
+
end
|
|
611
|
+
|
|
612
|
+
it "negates the selection with an operator" do
|
|
613
|
+
expect(selection.selector).to eq(
|
|
614
|
+
{ "field" => { "$ne" => 1 }, "other" => { "$not" => { "$in" => [ 1, 2 ] }}}
|
|
615
|
+
)
|
|
616
|
+
end
|
|
617
|
+
|
|
618
|
+
it "returns a cloned query" do
|
|
619
|
+
expect(selection).to_not equal(query)
|
|
620
|
+
end
|
|
621
|
+
|
|
622
|
+
it "removes the negation on the clone" do
|
|
623
|
+
expect(selection).to_not be_negating
|
|
624
|
+
end
|
|
625
|
+
end
|
|
626
|
+
|
|
627
|
+
context "when the following criteria is a where with a regexp" do
|
|
628
|
+
|
|
629
|
+
let(:selection) do
|
|
630
|
+
query.not.where(field: 1, other: /test/)
|
|
631
|
+
end
|
|
632
|
+
|
|
633
|
+
it "negates the selection with an operator" do
|
|
634
|
+
expect(selection.selector).to eq(
|
|
635
|
+
{ "field" => { "$ne" => 1 }, "other" => { "$not" => /test/ } }
|
|
636
|
+
)
|
|
637
|
+
end
|
|
638
|
+
|
|
639
|
+
it "returns a cloned query" do
|
|
640
|
+
expect(selection).to_not equal(query)
|
|
641
|
+
end
|
|
642
|
+
|
|
643
|
+
it "removes the negation on the clone" do
|
|
644
|
+
expect(selection).to_not be_negating
|
|
645
|
+
end
|
|
646
|
+
|
|
647
|
+
end
|
|
648
|
+
end
|
|
649
|
+
|
|
650
|
+
context "when provided nil" do
|
|
651
|
+
|
|
652
|
+
let(:selection) do
|
|
653
|
+
query.not(nil)
|
|
654
|
+
end
|
|
655
|
+
|
|
656
|
+
it "does not add any criterion" do
|
|
657
|
+
expect(selection.selector).to eq({})
|
|
658
|
+
end
|
|
659
|
+
|
|
660
|
+
it "returns the query" do
|
|
661
|
+
expect(selection).to eq(query)
|
|
662
|
+
end
|
|
663
|
+
|
|
664
|
+
it "returns a cloned query" do
|
|
665
|
+
expect(selection).to_not equal(query)
|
|
666
|
+
end
|
|
667
|
+
end
|
|
668
|
+
|
|
669
|
+
context "when provided a single criterion" do
|
|
670
|
+
|
|
671
|
+
let(:selection) do
|
|
672
|
+
query.not(field: /test/)
|
|
673
|
+
end
|
|
674
|
+
|
|
675
|
+
it "adds the $not selector" do
|
|
676
|
+
expect(selection.selector).to eq({
|
|
677
|
+
"field" => { "$not" => /test/ }
|
|
678
|
+
})
|
|
679
|
+
end
|
|
680
|
+
|
|
681
|
+
it "returns a cloned query" do
|
|
682
|
+
expect(selection).to_not equal(query)
|
|
683
|
+
end
|
|
684
|
+
end
|
|
685
|
+
|
|
686
|
+
context "when provided multiple criterion" do
|
|
687
|
+
|
|
688
|
+
context "when the criterion are for different fields" do
|
|
689
|
+
|
|
690
|
+
let(:selection) do
|
|
691
|
+
query.not(first: /1/, second: /2/)
|
|
692
|
+
end
|
|
693
|
+
|
|
694
|
+
it "adds the $not selectors" do
|
|
695
|
+
expect(selection.selector).to eq({
|
|
696
|
+
"first" => { "$not" => /1/ },
|
|
697
|
+
"second" => { "$not" => /2/ }
|
|
698
|
+
})
|
|
699
|
+
end
|
|
700
|
+
|
|
701
|
+
it "returns a cloned query" do
|
|
702
|
+
expect(selection).to_not equal(query)
|
|
703
|
+
end
|
|
704
|
+
end
|
|
705
|
+
end
|
|
706
|
+
|
|
707
|
+
context "when chaining the criterion" do
|
|
708
|
+
|
|
709
|
+
context "when the criterion are for different fields" do
|
|
710
|
+
|
|
711
|
+
let(:selection) do
|
|
712
|
+
query.not(first: /1/).not(second: /2/)
|
|
713
|
+
end
|
|
714
|
+
|
|
715
|
+
it "adds the $not selectors" do
|
|
716
|
+
expect(selection.selector).to eq({
|
|
717
|
+
"first" => { "$not" => /1/ },
|
|
718
|
+
"second" => { "$not" => /2/ }
|
|
719
|
+
})
|
|
720
|
+
end
|
|
721
|
+
|
|
722
|
+
it "returns a cloned query" do
|
|
723
|
+
expect(selection).to_not equal(query)
|
|
724
|
+
end
|
|
725
|
+
end
|
|
726
|
+
|
|
727
|
+
context "when the criterion are on the same field" do
|
|
728
|
+
|
|
729
|
+
let(:selection) do
|
|
730
|
+
query.not(first: /1/).not(first: /2/)
|
|
731
|
+
end
|
|
732
|
+
|
|
733
|
+
it "overwrites the first $not selector" do
|
|
734
|
+
expect(selection.selector).to eq({
|
|
735
|
+
"first" => { "$not" => /2/ }
|
|
736
|
+
})
|
|
737
|
+
end
|
|
738
|
+
|
|
739
|
+
it "returns a cloned query" do
|
|
740
|
+
expect(selection).to_not equal(query)
|
|
741
|
+
end
|
|
742
|
+
end
|
|
743
|
+
|
|
744
|
+
context "when the criterion are a double negative" do
|
|
745
|
+
|
|
746
|
+
let(:selection) do
|
|
747
|
+
query.not.where(:first.not => /1/)
|
|
748
|
+
end
|
|
749
|
+
|
|
750
|
+
it "does not double the $not selector" do
|
|
751
|
+
expect(selection.selector).to eq({
|
|
752
|
+
"first" => { "$not" => /1/ }
|
|
753
|
+
})
|
|
754
|
+
end
|
|
755
|
+
|
|
756
|
+
it "returns a cloned query" do
|
|
757
|
+
expect(selection).to_not equal(query)
|
|
758
|
+
end
|
|
759
|
+
end
|
|
760
|
+
end
|
|
761
|
+
end
|
|
762
|
+
end
|