mongoid 7.2.0 → 7.3.0

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 (191) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/Rakefile +16 -0
  4. data/lib/config/locales/en.yml +2 -2
  5. data/lib/mongoid/association/accessors.rb +1 -1
  6. data/lib/mongoid/association/constrainable.rb +1 -1
  7. data/lib/mongoid/association/depending.rb +4 -4
  8. data/lib/mongoid/association/embedded/batchable.rb +1 -1
  9. data/lib/mongoid/association/embedded/embedded_in.rb +1 -1
  10. data/lib/mongoid/association/embedded/embeds_many/proxy.rb +10 -3
  11. data/lib/mongoid/association/nested/many.rb +1 -1
  12. data/lib/mongoid/association/nested/one.rb +4 -2
  13. data/lib/mongoid/association/proxy.rb +6 -1
  14. data/lib/mongoid/association/referenced/auto_save.rb +2 -2
  15. data/lib/mongoid/association/referenced/has_many/enumerable.rb +493 -495
  16. data/lib/mongoid/association/referenced/has_many/proxy.rb +2 -2
  17. data/lib/mongoid/association/referenced/has_one/nested_builder.rb +2 -2
  18. data/lib/mongoid/attributes/projector.rb +120 -0
  19. data/lib/mongoid/attributes.rb +32 -14
  20. data/lib/mongoid/cacheable.rb +2 -2
  21. data/lib/mongoid/clients/factory.rb +22 -8
  22. data/lib/mongoid/clients.rb +1 -1
  23. data/lib/mongoid/config.rb +19 -2
  24. data/lib/mongoid/contextual/aggregable/mongo.rb +10 -8
  25. data/lib/mongoid/copyable.rb +1 -1
  26. data/lib/mongoid/criteria/findable.rb +1 -1
  27. data/lib/mongoid/criteria/queryable/expandable.rb +0 -24
  28. data/lib/mongoid/criteria/queryable/extensions/boolean.rb +1 -1
  29. data/lib/mongoid/criteria/queryable/extensions.rb +0 -4
  30. data/lib/mongoid/criteria/queryable/mergeable.rb +46 -20
  31. data/lib/mongoid/criteria/queryable/selectable.rb +8 -8
  32. data/lib/mongoid/criteria/queryable/selector.rb +0 -4
  33. data/lib/mongoid/criteria.rb +4 -5
  34. data/lib/mongoid/document.rb +4 -17
  35. data/lib/mongoid/errors/delete_restriction.rb +8 -9
  36. data/lib/mongoid/evolvable.rb +1 -1
  37. data/lib/mongoid/extensions/boolean.rb +1 -2
  38. data/lib/mongoid/extensions/false_class.rb +1 -1
  39. data/lib/mongoid/extensions/hash.rb +2 -2
  40. data/lib/mongoid/extensions/true_class.rb +1 -1
  41. data/lib/mongoid/fields.rb +43 -5
  42. data/lib/mongoid/inspectable.rb +1 -1
  43. data/lib/mongoid/interceptable.rb +3 -1
  44. data/lib/mongoid/matcher/bits.rb +41 -0
  45. data/lib/mongoid/matcher/bits_all_clear.rb +20 -0
  46. data/lib/mongoid/matcher/bits_all_set.rb +20 -0
  47. data/lib/mongoid/matcher/bits_any_clear.rb +20 -0
  48. data/lib/mongoid/matcher/bits_any_set.rb +20 -0
  49. data/lib/mongoid/matcher/elem_match.rb +2 -1
  50. data/lib/mongoid/matcher/expression.rb +9 -14
  51. data/lib/mongoid/matcher/field_expression.rb +4 -5
  52. data/lib/mongoid/matcher/field_operator.rb +13 -11
  53. data/lib/mongoid/matcher/mod.rb +17 -0
  54. data/lib/mongoid/matcher/type.rb +99 -0
  55. data/lib/mongoid/matcher.rb +26 -43
  56. data/lib/mongoid/persistable/deletable.rb +1 -2
  57. data/lib/mongoid/persistable/destroyable.rb +8 -2
  58. data/lib/mongoid/persistable/updatable.rb +27 -2
  59. data/lib/mongoid/query_cache.rb +35 -29
  60. data/lib/mongoid/reloadable.rb +5 -0
  61. data/lib/mongoid/selectable.rb +5 -7
  62. data/lib/mongoid/shardable.rb +21 -5
  63. data/lib/mongoid/touchable.rb +23 -4
  64. data/lib/mongoid/version.rb +1 -1
  65. data/lib/rails/generators/mongoid/config/config_generator.rb +8 -1
  66. data/spec/integration/app_spec.rb +171 -84
  67. data/spec/integration/associations/embeds_many_spec.rb +44 -0
  68. data/spec/integration/associations/has_one_spec.rb +48 -0
  69. data/spec/integration/callbacks_models.rb +49 -0
  70. data/spec/integration/callbacks_spec.rb +216 -0
  71. data/spec/integration/criteria/date_field_spec.rb +1 -1
  72. data/spec/integration/document_spec.rb +30 -0
  73. data/spec/integration/matcher_operator_data/bits_all_clear.yml +159 -0
  74. data/spec/integration/matcher_operator_data/bits_all_set.yml +159 -0
  75. data/spec/integration/matcher_operator_data/bits_any_clear.yml +159 -0
  76. data/spec/integration/matcher_operator_data/bits_any_set.yml +159 -0
  77. data/spec/integration/matcher_operator_data/comment.yml +22 -0
  78. data/spec/integration/matcher_operator_data/elem_match.yml +46 -0
  79. data/spec/integration/matcher_operator_data/gt_types.yml +63 -0
  80. data/spec/integration/matcher_operator_data/gte_types.yml +15 -0
  81. data/spec/integration/matcher_operator_data/implicit_traversal.yml +96 -0
  82. data/spec/integration/matcher_operator_data/in.yml +16 -0
  83. data/spec/integration/matcher_operator_data/lt_types.yml +15 -0
  84. data/spec/integration/matcher_operator_data/lte_types.yml +15 -0
  85. data/spec/integration/matcher_operator_data/mod.yml +55 -0
  86. data/spec/integration/matcher_operator_data/ne_types.yml +15 -0
  87. data/spec/integration/matcher_operator_data/type.yml +70 -0
  88. data/spec/integration/matcher_operator_data/type_array.yml +16 -0
  89. data/spec/integration/matcher_operator_data/type_binary.yml +18 -0
  90. data/spec/integration/matcher_operator_data/type_boolean.yml +39 -0
  91. data/spec/integration/matcher_operator_data/type_code.yml +26 -0
  92. data/spec/integration/matcher_operator_data/type_code_with_scope.yml +26 -0
  93. data/spec/integration/matcher_operator_data/type_date.yml +39 -0
  94. data/spec/integration/matcher_operator_data/type_db_pointer.yml +19 -0
  95. data/spec/integration/matcher_operator_data/type_decimal.yml +40 -0
  96. data/spec/integration/matcher_operator_data/type_double.yml +15 -0
  97. data/spec/integration/matcher_operator_data/type_int32.yml +33 -0
  98. data/spec/integration/matcher_operator_data/type_int64.yml +33 -0
  99. data/spec/integration/matcher_operator_data/type_max_key.yml +17 -0
  100. data/spec/integration/matcher_operator_data/type_min_key.yml +17 -0
  101. data/spec/integration/matcher_operator_data/type_null.yml +23 -0
  102. data/spec/integration/matcher_operator_data/type_object.yml +23 -0
  103. data/spec/integration/matcher_operator_data/type_object_id.yml +25 -0
  104. data/spec/integration/matcher_operator_data/type_regex.yml +44 -0
  105. data/spec/integration/matcher_operator_data/type_string.yml +15 -0
  106. data/spec/integration/matcher_operator_data/type_symbol.yml +32 -0
  107. data/spec/integration/matcher_operator_data/type_timestamp.yml +25 -0
  108. data/spec/integration/matcher_operator_data/type_undefined.yml +17 -0
  109. data/spec/lite_spec_helper.rb +5 -4
  110. data/spec/mongoid/association/depending_spec.rb +391 -352
  111. data/spec/mongoid/association/embedded/embedded_in/proxy_spec.rb +50 -0
  112. data/spec/mongoid/association/nested/one_spec.rb +18 -14
  113. data/spec/mongoid/association/referenced/belongs_to/proxy_spec.rb +25 -8
  114. data/spec/mongoid/association/referenced/has_and_belongs_to_many/binding_spec.rb +1 -1
  115. data/spec/mongoid/association/referenced/has_many/binding_spec.rb +1 -1
  116. data/spec/mongoid/association/referenced/has_many/enumerable_spec.rb +1 -1
  117. data/spec/mongoid/association/referenced/has_one_models.rb +8 -0
  118. data/spec/mongoid/atomic/paths_spec.rb +105 -12
  119. data/spec/mongoid/attributes/projector_data/embedded.yml +105 -0
  120. data/spec/mongoid/attributes/projector_data/fields.yml +93 -0
  121. data/spec/mongoid/attributes/projector_spec.rb +41 -0
  122. data/spec/mongoid/attributes_spec.rb +333 -0
  123. data/spec/mongoid/clients/factory_spec.rb +48 -0
  124. data/spec/mongoid/config_spec.rb +32 -0
  125. data/spec/mongoid/contextual/atomic_spec.rb +17 -4
  126. data/spec/mongoid/contextual/mongo_spec.rb +2 -2
  127. data/spec/mongoid/criteria/modifiable_spec.rb +1 -1
  128. data/spec/mongoid/criteria/queryable/expandable_spec.rb +0 -73
  129. data/spec/mongoid/criteria/queryable/extensions/boolean_spec.rb +1 -1
  130. data/spec/mongoid/criteria/queryable/mergeable_spec.rb +105 -7
  131. data/spec/mongoid/criteria/queryable/selectable_logical_spec.rb +265 -24
  132. data/spec/mongoid/criteria/queryable/selectable_shared_examples.rb +39 -0
  133. data/spec/mongoid/criteria/queryable/selectable_spec.rb +1 -565
  134. data/spec/mongoid/criteria/queryable/selectable_where_spec.rb +590 -0
  135. data/spec/mongoid/criteria_projection_spec.rb +411 -0
  136. data/spec/mongoid/criteria_spec.rb +0 -275
  137. data/spec/mongoid/document_fields_spec.rb +26 -0
  138. data/spec/mongoid/document_spec.rb +13 -13
  139. data/spec/mongoid/errors/delete_restriction_spec.rb +1 -1
  140. data/spec/mongoid/extensions/false_class_spec.rb +1 -1
  141. data/spec/mongoid/extensions/string_spec.rb +5 -5
  142. data/spec/mongoid/extensions/true_class_spec.rb +1 -1
  143. data/spec/mongoid/fields/localized_spec.rb +4 -4
  144. data/spec/mongoid/fields_spec.rb +4 -4
  145. data/spec/mongoid/inspectable_spec.rb +12 -4
  146. data/spec/mongoid/matcher/extract_attribute_data/numeric_keys.yml +104 -0
  147. data/spec/mongoid/matcher/extract_attribute_data/traversal.yml +68 -88
  148. data/spec/mongoid/matcher/extract_attribute_spec.rb +3 -13
  149. data/spec/mongoid/persistable/deletable_spec.rb +175 -1
  150. data/spec/mongoid/persistable/destroyable_spec.rb +191 -3
  151. data/spec/mongoid/persistable/savable_spec.rb +3 -5
  152. data/spec/mongoid/persistable/settable_spec.rb +30 -0
  153. data/spec/mongoid/persistable/upsertable_spec.rb +1 -1
  154. data/spec/mongoid/query_cache_middleware_spec.rb +8 -0
  155. data/spec/mongoid/reloadable_spec.rb +18 -1
  156. data/spec/mongoid/shardable_spec.rb +44 -0
  157. data/spec/mongoid/touchable_spec.rb +104 -16
  158. data/spec/mongoid/touchable_spec_models.rb +52 -0
  159. data/spec/mongoid/validatable_spec.rb +1 -1
  160. data/spec/shared/bin/get-mongodb-download-url +17 -0
  161. data/spec/shared/lib/mrss/cluster_config.rb +221 -0
  162. data/spec/shared/lib/mrss/constraints.rb +51 -0
  163. data/spec/shared/lib/mrss/docker_runner.rb +265 -0
  164. data/spec/shared/lib/mrss/lite_constraints.rb +16 -0
  165. data/spec/shared/lib/mrss/server_version_registry.rb +115 -0
  166. data/spec/shared/lib/mrss/spec_organizer.rb +14 -1
  167. data/spec/shared/lib/mrss/utils.rb +15 -0
  168. data/spec/shared/share/Dockerfile.erb +231 -0
  169. data/spec/shared/shlib/distro.sh +73 -0
  170. data/spec/shared/shlib/server.sh +290 -0
  171. data/spec/shared/shlib/set_env.sh +128 -0
  172. data/spec/spec_helper.rb +6 -2
  173. data/spec/support/client_registry.rb +9 -0
  174. data/spec/support/models/bolt.rb +8 -0
  175. data/spec/support/models/customer.rb +11 -0
  176. data/spec/support/models/customer_address.rb +12 -0
  177. data/spec/support/models/dictionary.rb +6 -0
  178. data/spec/support/models/hole.rb +13 -0
  179. data/spec/support/models/mop.rb +9 -0
  180. data/spec/support/models/nut.rb +8 -0
  181. data/spec/support/models/person.rb +6 -0
  182. data/spec/support/models/sealer.rb +8 -0
  183. data/spec/support/models/shirt.rb +12 -0
  184. data/spec/support/models/spacer.rb +8 -0
  185. data/spec/support/models/threadlocker.rb +8 -0
  186. data/spec/support/models/washer.rb +8 -0
  187. data/spec/support/spec_config.rb +8 -0
  188. data.tar.gz.sig +0 -0
  189. metadata +146 -14
  190. metadata.gz.sig +5 -2
  191. data/spec/support/cluster_config.rb +0 -158
