mongoid 6.4.0 → 6.4.7

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 (76) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/Rakefile +26 -0
  5. data/lib/mongoid.rb +1 -1
  6. data/lib/mongoid/clients/sessions.rb +2 -2
  7. data/lib/mongoid/contextual/aggregable/mongo.rb +1 -1
  8. data/lib/mongoid/contextual/map_reduce.rb +4 -4
  9. data/lib/mongoid/contextual/memory.rb +4 -4
  10. data/lib/mongoid/contextual/mongo.rb +3 -3
  11. data/lib/mongoid/criteria/modifiable.rb +12 -2
  12. data/lib/mongoid/criteria/queryable/selectable.rb +34 -7
  13. data/lib/mongoid/document.rb +4 -4
  14. data/lib/mongoid/extensions/big_decimal.rb +1 -1
  15. data/lib/mongoid/extensions/regexp.rb +1 -0
  16. data/lib/mongoid/extensions/string.rb +3 -1
  17. data/lib/mongoid/indexable.rb +4 -4
  18. data/lib/mongoid/matchable.rb +3 -0
  19. data/lib/mongoid/matchable/nor.rb +37 -0
  20. data/lib/mongoid/persistable.rb +1 -1
  21. data/lib/mongoid/persistable/creatable.rb +2 -2
  22. data/lib/mongoid/persistable/deletable.rb +2 -2
  23. data/lib/mongoid/persistable/settable.rb +5 -5
  24. data/lib/mongoid/persistable/updatable.rb +2 -2
  25. data/lib/mongoid/persistable/upsertable.rb +1 -1
  26. data/lib/mongoid/persistence_context.rb +4 -0
  27. data/lib/mongoid/query_cache.rb +21 -10
  28. data/lib/mongoid/railtie.rb +17 -0
  29. data/lib/mongoid/railties/controller_runtime.rb +86 -0
  30. data/lib/mongoid/relations/embedded/batchable.rb +4 -4
  31. data/lib/mongoid/relations/embedded/many.rb +23 -0
  32. data/lib/mongoid/relations/many.rb +2 -2
  33. data/lib/mongoid/relations/referenced/many.rb +1 -1
  34. data/lib/mongoid/relations/touchable.rb +1 -1
  35. data/lib/mongoid/reloadable.rb +1 -1
  36. data/lib/mongoid/scopable.rb +3 -3
  37. data/lib/mongoid/tasks/database.rb +2 -2
  38. data/lib/mongoid/threaded.rb +36 -0
  39. data/lib/mongoid/version.rb +1 -1
  40. data/lib/rails/generators/mongoid/config/templates/mongoid.yml +4 -0
  41. data/spec/app/models/array_field.rb +7 -0
  42. data/spec/app/models/delegating_patient.rb +16 -0
  43. data/spec/integration/document_spec.rb +22 -0
  44. data/spec/mongoid/clients/factory_spec.rb +52 -28
  45. data/spec/mongoid/clients/options_spec.rb +30 -15
  46. data/spec/mongoid/clients/sessions_spec.rb +12 -3
  47. data/spec/mongoid/contextual/geo_near_spec.rb +1 -0
  48. data/spec/mongoid/contextual/mongo_spec.rb +2 -2
  49. data/spec/mongoid/criteria/modifiable_spec.rb +59 -10
  50. data/spec/mongoid/criteria/queryable/extensions/big_decimal_spec.rb +3 -3
  51. data/spec/mongoid/criteria/queryable/selectable_spec.rb +42 -3
  52. data/spec/mongoid/criteria/queryable/selector_spec.rb +2 -2
  53. data/spec/mongoid/criteria/scopable_spec.rb +81 -0
  54. data/spec/mongoid/criteria_spec.rb +4 -1
  55. data/spec/mongoid/document_spec.rb +54 -0
  56. data/spec/mongoid/extensions/big_decimal_spec.rb +9 -9
  57. data/spec/mongoid/extensions/regexp_spec.rb +23 -0
  58. data/spec/mongoid/extensions/string_spec.rb +35 -7
  59. data/spec/mongoid/fields_spec.rb +1 -1
  60. data/spec/mongoid/findable_spec.rb +1 -1
  61. data/spec/mongoid/matchable/nor_spec.rb +209 -0
  62. data/spec/mongoid/matchable_spec.rb +26 -1
  63. data/spec/mongoid/persistable/incrementable_spec.rb +6 -6
  64. data/spec/mongoid/persistable/settable_spec.rb +35 -1
  65. data/spec/mongoid/query_cache_spec.rb +73 -18
  66. data/spec/mongoid/relations/embedded/many_spec.rb +246 -16
  67. data/spec/mongoid/scopable_spec.rb +13 -0
  68. data/spec/mongoid/threaded_spec.rb +68 -0
  69. data/spec/rails/controller_extension/controller_runtime_spec.rb +110 -0
  70. data/spec/spec_helper.rb +9 -0
  71. data/spec/support/cluster_config.rb +158 -0
  72. data/spec/support/constraints.rb +101 -0
  73. data/spec/support/macros.rb +20 -0
  74. data/spec/support/spec_config.rb +42 -0
  75. metadata +41 -23
  76. metadata.gz.sig +0 -0
