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.
Files changed (102) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +2 -0
  3. data.tar.gz.sig +1 -0
  4. data/LICENSE +1 -0
  5. data/README.md +3 -2
  6. data/Rakefile +12 -0
  7. data/lib/mongoid.rb +2 -1
  8. data/lib/mongoid/association/embedded/embeds_many.rb +2 -1
  9. data/lib/mongoid/association/embedded/embeds_one.rb +2 -1
  10. data/lib/mongoid/association/proxy.rb +1 -1
  11. data/lib/mongoid/association/relatable.rb +23 -21
  12. data/lib/mongoid/atomic.rb +13 -3
  13. data/lib/mongoid/atomic/paths/embedded.rb +1 -1
  14. data/lib/mongoid/attributes.rb +28 -20
  15. data/lib/mongoid/attributes/dynamic.rb +15 -14
  16. data/lib/mongoid/config/environment.rb +21 -8
  17. data/lib/mongoid/copyable.rb +5 -1
  18. data/lib/mongoid/criteria.rb +7 -1
  19. data/lib/mongoid/criteria/modifiable.rb +13 -2
  20. data/lib/mongoid/criteria/queryable/extensions/numeric.rb +1 -1
  21. data/lib/mongoid/criteria/queryable/extensions/regexp.rb +3 -3
  22. data/lib/mongoid/criteria/queryable/key.rb +67 -8
  23. data/lib/mongoid/criteria/queryable/mergeable.rb +5 -4
  24. data/lib/mongoid/criteria/queryable/selectable.rb +3 -4
  25. data/lib/mongoid/criteria/queryable/selector.rb +9 -31
  26. data/lib/mongoid/extensions/hash.rb +4 -2
  27. data/lib/mongoid/extensions/regexp.rb +1 -1
  28. data/lib/mongoid/extensions/string.rb +5 -3
  29. data/lib/mongoid/fields.rb +2 -1
  30. data/lib/mongoid/matchable.rb +14 -15
  31. data/lib/mongoid/matchable/all.rb +4 -3
  32. data/lib/mongoid/matchable/default.rb +71 -24
  33. data/lib/mongoid/matchable/regexp.rb +2 -2
  34. data/lib/mongoid/persistable/pushable.rb +11 -2
  35. data/lib/mongoid/persistence_context.rb +6 -6
  36. data/lib/mongoid/positional.rb +1 -1
  37. data/lib/mongoid/query_cache.rb +3 -2
  38. data/lib/mongoid/validatable/macros.rb +1 -1
  39. data/lib/mongoid/validatable/uniqueness.rb +1 -1
  40. data/lib/mongoid/version.rb +2 -1
  41. data/lib/rails/generators/mongoid/model/templates/model.rb.tt +1 -1
  42. data/spec/README.md +18 -0
  43. data/spec/app/models/delegating_patient.rb +16 -0
  44. data/spec/app/models/other_owner_object.rb +2 -0
  45. data/spec/integration/app_spec.rb +192 -0
  46. data/spec/integration/associations/embedded_spec.rb +62 -0
  47. data/spec/integration/criteria/time_with_zone_spec.rb +32 -0
  48. data/spec/integration/document_spec.rb +22 -0
  49. data/spec/integration/matchable_spec.rb +680 -0
  50. data/spec/lite_spec_helper.rb +15 -5
  51. data/spec/mongoid/association/embedded/embedded_in_spec.rb +58 -0
  52. data/spec/mongoid/association/embedded/embeds_many_models.rb +53 -0
  53. data/spec/mongoid/association/embedded/embeds_many_spec.rb +10 -0
  54. data/spec/mongoid/association/embedded/embeds_one_dnl_models.rb +6 -0
  55. data/spec/mongoid/association/embedded/embeds_one_models.rb +51 -0
  56. data/spec/mongoid/association/embedded/embeds_one_spec.rb +46 -0
  57. data/spec/mongoid/association/referenced/belongs_to_spec.rb +23 -6
  58. data/spec/mongoid/association/referenced/has_and_belongs_to_many/proxy_spec.rb +2 -1
  59. data/spec/mongoid/association/referenced/has_many/proxy_spec.rb +2 -1
  60. data/spec/mongoid/association/referenced/has_one_spec.rb +12 -2
  61. data/spec/mongoid/attributes/dynamic_spec.rb +153 -0
  62. data/spec/mongoid/attributes_spec.rb +19 -7
  63. data/spec/mongoid/clients/factory_spec.rb +2 -2
  64. data/spec/mongoid/clients/options_spec.rb +4 -4
  65. data/spec/mongoid/clients/sessions_spec.rb +20 -7
  66. data/spec/mongoid/clients/transactions_spec.rb +36 -15
  67. data/spec/mongoid/clients_spec.rb +2 -2
  68. data/spec/mongoid/contextual/atomic_spec.rb +20 -10
  69. data/spec/mongoid/contextual/geo_near_spec.rb +1 -0
  70. data/spec/mongoid/contextual/map_reduce_spec.rb +20 -5
  71. data/spec/mongoid/contextual/mongo_spec.rb +76 -53
  72. data/spec/mongoid/criteria/modifiable_spec.rb +59 -10
  73. data/spec/mongoid/criteria/queryable/extensions/numeric_spec.rb +54 -0
  74. data/spec/mongoid/criteria/queryable/extensions/regexp_spec.rb +7 -7
  75. data/spec/mongoid/criteria/queryable/extensions/string_spec.rb +1 -1
  76. data/spec/mongoid/criteria/queryable/key_spec.rb +48 -6
  77. data/spec/mongoid/criteria/queryable/selectable_logical_spec.rb +762 -0
  78. data/spec/mongoid/criteria/queryable/selectable_spec.rb +5 -224
  79. data/spec/mongoid/criteria/queryable/selector_spec.rb +37 -0
  80. data/spec/mongoid/criteria_spec.rb +7 -2
  81. data/spec/mongoid/document_fields_spec.rb +88 -0
  82. data/spec/mongoid/document_persistence_context_spec.rb +33 -0
  83. data/spec/mongoid/extensions/string_spec.rb +35 -7
  84. data/spec/mongoid/indexable_spec.rb +6 -4
  85. data/spec/mongoid/matchable/default_spec.rb +10 -3
  86. data/spec/mongoid/matchable/regexp_spec.rb +2 -2
  87. data/spec/mongoid/matchable_spec.rb +2 -2
  88. data/spec/mongoid/persistable/pushable_spec.rb +55 -1
  89. data/spec/mongoid/query_cache_spec.rb +2 -1
  90. data/spec/mongoid/relations/proxy_spec.rb +1 -1
  91. data/spec/mongoid/scopable_spec.rb +2 -1
  92. data/spec/mongoid/tasks/database_rake_spec.rb +13 -13
  93. data/spec/mongoid/tasks/database_spec.rb +1 -1
  94. data/spec/mongoid/validatable/uniqueness_spec.rb +33 -6
  95. data/spec/spec_helper.rb +4 -37
  96. data/spec/support/child_process_helper.rb +76 -0
  97. data/spec/support/cluster_config.rb +158 -0
  98. data/spec/support/constraints.rb +29 -19
  99. data/spec/support/expectations.rb +17 -3
  100. data/spec/support/spec_config.rb +12 -4
  101. metadata +525 -464
  102. metadata.gz.sig +2 -0
@@ -315,7 +315,7 @@ describe String do
315
315
  context "when provided a regex" do
316
316
 
317
317
  let(:regex) do
318
- /^[123]/
318
+ /\A[123]/.freeze
319
319
  end
320
320
 
321
321
  let(:evolved) do
@@ -23,16 +23,58 @@ describe Mongoid::Criteria::Queryable::Key do
23
23
 
24
24
  describe "#__expr_part__" do
25
25
 
26
- let(:key) do
27
- described_class.new("field", :__union__, "$all")
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
- let(:specified) do
31
- key.__expr_part__([ 1, 2 ])
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
- it "returns the name plus operator and value" do
35
- expect(specified).to eq({ "field" => { "$all" => [ 1, 2 ] }})
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