@@ -8,7 +8,7 @@ describe Mongoid::Persistable::Deletable do
8
8
  describe "#delete" do
9
9
 
10
10
  let!(:person) do
11
- Person.create
11
+ Person.create!
12
12
  end
13
13
 
14
14
  context "when deleting a readonly document" do
@@ -24,6 +24,20 @@ describe Mongoid::Persistable::Deletable do
24
24
  end
25
25
  end
26
26
 
27
+ context 'when deleting a document that was not saved' do
28
+ let(:unsaved_person) { Person.new(id: person.id) }
29
+
30
+ before do
31
+ unsaved_person.delete
32
+ end
33
+
34
+ it 'deletes the matching document from the database' do
35
+ lambda do
36
+ person.reload
37
+ end.should raise_error(Mongoid::Errors::DocumentNotFound)
38
+ end
39
+ end
40
+
27
41
  context "when removing a root document" do
28
42
 
29
43
  let!(:deleted) do
@@ -259,6 +273,86 @@ describe Mongoid::Persistable::Deletable do
259
273
  expect(Browser.count).to eq(1)
260
274
  end
261
275
  end
276
+
277
+ context 'when there are dependent documents' do
278
+ context 'has_one' do
279
+
280
+ context 'dependent: :destroy' do
281
+ let!(:parent) do
282
+ Hole.create!(bolt: Bolt.create!)
283
+ end
284
+
285
+ it 'does not destroy dependent documents' do
286
+ Bolt.count.should == 1
287
+ parent.delete
288
+ Bolt.count.should == 1
289
+ end
290
+ end
291
+
292
+ context 'dependent: :delete_all' do
293
+ let!(:parent) do
294
+ Hole.create!(threadlocker: Threadlocker.create!)
295
+ end
296
+
297
+ it 'does not destroy dependent documents' do
298
+ Threadlocker.count.should == 1
299
+ parent.delete
300
+ Threadlocker.count.should == 1
301
+ end
302
+ end
303
+
304
+ context 'dependent: :restrict_with_exception' do
305
+ let!(:parent) do
306
+ Hole.create!(sealer: Sealer.create!)
307
+ end
308
+
309
+ it 'does not destroy dependent documents' do
310
+ Sealer.count.should == 1
311
+ parent.delete
312
+ Sealer.count.should == 1
313
+ end
314
+ end
315
+ end
316
+
317
+ context 'has_many' do
318
+
319
+ context 'dependent: :destroy' do
320
+ let!(:parent) do
321
+ Hole.create!(nuts: [Nut.create!])
322
+ end
323
+
324
+ it 'does not destroy dependent documents' do
325
+ Nut.count.should == 1
326
+ parent.delete
327
+ Nut.count.should == 1
328
+ end
329
+ end
330
+
331
+ context 'dependent: :delete_all' do
332
+ let!(:parent) do
333
+ Hole.create!(washers: [Washer.create!])
334
+ end
335
+
336
+ it 'does not destroy dependent documents' do
337
+ Washer.count.should == 1
338
+ parent.delete
339
+ Washer.count.should == 1
340
+ end
341
+ end
342
+
343
+ context 'dependent: :restrict_with_exception' do
344
+ let!(:parent) do
345
+ Hole.create!(spacers: [Spacer.create!])
346
+ end
347
+
348
+ it 'does not destroy dependent documents' do
349
+ Spacer.count.should == 1
350
+ parent.delete
351
+ Spacer.count.should == 1
352
+ end
353
+ end
354
+ end
355
+ end
262
356
  end