@@ -1171,7 +1171,7 @@ describe Mongoid::Fields do
1171
1171
  end
1172
1172
 
1173
1173
  let(:decimal) do
1174
- BigDecimal.new("1000000.00")
1174
+ BigDecimal("1000000.00")
1175
1175
  end
1176
1176
 
1177
1177
  context "when setting to a big decimal" do
@@ -10,7 +10,7 @@ describe Mongoid::Findable do
10
10
  end
11
11
 
12
12
  it "returns the distinct values for the field" do
13
- expect(Band.distinct(:name)).to eq([ "Tool", "Photek" ])
13
+ expect(Band.distinct(:name).sort).to eq([ "Photek", "Tool" ])
14
14
  end
15
15
  end
16
16
 
@@ -0,0 +1,209 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ describe Mongoid::Matchable::Nor do
6
+
7
+ let(:target) do
8
+ Person.new
9
+ end
10
+
11
+ let(:matcher) do
12
+ described_class.new("value", target)
13
+ end
14
+
15
+ describe "#_matches?" do
16
+
17
+ context "when provided a simple expression" do
18
+
19
+ context "when one of the hashes does not match model" do
20
+
21
+ let(:matches) do
22
+ matcher._matches?(
23
+ [ { title: "Sir" }, { title: "King" } ]
24
+ )
25
+ end
26
+
27
+ let(:target) do
28
+ Person.new(title: 'Queen')
29
+ end
30
+
31
+ it "returns true" do
32
+ expect(matches).to be true
33
+ end
34
+ end
35
+
36
+ context "when all of the hashes match different fields in model" do
37
+ let(:matches) do
38
+ matcher._matches?(
39
+ [ { age: 10 }, { title: "King" } ]
40
+ )
41
+ end
42
+
43
+ let(:target) do
44
+ Person.new(title: 'King', age: 10)
45
+ end
46
+
47
+ it "returns false" do
48
+ expect(matches).to be false
49
+ end
50
+ end
51
+
52
+ context "when one of the hashes matches an array field in model" do
53
+ let(:matches) do
54
+ matcher._matches?(
55
+ [ { af: "Sir" }, { af: "King" } ]
56
+ )
57
+ end
58
+
59
+ let(:target) do
60
+ ArrayField.new(af: ['King'])
61
+ end
62
+
63
+ it "returns false" do
64
+ expect(matches).to be false
65
+ end
66
+ end
67
+
68
+ context "when none of the hashes matches an array field in model" do
69
+ let(:matches) do
70
+ matcher._matches?(
71
+ [ { af: "Sir" }, { af: "King" } ]
72
+ )
73
+ end
74
+
75
+ let(:target) do
76
+ ArrayField.new(af: ['Boo'])
77
+ end
78
+
79
+ it "returns true" do
80
+ expect(matches).to be true
81
+ end
82
+ end
83
+
84
+ context "when there are no criteria" do
85
+
86
+ it "returns false" do
87
+ expect(matcher._matches?([])).to be false
88
+ end
89
+ end
90
+
91
+ # $nor with $not is a double negation.
92
+ # Whatever the argument of $not is is what the overall condition
93
+ # is looking for.
94
+ context "when the expression is a $not" do
95
+
96
+ let(:matches) do
97
+ matcher._matches?([ { title: {:$not => /Foobar/ } }])
98
+ end
99
+
100
+ context "when the value does not match $not argument" do
101
+
102
+ let(:target) do
103
+ Person.new(title: 'test')
104
+ end
105
+
106
+ it "returns false" do
107
+ expect(matches).to be false
108
+ end
109
+ end
110
+
111
+ context "when the value matches $not argument" do
112
+
113
+ let(:target) do
114
+ Person.new(title: 'Foobar baz')
115
+ end
116
+
117
+ it "returns true" do
118
+ expect(matches).to be true
119
+ end
120
+ end
121
+ end
122
+ end
123
+
124
+ context "when provided a complex expression" do
125
+
126
+ context "when none of the model values match criteria values" do
127
+
128
+ let(:matches) do
129
+ matcher._matches?(
130
+ [
131
+ { title: { "$in" => [ "Sir", "Madam" ] } },
132
+ { title: "King" }
133
+ ]
134
+ )
135
+ end
136
+
137
+ let(:target) do
138
+ Person.new(title: 'Queen')
139
+ end
140
+
141
+ it "returns true" do
142
+ expect(matches).to be true
143
+ end
144
+ end
145
+
146
+ context "when there is a matching value" do
147
+
148
+ let(:matches) do
149
+ matcher._matches?(
150
+ [
151
+ { title: { "$in" => [ "Prince", "Madam" ] } },
152
+ { title: "King" }
153
+ ]
154
+ )
155
+ end
156
+
157
+ let(:target) do
158
+ Person.new(title: 'Prince')
159
+ end
160
+
161
+ it "returns false" do
162
+ expect(matches).to be false
163
+ end
164
+ end
165
+
166
+ context "when expression contain multiple fields" do
167
+
168
+ let(:matches) do
169
+ matcher._matches?(
170
+ [
171
+ { title: "Sir", age: 23 },
172
+ { title: "King", age: 100 }
173
+ ]
174
+ )
175
+ end
176
+
177
+ context 'and model has different values in all of the fields' do
178
+ let(:target) do
179
+ Person.new(title: 'Queen', age: 10)
180
+ end
181
+
182
+ it "returns true" do
183
+ expect(matches).to be true
184
+ end
185
+ end
186
+
187
+ context 'and model has identical value in one of the fields' do
188
+ let(:target) do
189
+ Person.new(title: 'Queen', age: 23)
190
+ end
191
+
192
+ it "returns true" do
193
+ expect(matches).to be true
194
+ end
195
+ end
196
+
197
+ context 'and model has identical values in all of the fields' do
198
+ let(:target) do
199
+ Person.new(title: 'Sir', age: 23)
200
+ end
201
+
202
+ it "returns false" do
203
+ expect(matches).to be false
204
+ end
205
+ end
206
+ end
207
+ end
208
+ end
209
+ end
@@ -86,7 +86,7 @@ describe Mongoid::Matchable do
86
86
  let(:selector) do
