mongoid 7.1.1 → 7.1.2
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/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/atomic.rb +13 -3
- data/lib/mongoid/criteria.rb +7 -1
- data/lib/mongoid/criteria/modifiable.rb +2 -1
- 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/mergeable.rb +75 -8
- data/lib/mongoid/criteria/queryable/selectable.rb +28 -8
- data/lib/mongoid/extensions/hash.rb +4 -2
- data/lib/mongoid/extensions/regexp.rb +1 -1
- data/lib/mongoid/fields.rb +2 -1
- data/lib/mongoid/matchable/regexp.rb +2 -2
- data/lib/mongoid/persistable/pushable.rb +4 -1
- data/lib/mongoid/persistence_context.rb +6 -6
- data/lib/mongoid/query_cache.rb +2 -1
- data/lib/mongoid/validatable/uniqueness.rb +1 -1
- data/lib/mongoid/version.rb +1 -1
- data/lib/rails/generators/mongoid/model/templates/model.rb.tt +1 -1
- data/spec/integration/app_spec.rb +192 -0
- data/spec/integration/associations/embedded_spec.rb +54 -0
- data/spec/integration/criteria/logical_spec.rb +13 -0
- data/spec/lite_spec_helper.rb +11 -4
- data/spec/mongoid/association/embedded/embeds_many_models.rb +19 -0
- data/spec/mongoid/association/embedded/embeds_many_spec.rb +10 -0
- data/spec/mongoid/association/embedded/embeds_one_spec.rb +0 -2
- 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/clients/options_spec.rb +2 -2
- data/spec/mongoid/clients/sessions_spec.rb +8 -4
- data/spec/mongoid/clients/transactions_spec.rb +20 -8
- data/spec/mongoid/clients_spec.rb +2 -2
- data/spec/mongoid/contextual/atomic_spec.rb +22 -11
- data/spec/mongoid/contextual/map_reduce_spec.rb +20 -5
- data/spec/mongoid/contextual/mongo_spec.rb +76 -53
- 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/mergeable_spec.rb +45 -12
- data/spec/mongoid/criteria/queryable/selectable_logical_spec.rb +480 -198
- data/spec/mongoid/criteria_spec.rb +4 -2
- data/spec/mongoid/document_persistence_context_spec.rb +33 -0
- data/spec/mongoid/indexable_spec.rb +6 -4
- data/spec/mongoid/matchable/default_spec.rb +1 -1
- data/spec/mongoid/matchable/regexp_spec.rb +2 -2
- data/spec/mongoid/matchable_spec.rb +2 -2
- 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/shardable_models.rb +1 -1
- data/spec/mongoid/shardable_spec.rb +2 -2
- data/spec/mongoid/tasks/database_rake_spec.rb +13 -13
- data/spec/mongoid/tasks/database_spec.rb +1 -1
- data/spec/spec_helper.rb +0 -31
- data/spec/support/child_process_helper.rb +76 -0
- data/spec/support/cluster_config.rb +3 -3
- data/spec/support/constraints.rb +26 -10
- data/spec/support/spec_config.rb +12 -4
- metadata +8 -2
- metadata.gz.sig +0 -0
@@ -11,7 +11,7 @@ describe Mongoid::Criteria::Queryable::Extensions::Regexp do
|
|
11
11
|
context "when provided a regexp" do
|
12
12
|
|
13
13
|
let(:regexp) do
|
14
|
-
|
14
|
+
/\A[123]/
|
15
15
|
end
|
16
16
|
|
17
17
|
let(:evolved) do
|
@@ -26,7 +26,7 @@ describe Mongoid::Criteria::Queryable::Extensions::Regexp do
|
|
26
26
|
context "when provided a string" do
|
27
27
|
|
28
28
|
let(:regexp) do
|
29
|
-
"
|
29
|
+
"\\A[123]"
|
30
30
|
end
|
31
31
|
|
32
32
|
let(:evolved) do
|
@@ -34,7 +34,7 @@ describe Mongoid::Criteria::Queryable::Extensions::Regexp do
|
|
34
34
|
end
|
35
35
|
|
36
36
|
it "returns the converted regexp" do
|
37
|
-
expect(evolved).to eq(
|
37
|
+
expect(evolved).to eq(/\A[123]/)
|
38
38
|
end
|
39
39
|
end
|
40
40
|
|
@@ -43,7 +43,7 @@ describe Mongoid::Criteria::Queryable::Extensions::Regexp do
|
|
43
43
|
context "when the elements are regexps" do
|
44
44
|
|
45
45
|
let(:regexp) do
|
46
|
-
|
46
|
+
/\A[123]/
|
47
47
|
end
|
48
48
|
|
49
49
|
let(:array) do
|
@@ -66,7 +66,7 @@ describe Mongoid::Criteria::Queryable::Extensions::Regexp do
|
|
66
66
|
context "when the elements are strings" do
|
67
67
|
|
68
68
|
let(:regexp) do
|
69
|
-
"
|
69
|
+
"\\A[123]"
|
70
70
|
end
|
71
71
|
|
72
72
|
let(:evolved) do
|
@@ -74,7 +74,7 @@ describe Mongoid::Criteria::Queryable::Extensions::Regexp do
|
|
74
74
|
end
|
75
75
|
|
76
76
|
it "returns the regexps" do
|
77
|
-
expect(evolved).to eq([
|
77
|
+
expect(evolved).to eq([ /\A[123]/ ])
|
78
78
|
end
|
79
79
|
end
|
80
80
|
end
|
@@ -83,7 +83,7 @@ describe Mongoid::Criteria::Queryable::Extensions::Regexp do
|
|
83
83
|
describe "#regexp?" do
|
84
84
|
|
85
85
|
let(:regexp) do
|
86
|
-
|
86
|
+
/\A[123]/
|
87
87
|
end
|
88
88
|
|
89
89
|
it "returns true" do
|
@@ -5,11 +5,11 @@ require "spec_helper"
|
|
5
5
|
|
6
6
|
describe Mongoid::Criteria::Queryable::Mergeable do
|
7
7
|
|
8
|
-
|
8
|
+
let(:query) do
|
9
|
+
Mongoid::Query.new
|
10
|
+
end
|
9
11
|
|
10
|
-
|
11
|
-
Mongoid::Query.new
|
12
|
-
end
|
12
|
+
describe "#intersect" do
|
13
13
|
|
14
14
|
before do
|
15
15
|
query.intersect
|
@@ -22,10 +22,6 @@ describe Mongoid::Criteria::Queryable::Mergeable do
|
|
22
22
|
|
23
23
|
describe "#override" do
|
24
24
|
|
25
|
-
let(:query) do
|
26
|
-
Mongoid::Query.new
|
27
|
-
end
|
28
|
-
|
29
25
|
before do
|
30
26
|
query.override
|
31
27
|
end
|
@@ -37,10 +33,6 @@ describe Mongoid::Criteria::Queryable::Mergeable do
|
|
37
33
|
|
38
34
|
describe "#union" do
|
39
35
|
|
40
|
-
let(:query) do
|
41
|
-
Mongoid::Query.new
|
42
|
-
end
|
43
|
-
|
44
36
|
before do
|
45
37
|
query.union
|
46
38
|
end
|
@@ -49,4 +41,45 @@ describe Mongoid::Criteria::Queryable::Mergeable do
|
|
49
41
|
expect(query.strategy).to eq(:__union__)
|
50
42
|
end
|
51
43
|
end
|
44
|
+
|
45
|
+
describe '#_mongoid_expand_keys' do
|
46
|
+
it 'expands simple keys' do
|
47
|
+
query.send(:_mongoid_expand_keys, {a: 1}).should == {a: 1}
|
48
|
+
end
|
49
|
+
|
50
|
+
let(:gt) do
|
51
|
+
Mongoid::Criteria::Queryable::Key.new("age", :__override__, "$gt")
|
52
|
+
end
|
53
|
+
|
54
|
+
let(:gtp) do
|
55
|
+
Mongoid::Criteria::Queryable::Key.new("age", :__override__, "$gt")
|
56
|
+
end
|
57
|
+
|
58
|
+
let(:lt) do
|
59
|
+
Mongoid::Criteria::Queryable::Key.new("age", :__override__, "$lt")
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'expands Key instances' do
|
63
|
+
query.send(:_mongoid_expand_keys, {gt => 42}).should == {'age' => {'$gt' => 42}}
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'expands multiple Key instances on the same field' do
|
67
|
+
query.send(:_mongoid_expand_keys, {gt => 42, lt => 50}).should == {
|
68
|
+
'age' => {'$gt' => 42, '$lt' => 50}}
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'expands simple and Key instances on the same field' do
|
72
|
+
query.send(:_mongoid_expand_keys, {'age' => 42, lt => 50}).should == {
|
73
|
+
'age' => {'$eq' => 42, '$lt' => 50}}
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'expands Key and simple instances on the same field' do
|
77
|
+
query.send(:_mongoid_expand_keys, {gt => 42, 'age' => 50}).should == {
|
78
|
+
'age' => {'$gt' => 42, '$eq' => 50}}
|
79
|
+
end
|
80
|
+
|
81
|
+
it 'Ruby does not allow same symbol operator with different values' do
|
82
|
+
{gt => 42, gtp => 50}.should == {gtp => 50}
|
83
|
+
end
|
84
|
+
end
|
52
85
|
end
|
@@ -85,7 +85,7 @@ describe Mongoid::Criteria::Queryable::Selectable do
|
|
85
85
|
|
86
86
|
it "adds the conditions to top level" do
|
87
87
|
expect(selection.selector).to eq({
|
88
|
-
"field" => {'$gt' => 3
|
88
|
+
"field" => {'$gt' => 3},
|
89
89
|
})
|
90
90
|
end
|
91
91
|
|
@@ -113,6 +113,54 @@ describe Mongoid::Criteria::Queryable::Selectable do
|
|
113
113
|
|
114
114
|
it_behaves_like 'adds the conditions to top level'
|
115
115
|
end
|
116
|
+
|
117
|
+
context 'when the criterion is a time' do
|
118
|
+
let(:selection) do
|
119
|
+
query.send(tested_method, :field.gte => Time.new(2020, 1, 1))
|
120
|
+
end
|
121
|
+
|
122
|
+
it 'adds the conditions' do
|
123
|
+
expect(selection.selector).to eq({
|
124
|
+
"field" => {'$gte' => Time.new(2020, 1, 1)},
|
125
|
+
})
|
126
|
+
end
|
127
|
+
|
128
|
+
it 'keeps argument type' do
|
129
|
+
selection.selector['field']['$gte'].should be_a(Time)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
context 'when the criterion is a datetime' do
|
134
|
+
let(:selection) do
|
135
|
+
query.send(tested_method, :field.gte => DateTime.new(2020, 1, 1))
|
136
|
+
end
|
137
|
+
|
138
|
+
it 'adds the conditions' do
|
139
|
+
expect(selection.selector).to eq({
|
140
|
+
"field" => {'$gte' => Time.utc(2020, 1, 1)},
|
141
|
+
})
|
142
|
+
end
|
143
|
+
|
144
|
+
it 'converts argument to a time' do
|
145
|
+
selection.selector['field']['$gte'].should be_a(Time)
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
context 'when the criterion is a date' do
|
150
|
+
let(:selection) do
|
151
|
+
query.send(tested_method, :field.gte => Date.new(2020, 1, 1))
|
152
|
+
end
|
153
|
+
|
154
|
+
it 'adds the conditions' do
|
155
|
+
expect(selection.selector).to eq({
|
156
|
+
"field" => {'$gte' => Time.utc(2020, 1, 1)},
|
157
|
+
})
|
158
|
+
end
|
159
|
+
|
160
|
+
it 'converts argument to a time' do
|
161
|
+
selection.selector['field']['$gte'].should be_a(Time)
|
162
|
+
end
|
163
|
+
end
|
116
164
|
end
|
117
165
|
|
118
166
|
context "when provided a nested criterion" do
|
@@ -283,25 +331,58 @@ describe Mongoid::Criteria::Queryable::Selectable do
|
|
283
331
|
|
284
332
|
context "when provided multiple criteria" do
|
285
333
|
|
286
|
-
context "when the
|
334
|
+
context "when the criterion is already included" do
|
287
335
|
|
288
|
-
|
289
|
-
|
336
|
+
context 'simple criterion' do
|
337
|
+
let(:selection) do
|
338
|
+
query.and({ first: [ 1, 2 ] }).and({ first: [ 1, 2 ] })
|
339
|
+
end
|
340
|
+
|
341
|
+
it "adds all conditions" do
|
342
|
+
expect(selection.selector).to eq({
|
343
|
+
'first' => [1, 2],
|
344
|
+
"$and" => [
|
345
|
+
{ "first" => [ 1, 2 ] }
|
346
|
+
]
|
347
|
+
})
|
348
|
+
end
|
349
|
+
|
350
|
+
it_behaves_like 'returns a cloned query'
|
290
351
|
end
|
291
352
|
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
353
|
+
context 'Key criterion' do
|
354
|
+
let(:selection) do
|
355
|
+
query.and({ first: [ 1, 2 ] }).and(:first.gt => 3)
|
356
|
+
end
|
357
|
+
|
358
|
+
it "adds all conditions" do
|
359
|
+
expect(selection.selector).to eq({
|
360
|
+
'first' => [1, 2],
|
361
|
+
"$and" => [
|
362
|
+
{ "first" => {'$gt' => 3} }
|
363
|
+
]
|
364
|
+
})
|
365
|
+
end
|
366
|
+
|
367
|
+
it_behaves_like 'returns a cloned query'
|
299
368
|
end
|
300
369
|
|
301
|
-
|
370
|
+
context 'Key criterion when existing criterion is an operator' do
|
371
|
+
let(:selection) do
|
372
|
+
query.and(:first.lt => 5).and(:first.gt => 3)
|
373
|
+
end
|
374
|
+
|
375
|
+
it "adds all conditions" do
|
376
|
+
expect(selection.selector).to eq({
|
377
|
+
'first' => {'$lt' => 5, '$gt' => 3},
|
378
|
+
})
|
379
|
+
end
|
380
|
+
|
381
|
+
it_behaves_like 'returns a cloned query'
|
382
|
+
end
|
302
383
|
end
|
303
384
|
|
304
|
-
context "when the new
|
385
|
+
context "when the new criteria are for different fields" do
|
305
386
|
|
306
387
|
let(:selection) do
|
307
388
|
query.and({ first: [ 1, 2 ] }, { second: [ 3, 4 ] })
|
@@ -317,22 +398,137 @@ describe Mongoid::Criteria::Queryable::Selectable do
|
|
317
398
|
it_behaves_like 'returns a cloned query'
|
318
399
|
end
|
319
400
|
|
320
|
-
context "when the new
|
401
|
+
context "when the new criteria are for the same field" do
|
321
402
|
|
322
|
-
|
323
|
-
|
403
|
+
context 'when criteria are simple' do
|
404
|
+
let(:selection) do
|
405
|
+
query.and({ first: [ 1, 2 ] }, { first: [ 3, 4 ] })
|
406
|
+
end
|
407
|
+
|
408
|
+
it "combines via $and operator" do
|
409
|
+
expect(selection.selector).to eq({
|
410
|
+
"first" => [ 1, 2 ],
|
411
|
+
"$and" => [
|
412
|
+
{ "first" => [ 3, 4 ] }
|
413
|
+
]
|
414
|
+
})
|
415
|
+
end
|
416
|
+
|
417
|
+
it_behaves_like 'returns a cloned query'
|
324
418
|
end
|
325
419
|
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
"
|
330
|
-
{
|
331
|
-
|
332
|
-
|
420
|
+
context 'when criteria are handled via Key' do
|
421
|
+
shared_examples_for 'adds the conditions to top level' do
|
422
|
+
|
423
|
+
it "adds the conditions to top level" do
|
424
|
+
expect(selection.selector).to eq({
|
425
|
+
"field" => {'$gt' => 3, '$lt' => 5},
|
426
|
+
})
|
427
|
+
end
|
428
|
+
|
429
|
+
it_behaves_like 'returns a cloned query'
|
430
|
+
end
|
431
|
+
|
432
|
+
context 'criteria are provided in the same hash' do
|
433
|
+
let(:selection) do
|
434
|
+
query.send(tested_method, :field.gt => 3, :field.lt => 5)
|
435
|
+
end
|
436
|
+
|
437
|
+
it_behaves_like 'adds the conditions to top level'
|
438
|
+
end
|
439
|
+
|
440
|
+
context 'criteria are provided in separate hashes' do
|
441
|
+
let(:selection) do
|
442
|
+
query.send(tested_method, {:field.gt => 3}, {:field.lt => 5})
|
443
|
+
end
|
444
|
+
|
445
|
+
it_behaves_like 'adds the conditions to top level'
|
446
|
+
end
|
447
|
+
|
448
|
+
context 'when the criterion is wrapped in an array' do
|
449
|
+
let(:selection) do
|
450
|
+
query.send(tested_method, [:field.gt => 3], [:field.lt => 5])
|
451
|
+
end
|
452
|
+
|
453
|
+
it_behaves_like 'adds the conditions to top level'
|
454
|
+
end
|
333
455
|
end
|
334
456
|
|
335
|
-
|
457
|
+
context 'when criteria are simple and handled via Key' do
|
458
|
+
shared_examples_for 'combines conditions with $and' do
|
459
|
+
|
460
|
+
it "combines conditions with $and" do
|
461
|
+
expect(selection.selector).to eq({
|
462
|
+
"field" => 3,
|
463
|
+
'$and' => ['field' => {'$lt' => 5}],
|
464
|
+
})
|
465
|
+
end
|
466
|
+
|
467
|
+
it_behaves_like 'returns a cloned query'
|
468
|
+
end
|
469
|
+
|
470
|
+
context 'criteria are provided in the same hash' do
|
471
|
+
let(:selection) do
|
472
|
+
query.send(tested_method, :field => 3, :field.lt => 5)
|
473
|
+
end
|
474
|
+
|
475
|
+
it_behaves_like 'combines conditions with $and'
|
476
|
+
end
|
477
|
+
|
478
|
+
context 'criteria are provided in separate hashes' do
|
479
|
+
let(:selection) do
|
480
|
+
query.send(tested_method, {:field => 3}, {:field.lt => 5})
|
481
|
+
end
|
482
|
+
|
483
|
+
it_behaves_like 'combines conditions with $and'
|
484
|
+
end
|
485
|
+
|
486
|
+
context 'when the criterion is wrapped in an array' do
|
487
|
+
let(:selection) do
|
488
|
+
query.send(tested_method, [:field => 3], [:field.lt => 5])
|
489
|
+
end
|
490
|
+
|
491
|
+
it_behaves_like 'combines conditions with $and'
|
492
|
+
end
|
493
|
+
end
|
494
|
+
|
495
|
+
context 'when criteria are handled via Key and simple' do
|
496
|
+
shared_examples_for 'combines conditions with $and' do
|
497
|
+
|
498
|
+
it "combines conditions with $and" do
|
499
|
+
expect(selection.selector).to eq({
|
500
|
+
"field" => {'$gt' => 3},
|
501
|
+
'$and' => ['field' => 5],
|
502
|
+
})
|
503
|
+
end
|
504
|
+
|
505
|
+
it_behaves_like 'returns a cloned query'
|
506
|
+
end
|
507
|
+
|
508
|
+
context 'criteria are provided in the same hash' do
|
509
|
+
let(:selection) do
|
510
|
+
query.send(tested_method, :field.gt => 3, :field => 5)
|
511
|
+
end
|
512
|
+
|
513
|
+
it_behaves_like 'combines conditions with $and'
|
514
|
+
end
|
515
|
+
|
516
|
+
context 'criteria are provided in separate hashes' do
|
517
|
+
let(:selection) do
|
518
|
+
query.send(tested_method, {:field.gt => 3}, {:field => 5})
|
519
|
+
end
|
520
|
+
|
521
|
+
it_behaves_like 'combines conditions with $and'
|
522
|
+
end
|
523
|
+
|
524
|
+
context 'when the criterion is wrapped in an array' do
|
525
|
+
let(:selection) do
|
526
|
+
query.send(tested_method, [:field.gt => 3], [:field => 5])
|
527
|
+
end
|
528
|
+
|
529
|
+
it_behaves_like 'combines conditions with $and'
|
530
|
+
end
|
531
|
+
end
|
336
532
|
end
|
337
533
|
end
|
338
534
|
|
@@ -509,17 +705,14 @@ describe Mongoid::Criteria::Queryable::Selectable do
|
|
509
705
|
end
|
510
706
|
end
|
511
707
|
|
512
|
-
|
513
|
-
|
514
|
-
let(:tested_method) { :or }
|
515
|
-
let(:expected_operator) { '$or' }
|
708
|
+
shared_examples '$or/$nor' do
|
516
709
|
|
517
710
|
it_behaves_like 'a non-hoisting logical operation'
|
518
711
|
|
519
712
|
context "when provided no arguments" do
|
520
713
|
|
521
714
|
let(:selection) do
|
522
|
-
query.
|
715
|
+
query.send(tested_method)
|
523
716
|
end
|
524
717
|
|
525
718
|
it_behaves_like 'returns a cloned query'
|
@@ -536,7 +729,7 @@ describe Mongoid::Criteria::Queryable::Selectable do
|
|
536
729
|
context "when provided nil" do
|
537
730
|
|
538
731
|
let(:selection) do
|
539
|
-
query.
|
732
|
+
query.send(tested_method, nil)
|
540
733
|
end
|
541
734
|
|
542
735
|
it_behaves_like 'returns a cloned query'
|
@@ -553,42 +746,42 @@ describe Mongoid::Criteria::Queryable::Selectable do
|
|
553
746
|
context "when provided a single criterion" do
|
554
747
|
|
555
748
|
let(:selection) do
|
556
|
-
query.
|
749
|
+
query.send(tested_method, field: [ 1, 2 ])
|
557
750
|
end
|
558
751
|
|
559
752
|
it_behaves_like 'returns a cloned query'
|
560
753
|
|
561
|
-
it "adds the $or selector" do
|
754
|
+
it "adds the $or/$nor selector" do
|
562
755
|
expect(selection.selector).to eq({
|
563
|
-
|
756
|
+
expected_operator => [{ "field" => [ 1, 2 ] }]
|
564
757
|
})
|
565
758
|
end
|
566
759
|
|
567
760
|
context 'when the criterion is wrapped in array' do
|
568
761
|
|
569
762
|
let(:selection) do
|
570
|
-
query.
|
763
|
+
query.send(tested_method, [{ field: [ 1, 2 ] }])
|
571
764
|
end
|
572
765
|
|
573
766
|
it_behaves_like 'returns a cloned query'
|
574
767
|
|
575
|
-
it "adds the $or selector" do
|
768
|
+
it "adds the $or/$nor selector" do
|
576
769
|
expect(selection.selector).to eq({
|
577
|
-
|
770
|
+
expected_operator => [{ "field" => [ 1, 2 ] }]
|
578
771
|
})
|
579
772
|
end
|
580
773
|
|
581
774
|
context 'when the array has nil as one of the elements' do
|
582
775
|
|
583
776
|
let(:selection) do
|
584
|
-
query.
|
777
|
+
query.send(tested_method, [{ field: [ 1, 2 ] }, nil])
|
585
778
|
end
|
586
779
|
|
587
780
|
it_behaves_like 'returns a cloned query'
|
588
781
|
|
589
|
-
it "adds the $or selector ignoring the nil element" do
|
782
|
+
it "adds the $or/$nor selector ignoring the nil element" do
|
590
783
|
expect(selection.selector).to eq({
|
591
|
-
|
784
|
+
expected_operator => [{ "field" => [ 1, 2 ] }]
|
592
785
|
})
|
593
786
|
end
|
594
787
|
end
|
@@ -597,27 +790,27 @@ describe Mongoid::Criteria::Queryable::Selectable do
|
|
597
790
|
context 'when query already has a condition on another field' do
|
598
791
|
|
599
792
|
let(:selection) do
|
600
|
-
query.where(foo: 'bar').
|
793
|
+
query.where(foo: 'bar').send(tested_method, field: [ 1, 2 ])
|
601
794
|
end
|
602
795
|
|
603
|
-
it 'moves original conditions under $or' do
|
796
|
+
it 'moves original conditions under $or/$nor' do
|
604
797
|
expect(selection.selector).to eq({
|
605
|
-
|
798
|
+
expected_operator => [{'foo' => 'bar'}, { "field" => [ 1, 2 ] }]
|
606
799
|
})
|
607
800
|
end
|
608
801
|
end
|
609
802
|
|
610
|
-
context 'when query already has an $or condition and another condition' do
|
803
|
+
context 'when query already has an $or/$nor condition and another condition' do
|
611
804
|
|
612
805
|
let(:selection) do
|
613
|
-
query.
|
806
|
+
query.send(tested_method, field: [ 1, 2 ]).where(foo: 'bar').send(tested_method, test: 1)
|
614
807
|
end
|
615
808
|
|
616
809
|
it 'unions existing conditions' do
|
617
810
|
expect(selection.selector).to eq(
|
618
|
-
|
811
|
+
expected_operator => [
|
619
812
|
{
|
620
|
-
|
813
|
+
expected_operator => [{ "field" => [ 1, 2 ] }],
|
621
814
|
'foo' => 'bar',
|
622
815
|
},
|
623
816
|
{'test' => 1},
|
@@ -632,14 +825,14 @@ describe Mongoid::Criteria::Queryable::Selectable do
|
|
632
825
|
context "when the criteria are for different fields" do
|
633
826
|
|
634
827
|
let(:selection) do
|
635
|
-
query.
|
828
|
+
query.send(tested_method, { first: [ 1, 2 ] }, { second: [ 3, 4 ] })
|
636
829
|
end
|
637
830
|
|
638
831
|
it_behaves_like 'returns a cloned query'
|
639
832
|
|
640
|
-
it "adds the $or selector" do
|
833
|
+
it "adds the $or/$nor selector" do
|
641
834
|
expect(selection.selector).to eq({
|
642
|
-
|
835
|
+
expected_operator => [
|
643
836
|
{ "first" => [ 1, 2 ] },
|
644
837
|
{ "second" => [ 3, 4 ] }
|
645
838
|
]
|
@@ -650,12 +843,12 @@ describe Mongoid::Criteria::Queryable::Selectable do
|
|
650
843
|
context "when the criteria uses a Key instance" do
|
651
844
|
|
652
845
|
let(:selection) do
|
653
|
-
query.
|
846
|
+
query.send(tested_method, { first: [ 1, 2 ] }, { :second.gt => 3 })
|
654
847
|
end
|
655
848
|
|
656
|
-
it "adds the $or selector" do
|
849
|
+
it "adds the $or/$nor selector" do
|
657
850
|
expect(selection.selector).to eq({
|
658
|
-
|
851
|
+
expected_operator => [
|
659
852
|
{ "first" => [ 1, 2 ] },
|
660
853
|
{ "second" => { "$gt" => 3 }}
|
661
854
|
]
|
@@ -663,233 +856,197 @@ describe Mongoid::Criteria::Queryable::Selectable do
|
|
663
856
|
end
|
664
857
|
|
665
858
|
it_behaves_like 'returns a cloned query'
|
666
|
-
end
|
667
859
|
|
668
|
-
|
860
|
+
context 'when the criterion is a time' do
|
861
|
+
let(:selection) do
|
862
|
+
query.send(tested_method, :field.gte => Time.new(2020, 1, 1))
|
863
|
+
end
|
669
864
|
|
670
|
-
|
671
|
-
|
672
|
-
|
865
|
+
it 'adds the conditions' do
|
866
|
+
expect(selection.selector).to eq(expected_operator => [
|
867
|
+
"field" => {'$gte' => Time.new(2020, 1, 1)},
|
868
|
+
])
|
869
|
+
end
|
673
870
|
|
674
|
-
|
675
|
-
|
676
|
-
|
677
|
-
})
|
871
|
+
it 'keeps the type' do
|
872
|
+
selection.selector[expected_operator].first['field']['$gte'].should be_a(Time)
|
873
|
+
end
|
678
874
|
end
|
679
875
|
|
680
|
-
|
681
|
-
|
876
|
+
context 'when the criterion is a datetime' do
|
877
|
+
let(:selection) do
|
878
|
+
query.send(tested_method, :field.gte => DateTime.new(2020, 1, 1))
|
879
|
+
end
|
682
880
|
|
683
|
-
|
881
|
+
it 'adds the conditions' do
|
882
|
+
expect(selection.selector).to eq(expected_operator => [
|
883
|
+
"field" => {'$gte' => Time.utc(2020, 1, 1)},
|
884
|
+
])
|
885
|
+
end
|
684
886
|
|
685
|
-
|
686
|
-
|
887
|
+
it 'converts argument to a time' do
|
888
|
+
selection.selector[expected_operator].first['field']['$gte'].should be_a(Time)
|
889
|
+
end
|
687
890
|
end
|
688
891
|
|
689
|
-
|
892
|
+
context 'when the criterion is a date' do
|
893
|
+
let(:selection) do
|
894
|
+
query.send(tested_method, :field.gte => Date.new(2020, 1, 1))
|
895
|
+
end
|
690
896
|
|
691
|
-
|
692
|
-
|
693
|
-
|
694
|
-
|
695
|
-
|
696
|
-
|
697
|
-
|
897
|
+
it 'adds the conditions' do
|
898
|
+
expect(selection.selector).to eq(expected_operator => [
|
899
|
+
"field" => {'$gte' => Time.utc(2020, 1, 1)},
|
900
|
+
])
|
901
|
+
end
|
902
|
+
|
903
|
+
it 'converts argument to a time' do
|
904
|
+
selection.selector[expected_operator].first['field']['$gte'].should be_a(Time)
|
905
|
+
end
|
698
906
|
end
|
699
907
|
end
|
700
908
|
|
701
|
-
context "when
|
909
|
+
context "when a criterion has an aliased field" do
|
702
910
|
|
703
911
|
let(:selection) do
|
704
|
-
query.
|
912
|
+
query.send(tested_method, { id: 1 })
|
705
913
|
end
|
706
914
|
|
707
|
-
|
708
|
-
|
709
|
-
it "appends both $or expressions" do
|
915
|
+
it "adds the $or/$nor selector and aliases the field" do
|
710
916
|
expect(selection.selector).to eq({
|
711
|
-
"
|
712
|
-
{ "first" => [ 1, 2 ] },
|
713
|
-
{ "first" => [ 3, 4 ] }
|
714
|
-
]
|
917
|
+
expected_operator => [ { "_id" => 1 } ]
|
715
918
|
})
|
716
919
|
end
|
717
|
-
end
|
718
|
-
end
|
719
|
-
|
720
|
-
context "when chaining the criterion" do
|
721
|
-
|
722
|
-
context "when the criterion are for different fields" do
|
723
|
-
|
724
|
-
let(:selection) do
|
725
|
-
query.or(first: [ 1, 2 ]).or(second: [ 3, 4 ])
|
726
|
-
end
|
727
920
|
|
728
921
|
it_behaves_like 'returns a cloned query'
|
729
|
-
|
730
|
-
it "adds the $or selectors" do
|
731
|
-
expect(selection.selector).to eq({
|
732
|
-
"$or" => [
|
733
|
-
{ "first" => [ 1, 2 ] },
|
734
|
-
{ "second" => [ 3, 4 ] }
|
735
|
-
]
|
736
|
-
})
|
737
|
-
end
|
738
922
|
end
|
739
923
|
|
740
|
-
context "when
|
924
|
+
context "when a criterion is wrapped in an array" do
|
741
925
|
|
742
926
|
let(:selection) do
|
743
|
-
query.
|
927
|
+
query.send(tested_method, [{ first: [ 1, 2 ] }, { :second.gt => 3 }])
|
744
928
|
end
|
745
929
|
|
746
930
|
it_behaves_like 'returns a cloned query'
|
747
931
|
|
748
|
-
it "
|
932
|
+
it "adds the $or/$nor selector" do
|
749
933
|
expect(selection.selector).to eq({
|
750
|
-
|
934
|
+
expected_operator => [
|
751
935
|
{ "first" => [ 1, 2 ] },
|
752
|
-
{ "
|
936
|
+
{ "second" => { "$gt" => 3 }}
|
753
937
|
]
|
754
938
|
})
|
755
939
|
end
|
756
940
|
end
|
757
|
-
end
|
758
|
-
end
|
759
941
|
|
760
|
-
|
761
|
-
|
762
|
-
let(:tested_method) { :nor }
|
763
|
-
let(:expected_operator) { '$nor' }
|
764
|
-
|
765
|
-
it_behaves_like 'a non-hoisting logical operation'
|
766
|
-
|
767
|
-
context "when provided no criterion" do
|
768
|
-
|
769
|
-
let(:selection) do
|
770
|
-
query.nor
|
771
|
-
end
|
772
|
-
|
773
|
-
it "does not add any criterion" do
|
774
|
-
expect(selection.selector).to eq({})
|
775
|
-
end
|
776
|
-
|
777
|
-
it "returns the query" do
|
778
|
-
expect(selection).to eq(query)
|
779
|
-
end
|
942
|
+
context "when the criteria are on the same field" do
|
780
943
|
|
781
|
-
|
782
|
-
|
944
|
+
context 'simple criteria' do
|
945
|
+
let(:selection) do
|
946
|
+
query.send(tested_method, { first: [ 1, 2 ] }, { first: [ 3, 4 ] })
|
947
|
+
end
|
783
948
|
|
784
|
-
|
949
|
+
it_behaves_like 'returns a cloned query'
|
785
950
|
|
786
|
-
|
787
|
-
|
788
|
-
|
951
|
+
it "appends both $or/$nor expressions" do
|
952
|
+
expect(selection.selector).to eq({
|
953
|
+
expected_operator => [
|
954
|
+
{ "first" => [ 1, 2 ] },
|
955
|
+
{ "first" => [ 3, 4 ] }
|
956
|
+
]
|
957
|
+
})
|
958
|
+
end
|
959
|
+
end
|
789
960
|
|
790
|
-
|
791
|
-
|
792
|
-
|
961
|
+
context 'Key criteria as one argument' do
|
962
|
+
let(:selection) do
|
963
|
+
query.send(tested_method, :first.gt => 3, :first.lt => 5)
|
964
|
+
end
|
793
965
|
|
794
|
-
|
795
|
-
expect(selection).to eq(query)
|
796
|
-
end
|
966
|
+
it_behaves_like 'returns a cloned query'
|
797
967
|
|
798
|
-
|
799
|
-
|
968
|
+
it "adds all criteria" do
|
969
|
+
expect(selection.selector).to eq({
|
970
|
+
expected_operator => [
|
971
|
+
{ "first" => {'$gt' => 3, '$lt' => 5} },
|
972
|
+
]
|
973
|
+
})
|
974
|
+
end
|
975
|
+
end
|
800
976
|
|
801
|
-
|
977
|
+
context 'Key criteria as multiple arguments' do
|
978
|
+
let(:selection) do
|
979
|
+
query.send(tested_method, {:first.gt => 3}, {:first.lt => 5})
|
980
|
+
end
|
802
981
|
|
803
|
-
|
804
|
-
query.nor(field: [ 1, 2 ])
|
805
|
-
end
|
982
|
+
it_behaves_like 'returns a cloned query'
|
806
983
|
|
807
|
-
|
808
|
-
|
809
|
-
|
810
|
-
|
984
|
+
it "adds all criteria" do
|
985
|
+
expect(selection.selector).to eq({
|
986
|
+
expected_operator => [
|
987
|
+
{ "first" => {'$gt' => 3} },
|
988
|
+
{ "first" => {'$lt' => 5} },
|
989
|
+
]
|
990
|
+
})
|
991
|
+
end
|
992
|
+
end
|
811
993
|
end
|
812
|
-
|
813
|
-
it_behaves_like 'returns a cloned query'
|
814
994
|
end
|
815
995
|
|
816
|
-
context "when
|
996
|
+
context "when chaining the criterion" do
|
817
997
|
|
818
|
-
context "when the criterion are
|
998
|
+
context "when the criterion are for different fields" do
|
819
999
|
|
820
1000
|
let(:selection) do
|
821
|
-
query.
|
1001
|
+
query.send(tested_method, first: [ 1, 2 ]).send(tested_method, second: [ 3, 4 ])
|
822
1002
|
end
|
823
1003
|
|
824
|
-
|
1004
|
+
it_behaves_like 'returns a cloned query'
|
1005
|
+
|
1006
|
+
it "adds the $or/$nor selectors" do
|
825
1007
|
expect(selection.selector).to eq({
|
826
|
-
|
1008
|
+
expected_operator => [
|
827
1009
|
{ "first" => [ 1, 2 ] },
|
828
1010
|
{ "second" => [ 3, 4 ] }
|
829
1011
|
]
|
830
1012
|
})
|
831
1013
|
end
|
832
|
-
|
833
|
-
it_behaves_like 'returns a cloned query'
|
834
1014
|
end
|
835
1015
|
|
836
1016
|
context "when the criterion are on the same field" do
|
837
1017
|
|
838
1018
|
let(:selection) do
|
839
|
-
query.
|
1019
|
+
query.send(tested_method, first: [ 1, 2 ]).send(tested_method, first: [ 3, 4 ])
|
840
1020
|
end
|
841
1021
|
|
842
|
-
|
1022
|
+
it_behaves_like 'returns a cloned query'
|
1023
|
+
|
1024
|
+
it "appends both $or/$nor expressions" do
|
843
1025
|
expect(selection.selector).to eq({
|
844
|
-
|
1026
|
+
expected_operator => [
|
845
1027
|
{ "first" => [ 1, 2 ] },
|
846
1028
|
{ "first" => [ 3, 4 ] }
|
847
1029
|
]
|
848
1030
|
})
|
849
1031
|
end
|
850
|
-
|
851
|
-
it_behaves_like 'returns a cloned query'
|
852
1032
|
end
|
853
1033
|
end
|
1034
|
+
end
|
854
1035
|
|
855
|
-
|
856
|
-
|
857
|
-
context "when the criterion are fnor different fields" do
|
858
|
-
|
859
|
-
let(:selection) do
|
860
|
-
query.nor(first: [ 1, 2 ]).nor(second: [ 3, 4 ])
|
861
|
-
end
|
862
|
-
|
863
|
-
it "adds the $nor selectors" do
|
864
|
-
expect(selection.selector).to eq({
|
865
|
-
"$nor" => [
|
866
|
-
{ "first" => [ 1, 2 ] },
|
867
|
-
{ "second" => [ 3, 4 ] }
|
868
|
-
]
|
869
|
-
})
|
870
|
-
end
|
1036
|
+
describe "#or" do
|
871
1037
|
|
872
|
-
|
873
|
-
|
1038
|
+
let(:tested_method) { :or }
|
1039
|
+
let(:expected_operator) { '$or' }
|
874
1040
|
|
875
|
-
|
1041
|
+
it_behaves_like '$or/$nor'
|
1042
|
+
end
|
876
1043
|
|
877
|
-
|
878
|
-
query.nor(first: [ 1, 2 ]).nor(first: [ 3, 4 ])
|
879
|
-
end
|
1044
|
+
describe "#nor" do
|
880
1045
|
|
881
|
-
|
882
|
-
|
883
|
-
"$nor" => [
|
884
|
-
{ "first" => [ 1, 2 ] },
|
885
|
-
{ "first" => [ 3, 4 ] }
|
886
|
-
]
|
887
|
-
})
|
888
|
-
end
|
1046
|
+
let(:tested_method) { :nor }
|
1047
|
+
let(:expected_operator) { '$nor' }
|
889
1048
|
|
890
|
-
|
891
|
-
end
|
892
|
-
end
|
1049
|
+
it_behaves_like '$or/$nor'
|
893
1050
|
end
|
894
1051
|
|
895
1052
|
describe "#any_of" do
|
@@ -1098,6 +1255,112 @@ describe Mongoid::Criteria::Queryable::Selectable do
|
|
1098
1255
|
it_behaves_like 'returns a cloned query'
|
1099
1256
|
end
|
1100
1257
|
|
1258
|
+
context 'when criteria are simple and handled via Key' do
|
1259
|
+
shared_examples_for 'adds conditions with $or' do
|
1260
|
+
|
1261
|
+
it "adds conditions with $or" do
|
1262
|
+
expect(selection.selector).to eq({
|
1263
|
+
'$or' => [
|
1264
|
+
{'field' => 3},
|
1265
|
+
{'field' => {'$lt' => 5}},
|
1266
|
+
],
|
1267
|
+
})
|
1268
|
+
end
|
1269
|
+
|
1270
|
+
it_behaves_like 'returns a cloned query'
|
1271
|
+
end
|
1272
|
+
|
1273
|
+
shared_examples_for 'adds one condition' do
|
1274
|
+
|
1275
|
+
it "adds one condition" do
|
1276
|
+
expect(selection.selector).to eq({
|
1277
|
+
'field' => 3,
|
1278
|
+
'$and' => [
|
1279
|
+
{'field' => {'$lt' => 5}},
|
1280
|
+
],
|
1281
|
+
})
|
1282
|
+
end
|
1283
|
+
|
1284
|
+
it_behaves_like 'returns a cloned query'
|
1285
|
+
end
|
1286
|
+
|
1287
|
+
context 'criteria are provided in the same hash' do
|
1288
|
+
let(:selection) do
|
1289
|
+
query.send(tested_method, :field => 3, :field.lt => 5)
|
1290
|
+
end
|
1291
|
+
|
1292
|
+
it_behaves_like 'adds one condition'
|
1293
|
+
end
|
1294
|
+
|
1295
|
+
context 'criteria are provided in separate hashes' do
|
1296
|
+
let(:selection) do
|
1297
|
+
query.send(tested_method, {:field => 3}, {:field.lt => 5})
|
1298
|
+
end
|
1299
|
+
|
1300
|
+
it_behaves_like 'adds conditions with $or'
|
1301
|
+
end
|
1302
|
+
|
1303
|
+
context 'when the criterion is wrapped in an array' do
|
1304
|
+
let(:selection) do
|
1305
|
+
query.send(tested_method, [:field => 3], [:field.lt => 5])
|
1306
|
+
end
|
1307
|
+
|
1308
|
+
it_behaves_like 'adds conditions with $or'
|
1309
|
+
end
|
1310
|
+
end
|
1311
|
+
|
1312
|
+
context 'when criteria are handled via Key and simple' do
|
1313
|
+
shared_examples_for 'adds conditions with $or' do
|
1314
|
+
|
1315
|
+
it "adds conditions with $or" do
|
1316
|
+
expect(selection.selector).to eq({
|
1317
|
+
'$or' => [
|
1318
|
+
{'field' => {'$gt' => 3}},
|
1319
|
+
{'field' => 5},
|
1320
|
+
],
|
1321
|
+
})
|
1322
|
+
end
|
1323
|
+
|
1324
|
+
it_behaves_like 'returns a cloned query'
|
1325
|
+
end
|
1326
|
+
|
1327
|
+
shared_examples_for 'adds one condition' do
|
1328
|
+
|
1329
|
+
it "adds one condition" do
|
1330
|
+
expect(selection.selector).to eq({
|
1331
|
+
'field' => {'$gt' => 3},
|
1332
|
+
'$and' => ['field' => 5],
|
1333
|
+
})
|
1334
|
+
end
|
1335
|
+
|
1336
|
+
it_behaves_like 'returns a cloned query'
|
1337
|
+
end
|
1338
|
+
|
1339
|
+
context 'criteria are provided in the same hash' do
|
1340
|
+
let(:selection) do
|
1341
|
+
query.send(tested_method, :field.gt => 3, :field => 5)
|
1342
|
+
end
|
1343
|
+
|
1344
|
+
it_behaves_like 'adds one condition'
|
1345
|
+
end
|
1346
|
+
|
1347
|
+
context 'criteria are provided in separate hashes' do
|
1348
|
+
let(:selection) do
|
1349
|
+
query.send(tested_method, {:field.gt => 3}, {:field => 5})
|
1350
|
+
end
|
1351
|
+
|
1352
|
+
it_behaves_like 'adds conditions with $or'
|
1353
|
+
end
|
1354
|
+
|
1355
|
+
context 'when the criterion is wrapped in an array' do
|
1356
|
+
let(:selection) do
|
1357
|
+
query.send(tested_method, [:field.gt => 3], [:field => 5])
|
1358
|
+
end
|
1359
|
+
|
1360
|
+
it_behaves_like 'adds conditions with $or'
|
1361
|
+
end
|
1362
|
+
end
|
1363
|
+
|
1101
1364
|
context "when a criterion has an aliased field" do
|
1102
1365
|
|
1103
1366
|
let(:selection) do
|
@@ -1271,6 +1534,25 @@ describe Mongoid::Criteria::Queryable::Selectable do
|
|
1271
1534
|
end
|
1272
1535
|
end
|
1273
1536
|
|
1537
|
+
context "when the criteria uses Key" do
|
1538
|
+
|
1539
|
+
let(:selection) do
|
1540
|
+
query.not(:age.gt => 50)
|
1541
|
+
end
|
1542
|
+
|
1543
|
+
it "negates the gt selection" do
|
1544
|
+
expect(selection.selector).to eq(
|
1545
|
+
'$and' => ['$nor' => ['age' => {'$gt' => 50}]]
|
1546
|
+
)
|
1547
|
+
end
|
1548
|
+
|
1549
|
+
it_behaves_like 'returns a cloned query'
|
1550
|
+
|
1551
|
+
it "removes the negation on the clone" do
|
1552
|
+
expect(selection).to_not be_negating
|
1553
|
+
end
|
1554
|
+
end
|
1555
|
+
|
1274
1556
|
context "when the following criteria is a where" do
|
1275
1557
|
|
1276
1558
|
let(:selection) do
|