263
357
 
264
358
  describe "#delete_all" do
@@ -337,5 +431,85 @@ describe Mongoid::Persistable::Deletable do
337
431
  end
338
432
  end
339
433
  end
434
+
435
+ context 'when there are dependent documents' do
436
+ context 'has_one' do
437
+
438
+ context 'dependent: :destroy' do
439
+ let!(:parent) do
440
+ Hole.create!(bolt: Bolt.create!)
441
+ end
442
+
443
+ it 'does not destroy dependent documents' do
444
+ Bolt.count.should == 1
445
+ Hole.delete_all
446
+ Bolt.count.should == 1
447
+ end
448
+ end
449
+
450
+ context 'dependent: :delete_all' do
451
+ let!(:parent) do
452
+ Hole.create!(threadlocker: Threadlocker.create!)
453
+ end
454
+
455
+ it 'does not destroy dependent documents' do
456
+ Threadlocker.count.should == 1
457
+ Hole.delete_all
458
+ Threadlocker.count.should == 1
459
+ end
460
+ end
461
+
462
+ context 'dependent: :restrict_with_exception' do
463
+ let!(:parent) do
464
+ Hole.create!(sealer: Sealer.create!)
465
+ end
466
+
467
+ it 'does not destroy dependent documents' do
468
+ Sealer.count.should == 1
469
+ Hole.delete_all
470
+ Sealer.count.should == 1
471
+ end
472
+ end
473
+ end
474
+
475
+ context 'has_many' do
476
+
477
+ context 'dependent: :destroy' do
478
+ let!(:parent) do
479
+ Hole.create!(nuts: [Nut.create!])
480
+ end
481
+
482
+ it 'does not destroy dependent documents' do
483
+ Nut.count.should == 1
484
+ Hole.delete_all
485
+ Nut.count.should == 1
486
+ end
487
+ end
488
+
489
+ context 'dependent: :delete_all' do
490
+ let!(:parent) do
491
+ Hole.create!(washers: [Washer.create!])
492
+ end
493
+
494
+ it 'does not destroy dependent documents' do
495
+ Washer.count.should == 1
496
+ Hole.delete_all
497
+ Washer.count.should == 1
498
+ end
499
+ end
500
+
501
+ context 'dependent: :restrict_with_exception' do
502
+ let!(:parent) do
503
+ Hole.create!(spacers: [Spacer.create!])
504
+ end
505
+
506
+ it 'does not destroy dependent documents' do
507
+ Spacer.count.should == 1
508
+ Hole.delete_all
509
+ Spacer.count.should == 1
510
+ end
511
+ end
512
+ end
513
+ end
340
514
  end