87
87
  { "occupants.0" => "Tim" }
88
88
  end
89
-
89
+
90
90
  it "returns true" do
91
91
  expect(document.locations.first._matches?(selector)).to be true
92
92
  end
@@ -774,6 +774,31 @@ describe Mongoid::Matchable do
774
774
  end
775
775
  end
776
776
 
777
+ context "with an $nor selector" do
778
+
779
+ context "when the attributes match" do
780
+
781
+ let(:selector) do
782
+ { "$nor" => [ { number: 10 }, { number: { "$gt" => 199 } } ] }
783
+ end
784
+
785
+ it "returns true" do
786
+ expect(document._matches?(selector)).to be true
787
+ end
788
+ end
789
+
790
+ context "when the attributes do not match" do
791
+
792
+ let(:selector) do
793
+ { "$nor" => [ { number: 10 }, { number: { "$gt" => 99 } } ] }
794
+ end
795
+
796
+ it "returns false" do
797
+ expect(document._matches?(selector)).to be false
798
+ end
799
+ end
800
+ end
801
+
777
802
  context "with a $size selector" do
778
803
 
779
804
  context "when the attributes match" do
@@ -66,15 +66,15 @@ describe Mongoid::Persistable::Incrementable do
66
66
  context "when providing big decimal values" do
67
67
 
68
68
  let(:five) do
69
- BigDecimal.new("5.0")
69
+ BigDecimal("5.0")
70
70
  end
71
71
 
72
72
  let(:neg_ten) do
73
- BigDecimal.new("-10.0")
73
+ BigDecimal("-10.0")
74
74
  end
75
75
 
76
76
  let(:thirty) do
77
- BigDecimal.new("30.0")
77
+ BigDecimal("30.0")
78
78
  end
79
79
 
80
80
  let!(:inc) do
@@ -151,15 +151,15 @@ describe Mongoid::Persistable::Incrementable do
151
151
  context "when providing big decimal values" do
152
152
 
153
153
  let(:five) do
154
- BigDecimal.new("5.0")
154
+ BigDecimal("5.0")
155
155
  end
156
156
 
157
157
  let(:neg_ten) do
158
- BigDecimal.new("-10.0")
158
+ BigDecimal("-10.0")
159
159
  end
160
160
 
161
161
  let(:thirty) do
162
- BigDecimal.new("30.0")
162
+ BigDecimal("30.0")
163
163
  end
164
164
 
165
165
  let!(:inc) do
