mongoid 6.4.0 → 6.4.7

Sign up to get free protection for your applications and to get access to all the features.
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