341
515
  end
@@ -8,7 +8,7 @@ describe Mongoid::Persistable::Destroyable do
8
8
  describe "#destroy" do
9
9
 
10
10
  let!(:person) do
11
- Person.create
11
+ Person.create!
12
12
  end
13
13
 
14
14
  context "when destroying a readonly document" do
@@ -24,9 +24,23 @@ describe Mongoid::Persistable::Destroyable do
24
24
  end
25
25
  end
26
26
 
27
+ context 'when destroying a document that was not saved' do
28
+ let(:unsaved_person) { Person.new(id: person.id) }
29
+
30
+ before do
31
+ unsaved_person.destroy
32
+ end
33
+
34
+ it 'deletes the matching document from the database' do
35
+ lambda do
36
+ person.reload
37
+ end.should raise_error(Mongoid::Errors::DocumentNotFound)
38
+ end
39
+ end
40
+
27
41
  context "when removing a root document" do
28
42
 
29
- let!(:destroyd) do
43
+ let!(:destroyed) do
30
44
  person.destroy
31
45
  end
32
46
 
@@ -37,7 +51,7 @@ describe Mongoid::Persistable::Destroyable do
37
51
  end
38
52
 
39
53
  it "returns true" do
40
- expect(destroyd).to be true
54
+ expect(destroyed).to be true
41
55
  end
