mongoid 7.0.5 → 7.0.6
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 +0 -0
- data.tar.gz.sig +0 -0
- data/LICENSE +1 -0
- data/README.md +2 -1
- data/lib/mongoid.rb +1 -0
- 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/criteria/queryable/mergeable.rb +5 -4
- data/lib/mongoid/criteria/queryable/selectable.rb +2 -3
- 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/version.rb +2 -1
- data/spec/integration/criteria/time_with_zone_spec.rb +32 -0
- data/spec/integration/matchable_spec.rb +680 -0
- data/spec/lite_spec_helper.rb +4 -1
- data/spec/mongoid/attributes/dynamic_spec.rb +153 -0
- data/spec/mongoid/attributes_spec.rb +19 -7
- data/spec/mongoid/criteria/queryable/selectable_logical_spec.rb +762 -0
- data/spec/mongoid/criteria/queryable/selectable_spec.rb +5 -224
- data/spec/mongoid/document_fields_spec.rb +88 -0
- data/spec/mongoid/matchable/default_spec.rb +9 -2
- data/spec/mongoid/validatable/uniqueness_spec.rb +33 -6
- data/spec/support/expectations.rb +17 -3
- metadata +457 -442
- metadata.gz.sig +0 -0
data/spec/lite_spec_helper.rb
CHANGED
@@ -4,7 +4,6 @@ $LOAD_PATH.unshift(File.dirname(__FILE__))
|
|
4
4
|
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), "..", "lib"))
|
5
5
|
|
6
6
|
require "mongoid"
|
7
|
-
require "rspec"
|
8
7
|
|
9
8
|
# MRI 2.5 and JRuby 9.2 change visibility of Object#pp when 'pp' is required,
|
10
9
|
# which happens when RSpec reports anything. This creates an issue for tests
|
@@ -36,6 +35,10 @@ else
|
|
36
35
|
end
|
37
36
|
|
38
37
|
RSpec.configure do |config|
|
38
|
+
config.expect_with(:rspec) do |c|
|
39
|
+
c.syntax = [:should, :expect]
|
40
|
+
end
|
41
|
+
|
39
42
|
if SpecConfig.instance.ci?
|
40
43
|
config.add_formatter(RSpec::Core::Formatters::JsonFormatter, File.join(File.dirname(__FILE__), '../tmp/rspec.json'))
|
41
44
|
end
|
@@ -0,0 +1,153 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# encoding: utf-8
|
3
|
+
|
4
|
+
require "spec_helper"
|
5
|
+
|
6
|
+
describe Mongoid::Attributes::Dynamic do
|
7
|
+
shared_examples_for 'dynamic field' do
|
8
|
+
let(:raw_attributes) do
|
9
|
+
{attr_name => 'foo bar'}
|
10
|
+
end
|
11
|
+
|
12
|
+
context 'when reading attributes' do
|
13
|
+
context 'an unsaved model' do
|
14
|
+
it 'can be read' do
|
15
|
+
bar = Bar.new(raw_attributes)
|
16
|
+
expect(bar.send(attr_name)).to eq('foo bar')
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
context 'saved model' do
|
21
|
+
it 'can be read' do
|
22
|
+
bar = Bar.new(raw_attributes)
|
23
|
+
bar.save!
|
24
|
+
|
25
|
+
bar = Bar.find(bar.id)
|
26
|
+
expect(bar.send(attr_name)).to eq('foo bar')
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
context 'when attribute is not set' do
|
31
|
+
it 'cannot be read' do
|
32
|
+
bar = Bar.new
|
33
|
+
expect do
|
34
|
+
bar.send(attr_name)
|
35
|
+
end.to raise_error(NoMethodError)
|
36
|
+
end
|
37
|
+
|
38
|
+
context 'reading via read_attribute' do
|
39
|
+
it 'returns nil' do
|
40
|
+
bar = Bar.new
|
41
|
+
expect(bar.read_attribute(:foo)).to be nil
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
context 'reading via []' do
|
46
|
+
it 'returns nil' do
|
47
|
+
bar = Bar.new
|
48
|
+
expect(bar[:foo]).to be nil
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
context 'when writing attributes via constructor' do
|
55
|
+
it 'can be written' do
|
56
|
+
bar = Bar.new(raw_attributes)
|
57
|
+
bar.save!
|
58
|
+
|
59
|
+
bar = Bar.find(bar.id)
|
60
|
+
expect(bar.send(attr_name)).to eq('foo bar')
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
context 'when writing attributes via attributes=' do
|
65
|
+
it 'can be written' do
|
66
|
+
bar = Bar.new
|
67
|
+
bar.attributes = raw_attributes
|
68
|
+
bar.save!
|
69
|
+
|
70
|
+
bar = Bar.find(bar.id)
|
71
|
+
expect(bar.send(attr_name)).to eq('foo bar')
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
context 'when writing attributes via write_attribute' do
|
76
|
+
it 'can be written' do
|
77
|
+
bar = Bar.new
|
78
|
+
bar.write_attribute(attr_name, 'foo bar')
|
79
|
+
bar.save!
|
80
|
+
|
81
|
+
bar = Bar.find(bar.id)
|
82
|
+
expect(bar.send(attr_name)).to eq('foo bar')
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
context 'when writing attributes via []=' do
|
87
|
+
context 'string key' do
|
88
|
+
it 'can be written' do
|
89
|
+
bar = Bar.new
|
90
|
+
bar[attr_name.to_s] = 'foo bar'
|
91
|
+
bar.save!
|
92
|
+
|
93
|
+
bar = Bar.find(bar.id)
|
94
|
+
expect(bar.send(attr_name)).to eq('foo bar')
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
context 'symbol key' do
|
99
|
+
it 'can be written' do
|
100
|
+
bar = Bar.new
|
101
|
+
bar[attr_name.to_sym] = 'foo bar'
|
102
|
+
bar.save!
|
103
|
+
|
104
|
+
bar = Bar.find(bar.id)
|
105
|
+
expect(bar.send(attr_name)).to eq('foo bar')
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
context 'when writing attributes via #{attribute}=' do
|
111
|
+
context 'when attribute is not already set' do
|
112
|
+
let(:bar) { Bar.new }
|
113
|
+
|
114
|
+
it 'cannot be written' do
|
115
|
+
expect do
|
116
|
+
bar.send("#{attr_name}=", 'foo bar')
|
117
|
+
bar.save!
|
118
|
+
end.to raise_error(NoMethodError)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
context 'when attribute is already set' do
|
123
|
+
let(:bar) { Bar.new(attr_name => 'foo bar') }
|
124
|
+
|
125
|
+
it 'can be written' do
|
126
|
+
bar.send("#{attr_name}=", 'new foo bar')
|
127
|
+
bar.save!
|
128
|
+
|
129
|
+
_bar = Bar.find(bar.id)
|
130
|
+
expect(_bar.send(attr_name)).to eq('new foo bar')
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
context 'when attribute name is alphanumeric' do
|
137
|
+
let(:attr_name) { 'foo' }
|
138
|
+
|
139
|
+
it_behaves_like 'dynamic field'
|
140
|
+
end
|
141
|
+
|
142
|
+
context 'when attribute name contains spaces' do
|
143
|
+
let(:attr_name) { 'hello world' }
|
144
|
+
|
145
|
+
it_behaves_like 'dynamic field'
|
146
|
+
end
|
147
|
+
|
148
|
+
context 'when attribute name contains special characters' do
|
149
|
+
let(:attr_name) { 'hello%world' }
|
150
|
+
|
151
|
+
it_behaves_like 'dynamic field'
|
152
|
+
end
|
153
|
+
end
|
@@ -1346,10 +1346,16 @@ describe Mongoid::Attributes do
|
|
1346
1346
|
context "when attribute is a Hash" do
|
1347
1347
|
let(:person) { Person.new map: { somekey: "somevalue" } }
|
1348
1348
|
|
1349
|
-
it "raises an error when
|
1350
|
-
expect
|
1349
|
+
it "raises an error when trying to set a value of invalid type - array" do
|
1350
|
+
expect do
|
1351
1351
|
person.map = []
|
1352
|
-
|
1352
|
+
end.to raise_error(Mongoid::Errors::InvalidValue, /Value of type Array cannot be written to a field of type Hash/)
|
1353
|
+
end
|
1354
|
+
|
1355
|
+
it "raises an error when trying to set a value of invalid type - boolean" do
|
1356
|
+
expect do
|
1357
|
+
person.map = false
|
1358
|
+
end.to raise_error(Mongoid::Errors::InvalidValue, /Value of type FalseClass cannot be written to a field of type Hash/)
|
1353
1359
|
end
|
1354
1360
|
|
1355
1361
|
it "can set a Hash value" do
|
@@ -1364,10 +1370,16 @@ describe Mongoid::Attributes do
|
|
1364
1370
|
expect(person.aliases).to eq([ :alias_1 ])
|
1365
1371
|
end
|
1366
1372
|
|
1367
|
-
it "raises an error when
|
1368
|
-
expect
|
1373
|
+
it "raises an error when trying to set a value of invalid type - hash" do
|
1374
|
+
expect do
|
1369
1375
|
person.aliases = {}
|
1370
|
-
|
1376
|
+
end.to raise_error(Mongoid::Errors::InvalidValue, /Value of type Hash cannot be written to a field of type Array/)
|
1377
|
+
end
|
1378
|
+
|
1379
|
+
it "raises an error when trying to set a value of invalid type - boolean" do
|
1380
|
+
expect do
|
1381
|
+
person.aliases = false
|
1382
|
+
end.to raise_error(Mongoid::Errors::InvalidValue, /Value of type FalseClass cannot be written to a field of type Array/)
|
1371
1383
|
end
|
1372
1384
|
end
|
1373
1385
|
|
@@ -1422,7 +1434,7 @@ describe Mongoid::Attributes do
|
|
1422
1434
|
end
|
1423
1435
|
|
1424
1436
|
describe "#typed_attributes" do
|
1425
|
-
|
1437
|
+
|
1426
1438
|
let(:date_time) do
|
1427
1439
|
DateTime.current
|
1428
1440
|
end
|
@@ -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
|