mongoid 6.4.1 → 6.4.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. checksums.yaml +5 -5
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +1 -3
  4. data/Rakefile +26 -0
  5. data/lib/mongoid.rb +1 -1
  6. data/lib/mongoid/contextual/map_reduce.rb +1 -1
  7. data/lib/mongoid/criteria/modifiable.rb +12 -2
  8. data/lib/mongoid/criteria/queryable/selectable.rb +34 -7
  9. data/lib/mongoid/document.rb +4 -4
  10. data/lib/mongoid/extensions/big_decimal.rb +1 -1
  11. data/lib/mongoid/extensions/regexp.rb +1 -0
  12. data/lib/mongoid/extensions/string.rb +3 -1
  13. data/lib/mongoid/matchable.rb +3 -0
  14. data/lib/mongoid/matchable/nor.rb +37 -0
  15. data/lib/mongoid/persistable/settable.rb +5 -5
  16. data/lib/mongoid/persistence_context.rb +4 -0
  17. data/lib/mongoid/query_cache.rb +64 -19
  18. data/lib/mongoid/railtie.rb +17 -0
  19. data/lib/mongoid/railties/controller_runtime.rb +86 -0
  20. data/lib/mongoid/scopable.rb +3 -3
  21. data/lib/mongoid/threaded.rb +36 -0
  22. data/lib/mongoid/version.rb +1 -1
  23. data/spec/app/models/array_field.rb +7 -0
  24. data/spec/app/models/delegating_patient.rb +16 -0
  25. data/spec/integration/document_spec.rb +22 -0
  26. data/spec/mongoid/clients/factory_spec.rb +52 -28
  27. data/spec/mongoid/clients/options_spec.rb +30 -15
  28. data/spec/mongoid/clients/sessions_spec.rb +12 -3
  29. data/spec/mongoid/contextual/geo_near_spec.rb +1 -0
  30. data/spec/mongoid/contextual/mongo_spec.rb +2 -2
  31. data/spec/mongoid/criteria/modifiable_spec.rb +59 -10
  32. data/spec/mongoid/criteria/queryable/extensions/big_decimal_spec.rb +3 -3
  33. data/spec/mongoid/criteria/queryable/selectable_spec.rb +42 -3
  34. data/spec/mongoid/criteria/queryable/selector_spec.rb +2 -2
  35. data/spec/mongoid/criteria/scopable_spec.rb +81 -0
  36. data/spec/mongoid/criteria_spec.rb +4 -1
  37. data/spec/mongoid/document_spec.rb +54 -0
  38. data/spec/mongoid/extensions/big_decimal_spec.rb +9 -9
  39. data/spec/mongoid/extensions/regexp_spec.rb +23 -0
  40. data/spec/mongoid/extensions/string_spec.rb +35 -7
  41. data/spec/mongoid/fields_spec.rb +1 -1
  42. data/spec/mongoid/findable_spec.rb +1 -1
  43. data/spec/mongoid/matchable/nor_spec.rb +209 -0
  44. data/spec/mongoid/matchable_spec.rb +26 -1
  45. data/spec/mongoid/persistable/incrementable_spec.rb +6 -6
  46. data/spec/mongoid/persistable/settable_spec.rb +19 -0
  47. data/spec/mongoid/query_cache_spec.rb +87 -18
  48. data/spec/mongoid/scopable_spec.rb +13 -0
  49. data/spec/mongoid/threaded_spec.rb +68 -0
  50. data/spec/rails/controller_extension/controller_runtime_spec.rb +110 -0
  51. data/spec/spec_helper.rb +10 -0
  52. data/spec/support/cluster_config.rb +158 -0
  53. data/spec/support/constraints.rb +101 -0
  54. data/spec/support/macros.rb +20 -0
  55. data/spec/support/session_registry.rb +50 -0
  56. data/spec/support/spec_config.rb +42 -0
  57. metadata +43 -23
  58. metadata.gz.sig +0 -0
@@ -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
@@ -315,6 +315,25 @@ describe Mongoid::Persistable::Settable do
315
315
  end
316
316
  end
317
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
318
337
 
319
338
  context 'when the nested hash is many levels deep' do
320
339
 
@@ -7,6 +7,20 @@ describe Mongoid::QueryCache do
7
7
  Mongoid::QueryCache.cache { spec.run }
8
8
  end
9
9
 
10
+ before(:all) do
11
+ # It is likely that there are other session leaks in the driver
12
+ # and/or Mongoid that are unrelated to the query cache. Clear the
13
+ # SessionRegistry at the start of these tests in order to detect leaks that
14
+ # occur only within the scope of these tests.
15
+ #
16
+ # Other session leaks will be detected and addressed as part of RUBY-2391.
17
+ SessionRegistry.instance.clear_registry
18
+ end
19
+
20
+ after do
21
+ SessionRegistry.instance.verify_sessions_ended!
22
+ end
23
+
10
24
  context 'when iterating over objects sharing the same base' do