@@ -278,7 +278,22 @@ describe Mongoid::Persistable::Settable do
278
278
  end
279
279
  end
280
280
 
281
- context 'when the field is a bested hash' do
281
+ context 'when the field is a nested hash' do
282
+
283
+ context 'when the field is reset to an empty hash' do
284
+
285
+ before do
286
+ church.set('location' => {})
287
+ end
288
+
289
+ it 'updates the field locally' do
290
+ expect(church.location).to eq({})
291
+ end
292
+
293
+ it 'updates the field in the database' do
294
+ expect(church.reload.location).to eq({})
295
+ end
296
+ end
282
297
 
283
298
  context 'when a leaf value in the nested hash is updated' do
284
299
 
@@ -300,6 +315,25 @@ describe Mongoid::Persistable::Settable do
300
315
  end
301
316
  end
302
317
 
318
+ context 'when a leaf value in the nested hash is updated to a number' do
319
+
320
+ let(:church) do
321
+ Church.new.tap do |a|
322
+ a.location = {'address' => {'city' => 'Berlin', 'street' => 'Yorckstr'}}
323
+ a.name = 'Church1'
324
+ a.save
325
+ end
326
+ end
327
+
328
+ before do
329
+ church.set('location.address.city' => 12345)
330
+ end
331
+
332
+ it 'updates the nested value to the correct value' do
333
+ expect(church.name).to eq('Church1')
334
+ expect(church.location).to eql({'address' => {'city' => 12345, 'street' => 'Yorckstr'}})
335
+ end
336
+ end
303
337
 
304
338
  context 'when the nested hash is many levels deep' do
305
339
 
@@ -38,9 +38,10 @@ describe Mongoid::QueryCache do
38
38
  end
39
39
 
40
40
  it 'queries for each access to the base' do
41
- expect(server).to receive(:with_connection).exactly(relations.size).times.and_call_original
42
- relations.each do |object|
43
- object.person
41
+ expect_query(relations.size) do
42
+ relations.each do |object|
43
+ object.person
44
+ end
44
45
  end
45
46
  end
46
47
  end
@@ -52,9 +53,10 @@ describe Mongoid::QueryCache do
52
53
  end
53
54
 
54
55
  it 'queries only once for the base' do
55
- expect(server).to receive(:with_connection).exactly(1).times.and_call_original
56
- relations.each do |object|
57
- object.person
56
+ expect_query(1) do
57
+ relations.each do |object|
58
+ object.person
59
+ end
58
60
  end
59
61
  end
60
62
  end
@@ -205,6 +207,10 @@ describe Mongoid::QueryCache do
205
207
  end
206
208
 
207
209
  before do
210
+ 10.times do |i|
211
+ game.ratings << Rating.create!(value: i+1)
212
+ end
213
+
208
214
  game.ratings.where(:value.gt => 5).asc(:id).all.to_a
209
215
  end
210
216
 
@@ -212,7 +218,9 @@ describe Mongoid::QueryCache do
212
218
 
213
219
  it "uses the cache" do
214
220
  expect_no_queries do
215
- game.ratings.where(:value.gt => 5).limit(2).asc(:id).to_a
221
+ result = game.ratings.where(:value.gt => 5).limit(2).asc(:id).to_a
222
+ expect(result.length).to eq(2)
223
+ expect(result.map { |r| r['value'] }).to eq([6, 7])
216
224
  end
217
225
  end
218
226
  end
@@ -225,14 +233,23 @@ describe Mongoid::QueryCache do
225
233
  end
226
234
 
227
235
  before do
236
+ 10.times do |i|
237
+ game.ratings << Rating.create!(value: i+1)
238
+ end
239
+
228
240
  game.ratings.where(:value.gt => 5).limit(3).asc(:id).all.to_a
229
241
  end
230
242
 
231
243
  context "when the next query has a limit" do
244
+ # Server versions older than 3.2 also perform a killCursors operation,
245
+ # which causes this test to fail.
246
+ min_server_version '3.2'
232
247
 
233
248
  it "queries again" do
234
249
  expect_query(1) do
235
- game.ratings.where(:value.gt => 5).limit(2).asc(:id).to_a
250
+ result = game.ratings.where(:value.gt => 5).limit(2).asc(:id).to_a
251
+ expect(result.length).to eq(2)
252
+ expect(result.map { |r| r['value'] }).to eq([6, 7])
236
253
  end
237
254
  end
238
255
  end
@@ -241,7 +258,9 @@ describe Mongoid::QueryCache do
241
258
 
242
259
  it "queries again" do
243
260
  expect_query(1) do