42
56
 
43
57
  it "resets the flagged for destroy flag" do
@@ -145,6 +159,90 @@ describe Mongoid::Persistable::Destroyable do
145
159
  end
146
160
  end
147
161
  end
162
+
163
+ context 'when there are dependent documents' do
164
+ context 'has_one' do
165
+
166
+ context 'dependent: :destroy' do
167
+ let!(:parent) do
168
+ Hole.create!(bolt: Bolt.create!)
169
+ end
170
+
171
+ it 'destroys dependent documents' do
172
+ Bolt.count.should == 1
173
+ parent.destroy
174
+ Bolt.count.should == 0
175
+ end
176
+ end
177
+
178
+ context 'dependent: :destroy_all' do
179
+ let!(:parent) do
180
+ Hole.create!(threadlocker: Threadlocker.create!)
181
+ end
182
+
183
+ it 'deletes dependent documents' do
184
+ Threadlocker.count.should == 1
185
+ parent.destroy
186
+ Threadlocker.count.should == 0
187
+ end
188
+ end
189
+
190
+ context 'dependent: :restrict_with_exception' do
191
+ let!(:parent) do
192
+ Hole.create!(sealer: Sealer.create!)
193
+ end
194
+
195
+ it 'raises an exception' do
196
+ Sealer.count.should == 1
197
+ lambda do
198
+ parent.destroy
199
+ end.should raise_error(Mongoid::Errors::DeleteRestriction)
200
+ Sealer.count.should == 1
201
+ end
202
+ end
203
+ end
204
+
205
+ context 'has_many' do
206
+
207
+ context 'dependent: :destroy' do
208
+ let!(:parent) do
209
+ Hole.create!(nuts: [Nut.create!])
210
+ end
211
+
212
+ it 'destroys dependent documents' do
213
+ Nut.count.should == 1
214
+ parent.destroy
215
+ Nut.count.should == 0
216
+ end
217
+ end
218
+
219
+ context 'dependent: :destroy_all' do
220
+ let!(:parent) do
221
+ Hole.create!(washers: [Washer.create!])
222
+ end
223
+
224
+ it 'deletes dependent documents' do
225
+ Washer.count.should == 1
226
+ parent.destroy
227
+ Washer.count.should == 0
228
+ end
229
+ end
230
+
231
+ context 'dependent: :restrict_with_exception' do
232
+ let!(:parent) do
233
+ Hole.create!(spacers: [Spacer.create!])
234
+ end
235
+
236
+ it 'raises an exception' do
237
+ Spacer.count.should == 1
238
+ lambda do
239
+ parent.destroy
240
+ end.should raise_error(Mongoid::Errors::DeleteRestriction)
241
+ Spacer.count.should == 1
242
+ end
243
+ end
244
+ end
245
+ end
148
246
  end