11
25
 
12
26
  let(:server) do
@@ -38,9 +52,10 @@ describe Mongoid::QueryCache do
38
52
  end
39
53
 
40
54
  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
55
+ expect_query(relations.size) do
56
+ relations.each do |object|
57
+ object.person
58
+ end
44
59
  end
45
60
  end
46
61
  end
@@ -52,9 +67,10 @@ describe Mongoid::QueryCache do
52
67
  end
53
68
 
54
69
  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
70
+ expect_query(1) do
71
+ relations.each do |object|
72
+ object.person
73
+ end
58
74
  end
59
75
  end
60
76
  end
@@ -205,6 +221,10 @@ describe Mongoid::QueryCache do
205
221
  end
206
222
 
207
223
  before do
224
+ 10.times do |i|
225
+ game.ratings << Rating.create!(value: i+1)
226
+ end
227
+
208
228
  game.ratings.where(:value.gt => 5).asc(:id).all.to_a
209
229
  end
210
230
 
@@ -212,7 +232,9 @@ describe Mongoid::QueryCache do
212
232
 
213
233
  it "uses the cache" do
214
234
  expect_no_queries do
215
- game.ratings.where(:value.gt => 5).limit(2).asc(:id).to_a
235
+ result = game.ratings.where(:value.gt => 5).limit(2).asc(:id).to_a
236
+ expect(result.length).to eq(2)
237
+ expect(result.map { |r| r['value'] }).to eq([6, 7])
216
238
  end
217
239
  end
218
240
  end
@@ -225,14 +247,23 @@ describe Mongoid::QueryCache do
225
247
  end
226
248
 
227
249
  before do
250
+ 10.times do |i|
251
+ game.ratings << Rating.create!(value: i+1)
252
+ end
253
+
228
254
  game.ratings.where(:value.gt => 5).limit(3).asc(:id).all.to_a
229
255
  end
230
256
 
231
257
  context "when the next query has a limit" do
258
+ # Server versions older than 3.2 also perform a killCursors operation,
259
+ # which causes this test to fail.
260
+ min_server_version '3.2'
232
261
 
233
262
  it "queries again" do
234
263
  expect_query(1) do
235
- game.ratings.where(:value.gt => 5).limit(2).asc(:id).to_a
264
+ result = game.ratings.where(:value.gt => 5).limit(2).asc(:id).to_a
265
+ expect(result.length).to eq(2)
266
+ expect(result.map { |r| r['value'] }).to eq([6, 7])
236
267
  end
237
268
  end
238
269
  end
@@ -241,7 +272,9 @@ describe Mongoid::QueryCache do
241
272
 
242
273
  it "queries again" do
243
274
  expect_query(1) do
244
- game.ratings.where(:value.gt => 5).asc(:id).to_a
275
+ result = game.ratings.where(:value.gt => 5).asc(:id).to_a
276
+ expect(result.length).to eq(5)
277
+ expect(result.map { |r| r['value'] }).to eq([6, 7, 8, 9, 10])
245
278
  end
246
279
  end
247
280
  end
@@ -254,21 +287,34 @@ describe Mongoid::QueryCache do
254
287
  end
255
288
 
256
289
  before do
290
+ 10.times do |i|
291
+ game.ratings << Rating.create!(value: i+1)
292
+ end
293
+
257
294
  game.ratings.where(:value.gt => 5).asc(:id).all.to_a
258
295
  end
259
296
 
260
297
  it "does not query again" do
261
298
  expect_no_queries do
262
- game.ratings.where(:value.gt => 5).asc(:id).first
299
+ result = game.ratings.where(:value.gt => 5).asc(:id).first
300
+ expect(result['value']).to eq(6)
263
301
  end
264
302
  end
265
303
  end
266
304
 
267
305
  context "when limiting the result" do
306
+ before do
307
+ Band.destroy_all
308
+
309
+ 5.times { |i| Band.create!(name: "Band #{i}") }
310
+ Band.all.to_a
311
+ end
268
312
 
269
313
  it "does not query again" do
270
314
  expect_query(0) do
271
- Band.limit(2).all.to_a
315
+ result = Band.limit(2).all.to_a
316
+ expect(result.length).to eq(2)
317
+ expect(result.map { |r| r["name"] }).to eq(["Band 0", "Band 1"])
272
318
  end
273
319
  end
274
320
  end
@@ -276,12 +322,16 @@ describe Mongoid::QueryCache do
276
322
  context "when specifying a different skip value" do
277
323
 
278
324
  before do