244
- game.ratings.where(:value.gt => 5).asc(:id).to_a
261
+ result = game.ratings.where(:value.gt => 5).asc(:id).to_a
262
+ expect(result.length).to eq(5)
263
+ expect(result.map { |r| r['value'] }).to eq([6, 7, 8, 9, 10])
245
264
  end
246
265
  end
247
266
  end
@@ -254,21 +273,34 @@ describe Mongoid::QueryCache do
254
273
  end
255
274
 
256
275
  before do
276
+ 10.times do |i|
277
+ game.ratings << Rating.create!(value: i+1)
278
+ end
279
+
257
280
  game.ratings.where(:value.gt => 5).asc(:id).all.to_a
258
281
  end
259
282
 
260
283
  it "does not query again" do
261
284
  expect_no_queries do
262
- game.ratings.where(:value.gt => 5).asc(:id).first
285
+ result = game.ratings.where(:value.gt => 5).asc(:id).first
286
+ expect(result['value']).to eq(6)
263
287
  end
264
288
  end
265
289
  end
266
290
 
267
291
  context "when limiting the result" do
292
+ before do
293
+ Band.destroy_all
294
+
295
+ 5.times { |i| Band.create!(name: "Band #{i}") }
296
+ Band.all.to_a
297
+ end
268
298
 
269
299
  it "does not query again" do
270
300
  expect_query(0) do
271
- Band.limit(2).all.to_a
301
+ result = Band.limit(2).all.to_a
302
+ expect(result.length).to eq(2)
303
+ expect(result.map { |r| r["name"] }).to eq(["Band 0", "Band 1"])
272
304
  end
273
305
  end
274
306
  end
@@ -276,12 +308,16 @@ describe Mongoid::QueryCache do
276
308
  context "when specifying a different skip value" do
277
309
 
278
310
  before do
279
- Band.limit(2).skip(1).all.to_a
311
+ Band.destroy_all
312
+
313
+ 5.times { |i| Band.create!(name: "Band #{i}") }
280
314
  end
281
315
 
282
316
  it "queries again" do
283
317
  expect_query(1) do
284
- Band.limit(2).skip(3).all.to_a
318
+ result = Band.limit(2).skip(3).all.to_a
319
+ expect(result.length).to eq(2)
320
+ expect(result.map { |r| r["name"] }).to eq(["Band 3", "Band 4"])
285
321
  end
286
322
  end
287
323
  end
@@ -317,6 +353,25 @@ describe Mongoid::QueryCache do
317
353
  end
318
354
  end
319
355
 
356
+ context 'when querying colleciton larger than the batch size' do
357
+ before do
358
+ Band.destroy_all
359
+ 101.times { |i| Band.create!(_id: i) }
360
+ end
361
+
362
+ it 'does not raise an exception when querying multiple times' do
363
+ expect do
364
+ results1 = Band.all.to_a
365
+ expect(results1.length).to eq(101)
366
+ expect(results1.map { |band| band["_id"] }).to eq([*0..100])
367
+
368
+ results2 = Band.all.to_a
369
+ expect(results2.length).to eq(101)
370
+ expect(results2.map { |band| band["_id"] }).to eq([*0..100])
371
+ end.not_to raise_error
372
+ end
373
+ end
374
+
320
375
  context "when query caching is enabled and the batch_size is set" do
321
376
 
322
377
  around(:each) do |example|
@@ -428,15 +483,15 @@ describe Mongoid::QueryCache do
428
483
  context "when querying a very large collection" do
429
484
 
430
485
  before do
431
- 123.times { Band.create! }
486
+ 100.times { Band.create! }
432
487
  end
433
488
 
434
489
  it "returns the right number of records" do
435
- expect(Band.all.to_a.length).to eq(123)
490
+ expect(Band.all.to_a.length).to eq(100)
436
491
  end
437
492
 
438
493
  it "#pluck returns the same count of objects" do
439
- expect(Band.pluck(:name).length).to eq(123)
494
+ expect(Band.pluck(:name).length).to eq(100)
440
495
  end
441
496
 
442
497
  context "when loading all the documents" do
@@ -447,12 +502,12 @@ describe Mongoid::QueryCache do
447
502
 
448
503
  it "caches the complete result of the query" do
449
504
  expect_no_queries do
450
- expect(Band.all.to_a.length).to eq(123)
505
+ expect(Band.all.to_a.length).to eq(100)
451
506
  end
452
507
  end
453
508
 
454
509
  it "returns the same count of objects when using #pluck" do
455
- expect(Band.pluck(:name).length).to eq(123)
510
+ expect(Band.pluck(:name).length).to eq(100)
456
511
  end
457
512
  end
458
513
  end