149
247
 
150
248
  describe "#destroy!" do
@@ -264,5 +362,95 @@ describe Mongoid::Persistable::Destroyable do
264
362
  end
265
363
  end
266
364
  end
365
+
366
+ context 'when there are dependent documents' do
367
+ context 'has_one' do
368
+
369
+ context 'dependent: :destroy' do
370
+ let!(:parent) do
371
+ Hole.create!.tap do |hole|
372
+ Bolt.create!(hole: hole)
373
+ end
374
+ end
375
+
376
+ it 'destroys dependent documents' do
377
+ Bolt.count.should == 1
378
+ Hole.destroy_all
379
+ Bolt.count.should == 0
380
+ end
381
+ end
382
+
383
+ context 'dependent: :delete_all' do
384
+ let!(:parent) do
385
+ Hole.create!.tap do |hole|
386
+ Threadlocker.create!(hole: hole)
387
+ end
388
+ end
389
+
390
+ it 'deletes dependent documents' do
391
+ Threadlocker.count.should == 1
392
+ Hole.destroy_all
393
+ Threadlocker.count.should == 0
394
+ end
395
+ end
396
+
397
+ context 'dependent: :restrict_with_exception' do
398
+ let!(:parent) do
399
+ Hole.create!.tap do |hole|
400
+ Sealer.create!(hole: hole)
401
+ end
402
+ end
403
+
404
+ it 'raises an exception' do
405
+ Sealer.count.should == 1
406
+ lambda do
407
+ Hole.destroy_all
408
+ end.should raise_error(Mongoid::Errors::DeleteRestriction)
409
+ Sealer.count.should == 1
410
+ end
411
+ end
412
+ end
413
+
414
+ context 'has_many' do
415
+
416
+ context 'dependent: :destroy' do
417
+ let!(:parent) do
418
+ Hole.create!(nuts: [Nut.create!])
419
+ end
420
+
421
+ it 'destroys dependent documents' do
422
+ Nut.count.should == 1
423
+ Hole.destroy_all
424
+ Nut.count.should == 0
425
+ end
426
+ end
427
+
428
+ context 'dependent: :delete_all' do
429
+ let!(:parent) do
430
+ Hole.create!(washers: [Washer.create!])
431
+ end
432
+
433
+ it 'deletes dependent documents' do
434
+ Washer.count.should == 1
435
+ Hole.destroy_all
436
+ Washer.count.should == 0
437
+ end
438
+ end
439
+
440
+ context 'dependent: :restrict_with_exception' do
441
+ let!(:parent) do
442
+ Hole.create!(spacers: [Spacer.create!])
443
+ end
444
+
445
+ it 'raises an exception' do
446
+ Spacer.count.should == 1
447
+ lambda do
448
+ Hole.destroy_all
449
+ end.should raise_error(Mongoid::Errors::DeleteRestriction)
450
+ Spacer.count.should == 1
451
+ end
452
+ end
453
+ end
454
+ end
267
455
  end