279
- Band.limit(2).skip(1).all.to_a
325
+ Band.destroy_all
326
+
327
+ 5.times { |i| Band.create!(name: "Band #{i}") }
280
328
  end
281
329
 
282
330
  it "queries again" do
283
331
  expect_query(1) do
284
- Band.limit(2).skip(3).all.to_a
332
+ result = Band.limit(2).skip(3).all.to_a
333
+ expect(result.length).to eq(2)
334
+ expect(result.map { |r| r["name"] }).to eq(["Band 3", "Band 4"])
285
335
  end
286
336
  end
287
337
  end
@@ -317,6 +367,25 @@ describe Mongoid::QueryCache do
317
367
  end
318
368
  end
319
369
 
370
+ context 'when querying colleciton larger than the batch size' do
371
+ before do
372
+ Band.destroy_all
373
+ 101.times { |i| Band.create!(_id: i) }
374
+ end
375
+
376
+ it 'does not raise an exception when querying multiple times' do
377
+ expect do
378
+ results1 = Band.all.to_a
379
+ expect(results1.length).to eq(101)
380
+ expect(results1.map { |band| band["_id"] }).to eq([*0..100])
381
+
382
+ results2 = Band.all.to_a
383
+ expect(results2.length).to eq(101)
384
+ expect(results2.map { |band| band["_id"] }).to eq([*0..100])
385
+ end.not_to raise_error
386
+ end
387
+ end
388
+
320
389
  context "when query caching is enabled and the batch_size is set" do
321
390
 
322
391
  around(:each) do |example|
@@ -428,15 +497,15 @@ describe Mongoid::QueryCache do
428
497
  context "when querying a very large collection" do
429
498
 
430
499
  before do
431
- 123.times { Band.create! }
500
+ 100.times { Band.create! }
432
501
  end
433
502
 
434
503
  it "returns the right number of records" do
435
- expect(Band.all.to_a.length).to eq(123)
504
+ expect(Band.all.to_a.length).to eq(100)
436
505
  end
437
506
 
438
507
  it "#pluck returns the same count of objects" do
439
- expect(Band.pluck(:name).length).to eq(123)
508
+ expect(Band.pluck(:name).length).to eq(100)
440
509
  end
441
510
 
442
511
  context "when loading all the documents" do
@@ -447,12 +516,12 @@ describe Mongoid::QueryCache do
447
516
 
448
517
  it "caches the complete result of the query" do
449
518
  expect_no_queries do
450
- expect(Band.all.to_a.length).to eq(123)
519
+ expect(Band.all.to_a.length).to eq(100)
451
520
  end
452
521
  end
453
522
 
454
523
  it "returns the same count of objects when using #pluck" do
455
- expect(Band.pluck(:name).length).to eq(123)
524
+ expect(Band.pluck(:name).length).to eq(100)
456
525
  end
457
526
  end
458
527
  end
@@ -1130,6 +1130,19 @@ describe Mongoid::Scopable do
1130
1130
  it "sets the threading options" do
1131
1131
  Band.without_default_scope do
1132
1132
  expect(Mongoid::Threaded).to be_executing(:without_default_scope)
1133
+ expect(Mongoid::Threaded.without_default_scope?(Band)).to be(true)
1134
+ end
1135
+ end
1136
+
1137
+ it "suppresses default scope on the given model within the given block" do
1138
+ Appointment.without_default_scope do
1139
+ expect(Appointment.all.selector).to be_empty
1140
+ end
1141
+ end
1142
+
1143
+ it "does not affect other models' default scopes within the given block" do
1144
+ Appointment.without_default_scope do
1145
+ expect(Audio.all.selector).not_to be_empty
1133
1146
  end
1134
1147
  end
1135
1148
  end
@@ -233,4 +233,72 @@ describe Mongoid::Threaded do
233
233
  end
234
234
  end
235
235
  end
236
+
237
+ describe "#begin_without_default_scope" do
238
+
239
+ let(:klass) do
240
+ Appointment
241
+ end
242
+
243
+ after do
244
+ described_class.exit_without_default_scope(klass)
245
+ end
246
+
247
+ it "adds the given class to the without_default_scope stack" do
248
+ described_class.begin_without_default_scope(klass)
249
+
250
+ expect(described_class.stack(:without_default_scope)).to include(klass)
251
+ end
252
+ end
253
+
254
+ describe "#exit_without_default_scope" do
255
+
256
+ let(:klass) do
257
+ Appointment
258
+ end
259
+
260
+ before do
261
+ described_class.begin_without_default_scope(klass)
262
+ end
263
+
264
+ it "removes the given class from the without_default_scope stack" do
265
+ described_class.exit_without_default_scope(klass)
266
+
267
+ expect(described_class.stack(:without_default_scope)).not_to include(klass)
268
+ end
269
+ end
270
+
271
+ describe "#without_default_scope?" do
272
+
273
+ let(:klass) do
274
+ Appointment
275
+ end
276
+
277
+ context "when klass has begun without_default_scope" do
278
+
279
+ before do
280
+ described_class.begin_without_default_scope(klass)
281
+ end
282
+
283
+ after do
284
+ described_class.exit_without_default_scope(klass)
285
+ end
286
+
287
+ it "returns true" do
288
+ expect(described_class.without_default_scope?(klass)).to be(true)
289
+ end
290
+ end
291
+
292
+ context "when klass has exited without_default_scope" do
293
+
294
+ before do
295
+ described_class.begin_without_default_scope(klass)
296
+ described_class.exit_without_default_scope(klass)
297
+ end
298
+
299
+ it "returns false" do
300
+ expect(described_class.without_default_scope?(klass)).to be(false)
301
+ end
302
+ end
303
+ end
236
304
  end
@@ -0,0 +1,110 @@
1
+ require "spec_helper"
2
+ require "mongoid/railties/controller_runtime"
3
+
4
+ describe "Mongoid::Railties::ControllerRuntime" do
5
+ controller_runtime = Mongoid::Railties::ControllerRuntime
6
+ collector = controller_runtime::Collector
7
+
8
+ def set_metric value
9
+ Thread.current["Mongoid.controller_runtime"] = value
10
+ end
11
+
12
+ def clear_metric!
13
+ set_metric 0
14
+ end
15
+
16
+ describe "Collector" do
17
+
18
+ it "stores the metric in thread-safe manner" do
19
+ clear_metric!
20
+ expect(collector.runtime).to eq(0)
21
+ set_metric 42
22
+ expect(collector.runtime).to eq(42)
23
+ end
24
+
25
+ it "sets metric on both succeeded and failed" do
26
+ instance = collector.new
27
+ event_payload = OpenStruct.new duration: 42
28
+
29
+ clear_metric!
30
+ instance.succeeded event_payload
31
+ expect(collector.runtime).to eq(42)
32
+
33
+ clear_metric!
34
+ instance.failed event_payload
35
+ expect(collector.runtime).to eq(42)
36
+ end
37
+
38
+ it "resets the metric and returns the value" do
39
+ clear_metric!
40
+ expect(collector.reset_runtime).to eq(0)
41
+ set_metric 42
42
+ expect(collector.reset_runtime).to eq(42)
43
+ expect(collector.runtime).to eq(0)
44
+ end
45
+
46
+ end
47
+
48
+ reference_controller_class = Class.new do
49
+ def process_action *_
50
+ @process_action = true
51
+ end
52
+
53
+ def cleanup_view_runtime *_
54
+ @cleanup_view_runtime.call
55
+ end
56
+
57
+ def append_info_to_payload *_
58
+ @append_info_to_payload = true
59
+ end
60
+
61
+ def self.log_process_action *_
62
+ @log_process_action.call
63
+ end
64
+ end
65
+
66
+ controller_class = Class.new reference_controller_class do
67
+ include controller_runtime::ControllerExtension
68
+ end
69
+
70
+ let(:controller){ controller_class.new }
71
+
72
+ it "resets the metric before each action" do
73
+ set_metric 42
74
+ controller.send(:process_action, 'foo')
75
+ expect(collector.runtime).to be(0)
76
+ expect(controller.instance_variable_get "@process_action").to be(true)
77
+ end
78
+
79
+ it "strips the metric of other sources of the runtime" do
80
+ set_metric 1
81
+ controller.instance_variable_set "@cleanup_view_runtime", ->{
82
+ controller.instance_variable_set "@cleanup_view_runtime", true
83
+ set_metric 13
84
+ 42
85
+ }
86
+ returned = controller.send :cleanup_view_runtime
87
+ expect(controller.instance_variable_get "@cleanup_view_runtime").to be(true)
88
+ expect(controller.mongoid_runtime).to eq(14)
89
+ expect(returned).to be(29)
90
+ end
91
+
92
+ it "appends the metric to payload" do
93
+ payload = {}
94
+ set_metric 42
95
+ controller.send :append_info_to_payload, payload
96
+ expect(controller.instance_variable_get "@append_info_to_payload").to be(true)
97
+ expect(payload[:mongoid_runtime]).to eq(42)
98
+ end
99
+
100
+ it "adds metric to log message" do
101
+ controller_class.instance_variable_set "@log_process_action", ->{
102
+ controller_class.instance_variable_set "@log_process_action", true
103
+ []
104
+ }
105
+ messages = controller_class.log_process_action mongoid_runtime: 42.101
106
+ expect(controller_class.instance_variable_get "@log_process_action").to be(true)
107
+ expect(messages).to eq(["MongoDB: 42.1ms"])
108
+ end
109
+
110
+ end