268
456
  end
@@ -293,6 +293,8 @@ describe Mongoid::Persistable::Savable do
293
293
  expect(truck.crates[1].volume).to eq 0.8
294
294
  expect(truck.crates[1].toys.size).to eq 0
295
295
 
296
+ # TODO: MONGOID-5026: combine the updates so that there are
297
+ # no conflicts.
296
298
  #expect(truck.atomic_updates[:conflicts]).to eq nil
297
299
 
298
300
  expect { truck.save! }.not_to raise_error
@@ -360,8 +362,6 @@ describe Mongoid::Persistable::Savable do
360
362
 
361
363
  context 'when also updating first embedded top level association' do
362
364
  it 'performs all writes' do
363
- pending 'https://jira.mongodb.org/browse/MONGOID-4982'
364
-
365
365
  truck.crates.first.volume = 2
366
366
  truck.crates.first.toys.build(name: 'Bear')
367
367
  truck.crates.build
@@ -397,8 +397,6 @@ describe Mongoid::Persistable::Savable do
397
397
 
398
398
  context 'when embedded association embeds another association' do
399
399
  it 'persists the new documents' do
400
- pending 'https://jira.mongodb.org/browse/MONGOID-4982'
401
-
402
400
  expect(truck.seats.size).to eq 1
403
401
  expect(truck.seats[0].rating).to eq 1
404
402
 
@@ -409,7 +407,7 @@ describe Mongoid::Persistable::Savable do
409
407
 
410
408
  _truck = Truck.find(truck.id)
411
409
  expect(_truck.seats.size).to eq 2
412
- expect(_truck.seats[0].rating).to eq 1
410
+ expect(_truck.seats[0].rating).to eq 2
413
411
  expect(_truck.seats[0].armrests.length).to eq 1
414
412
  expect(_truck.seats[1].rating).to eq 100
415
413
  end
@@ -512,4 +512,34 @@ describe Mongoid::Persistable::Settable do
512
512
  end
513
513
  end
514
514
  end
515
+
516
+ context "when the field being set was projected out" do
517
+ let(:full_agent) do
518
+ Agent.create!(title: "Double-Oh Eight")
519
+ end
520
+
521
+ let(:agent) do
522
+ Agent.where(_id: full_agent.id).only(:dob).first
523
+ end
524
+
525
+ context 'field exists in database' do
526
+ it "raises MissingAttributeError" do
527
+ lambda do
528
+ agent.set(title: '008')
529
+ end.should raise_error(ActiveModel::MissingAttributeError)
530
+
531
+ expect(agent.reload.title).to eq 'Double-Oh Eight'
532
+ end
533
+ end
534
+
535
+ context 'field does not exist in database' do
536
+ it "raises MissingAttributeError" do
537
+ lambda do
538
+ agent.set(number: '008')
539
+ end.should raise_error(ActiveModel::MissingAttributeError)
540
+
541
+ expect(agent.reload.read_attribute(:number)).to be nil
542
+ end
543
+ end
544
+ end
515
545
  end
@@ -32,7 +32,7 @@ describe Mongoid::Persistable::Upsertable do
32
32
  context "when the document is new" do
33
33
 
34
34
  let!(:existing) do
35
- Band.create(name: "Photek")
35
+ Band.create!(name: "Photek")
36
36
  end
37
37
 
38
38
  context "when a matching document exists in the db" do
@@ -58,4 +58,12 @@ describe Mongoid::QueryCache::Middleware do
58
58
  end
59
59
  end
60
60
  end
61
+
62
+ context 'when driver implements query cache middleware' do
63
+ min_driver_version '2.15'
64
+
65
+ it 'uses the driver query cache middleware' do
66
+ Mongoid::QueryCache::Middleware.should be Mongo::QueryCache::Middleware
67
+ end
68
+ end
61
69
  end
@@ -110,7 +110,7 @@ describe Mongoid::Reloadable do
110
110
 
111
111
  context "when document not saved" do
112
112
 
113
- context "when raising not found error" do
113
+ context "when there is no document matching our id" do
114
114
 
115
115
  it "raises an error" do
116
116
  expect {
@@ -118,6 +118,23 @@ describe Mongoid::Reloadable do
118
118
  }.to raise_error(Mongoid::Errors::DocumentNotFound)
119
119
  end
120
120
  end
121
+
122
+ context 'when there is a document matching our id' do
123
+
124
+ let!(:previous) { Agent.create!(title: '007') }
125
+
126
+ let(:agent) { Agent.new(id: previous.id) }
127
+
128
+ it 'loads the existing document' do
129
+ agent.title.should be nil
130
+
131
+ lambda do
132
+ agent.reload
133
+ end.should_not raise_error
134
+
135
+ agent.title.should == '007'
136
+ end
137
+ end
121
138
  end
122
139
 
123
140
  context "when the document is embedded" do
@@ -128,6 +128,50 @@ describe Mongoid::Shardable do
128
128
  end
129
129
  end
130
130
 
131
+ context 'when record is persisted' do
132
+ let(:instance) { klass.create(name: value) }
133
+
134
+ it { is_expected.to eq({ 'name' => value }) }
135
+
136
+ context 'changing shard key value' do
137
+ let(:new_value) { 'a-new-value' }
138
+
139
+ before do
140
+ instance.name = new_value
141
+ end
142
+
143
+ it 'uses the newly set shard key value' do
144
+ subject.should == { 'name' => new_value }
145
+ end
146
+ end
147
+ end
148
+ end
149
+
150
+ describe '#shard_key_selector_in_db' do
151
+ subject { instance.shard_key_selector_in_db }
152
+ let(:klass) { Band }
153
+ let(:value) { 'a-brand-name' }
154
+
155
+ before { klass.shard_key(:name) }
156
+
157
+ context 'when record is new' do
158
+ let(:instance) { klass.new(name: value) }
159
+
160
+ it { is_expected.to eq({ 'name' => value }) }
161
+
162
+ context 'changing shard key value' do
163
+ let(:new_value) { 'a-new-value' }
164
+
165
+ before do
166
+ instance.name = new_value
167
+ end
168
+
169
+ it 'uses the existing shard key value' do
170
+ subject.should == { 'name' => new_value }
171
+ end
172
+ end
173
+ end
174
+
131
175
  context 'when record is persisted' do
132
176
  let(:instance) { klass.create(name: value) }
133
177