mongoid 8.0.5 → 8.1.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 (174) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/CHANGELOG.md +3 -3
  4. data/README.md +3 -3
  5. data/Rakefile +0 -25
  6. data/lib/config/locales/en.yml +46 -14
  7. data/lib/mongoid/association/accessors.rb +2 -2
  8. data/lib/mongoid/association/builders.rb +1 -1
  9. data/lib/mongoid/association/embedded/batchable.rb +2 -2
  10. data/lib/mongoid/association/embedded/embedded_in/buildable.rb +2 -2
  11. data/lib/mongoid/association/embedded/embedded_in/proxy.rb +2 -1
  12. data/lib/mongoid/association/embedded/embeds_many/buildable.rb +3 -2
  13. data/lib/mongoid/association/embedded/embeds_many/proxy.rb +6 -6
  14. data/lib/mongoid/association/embedded/embeds_one/buildable.rb +1 -1
  15. data/lib/mongoid/association/embedded/embeds_one/proxy.rb +1 -1
  16. data/lib/mongoid/association/nested/one.rb +40 -2
  17. data/lib/mongoid/association/proxy.rb +1 -1
  18. data/lib/mongoid/association/referenced/counter_cache.rb +2 -2
  19. data/lib/mongoid/association/referenced/has_and_belongs_to_many/proxy.rb +1 -1
  20. data/lib/mongoid/association/referenced/has_many/enumerable.rb +2 -2
  21. data/lib/mongoid/association/referenced/has_many/proxy.rb +3 -3
  22. data/lib/mongoid/association/reflections.rb +2 -2
  23. data/lib/mongoid/atomic.rb +0 -7
  24. data/lib/mongoid/attributes/dynamic.rb +1 -1
  25. data/lib/mongoid/attributes/nested.rb +2 -2
  26. data/lib/mongoid/attributes/projector.rb +1 -1
  27. data/lib/mongoid/attributes/readonly.rb +1 -1
  28. data/lib/mongoid/attributes.rb +8 -2
  29. data/lib/mongoid/changeable.rb +107 -5
  30. data/lib/mongoid/clients/storage_options.rb +2 -5
  31. data/lib/mongoid/clients/validators/storage.rb +1 -13
  32. data/lib/mongoid/collection_configurable.rb +58 -0
  33. data/lib/mongoid/composable.rb +2 -0
  34. data/lib/mongoid/config/defaults.rb +60 -0
  35. data/lib/mongoid/config/validators/async_query_executor.rb +24 -0
  36. data/lib/mongoid/config/validators.rb +1 -0
  37. data/lib/mongoid/config.rb +101 -0
  38. data/lib/mongoid/contextual/atomic.rb +1 -1
  39. data/lib/mongoid/contextual/memory.rb +233 -33
  40. data/lib/mongoid/contextual/mongo/documents_loader.rb +177 -0
  41. data/lib/mongoid/contextual/mongo.rb +373 -113
  42. data/lib/mongoid/contextual/none.rb +162 -7
  43. data/lib/mongoid/contextual.rb +12 -0
  44. data/lib/mongoid/criteria/findable.rb +2 -2
  45. data/lib/mongoid/criteria/includable.rb +4 -3
  46. data/lib/mongoid/criteria/queryable/key.rb +1 -1
  47. data/lib/mongoid/criteria/queryable/mergeable.rb +1 -1
  48. data/lib/mongoid/criteria/queryable/optional.rb +8 -8
  49. data/lib/mongoid/criteria/queryable/selectable.rb +43 -12
  50. data/lib/mongoid/criteria.rb +6 -5
  51. data/lib/mongoid/deprecable.rb +1 -1
  52. data/lib/mongoid/errors/create_collection_failure.rb +33 -0
  53. data/lib/mongoid/errors/drop_collection_failure.rb +27 -0
  54. data/lib/mongoid/errors/immutable_attribute.rb +26 -0
  55. data/lib/mongoid/errors/invalid_async_query_executor.rb +25 -0
  56. data/lib/mongoid/errors/invalid_global_executor_concurrency.rb +22 -0
  57. data/lib/mongoid/errors/invalid_storage_parent.rb +2 -0
  58. data/lib/mongoid/errors.rb +4 -1
  59. data/lib/mongoid/extensions/object.rb +2 -2
  60. data/lib/mongoid/extensions/time.rb +2 -0
  61. data/lib/mongoid/fields/localized.rb +10 -0
  62. data/lib/mongoid/fields/standard.rb +10 -0
  63. data/lib/mongoid/fields.rb +69 -13
  64. data/lib/mongoid/findable.rb +27 -3
  65. data/lib/mongoid/interceptable.rb +7 -6
  66. data/lib/mongoid/matcher/eq_impl.rb +1 -1
  67. data/lib/mongoid/matcher/type.rb +1 -1
  68. data/lib/mongoid/persistable/creatable.rb +1 -0
  69. data/lib/mongoid/persistable/deletable.rb +1 -1
  70. data/lib/mongoid/persistable/savable.rb +13 -1
  71. data/lib/mongoid/persistable/unsettable.rb +2 -2
  72. data/lib/mongoid/persistable/updatable.rb +51 -1
  73. data/lib/mongoid/persistable/upsertable.rb +20 -1
  74. data/lib/mongoid/persistable.rb +3 -0
  75. data/lib/mongoid/query_cache.rb +5 -1
  76. data/lib/mongoid/railties/database.rake +7 -2
  77. data/lib/mongoid/reloadable.rb +5 -3
  78. data/lib/mongoid/stateful.rb +22 -1
  79. data/lib/mongoid/tasks/database.rake +12 -0
  80. data/lib/mongoid/tasks/database.rb +20 -0
  81. data/lib/mongoid/utils.rb +22 -0
  82. data/lib/mongoid/validatable/macros.rb +5 -5
  83. data/lib/mongoid/validatable.rb +4 -1
  84. data/lib/mongoid/version.rb +1 -1
  85. data/lib/mongoid/warnings.rb +17 -1
  86. data/lib/mongoid.rb +16 -3
  87. data/spec/integration/app_spec.rb +2 -2
  88. data/spec/integration/callbacks_models.rb +37 -0
  89. data/spec/integration/callbacks_spec.rb +134 -0
  90. data/spec/integration/discriminator_key_spec.rb +4 -5
  91. data/spec/integration/i18n_fallbacks_spec.rb +3 -2
  92. data/spec/mongoid/association/embedded/embedded_in/proxy_spec.rb +27 -0
  93. data/spec/mongoid/association/embedded/embeds_many/proxy_spec.rb +20 -25
  94. data/spec/mongoid/association/embedded/embeds_many_models.rb +1 -0
  95. data/spec/mongoid/association/embedded/embeds_one/proxy_spec.rb +15 -2
  96. data/spec/mongoid/association/referenced/belongs_to_spec.rb +2 -18
  97. data/spec/mongoid/association/referenced/has_and_belongs_to_many/proxy_spec.rb +5 -27
  98. data/spec/mongoid/association/referenced/has_many/proxy_spec.rb +9 -50
  99. data/spec/mongoid/association/syncable_spec.rb +1 -1
  100. data/spec/mongoid/attributes_spec.rb +3 -6
  101. data/spec/mongoid/changeable_spec.rb +299 -24
  102. data/spec/mongoid/clients_spec.rb +122 -13
  103. data/spec/mongoid/collection_configurable_spec.rb +158 -0
  104. data/spec/mongoid/config/defaults_spec.rb +160 -0
  105. data/spec/mongoid/config_spec.rb +154 -18
  106. data/spec/mongoid/contextual/memory_spec.rb +332 -76
  107. data/spec/mongoid/contextual/mongo/documents_loader_spec.rb +187 -0
  108. data/spec/mongoid/contextual/mongo_spec.rb +995 -36
  109. data/spec/mongoid/contextual/none_spec.rb +49 -2
  110. data/spec/mongoid/copyable_spec.rb +3 -11
  111. data/spec/mongoid/criteria/queryable/extensions/string_spec.rb +4 -10
  112. data/spec/mongoid/criteria/queryable/options_spec.rb +1 -1
  113. data/spec/mongoid/criteria/queryable/selectable_logical_spec.rb +419 -0
  114. data/spec/mongoid/criteria/queryable/selectable_spec.rb +1 -1
  115. data/spec/mongoid/criteria/queryable/selector_spec.rb +1 -1
  116. data/spec/mongoid/criteria_projection_spec.rb +1 -4
  117. data/spec/mongoid/criteria_spec.rb +5 -9
  118. data/spec/mongoid/errors/readonly_document_spec.rb +2 -2
  119. data/spec/mongoid/extensions/time_spec.rb +8 -43
  120. data/spec/mongoid/extensions/time_with_zone_spec.rb +7 -52
  121. data/spec/mongoid/fields/localized_spec.rb +46 -28
  122. data/spec/mongoid/fields_spec.rb +136 -34
  123. data/spec/mongoid/findable_spec.rb +391 -34
  124. data/spec/mongoid/indexable_spec.rb +16 -10
  125. data/spec/mongoid/interceptable_spec.rb +15 -3
  126. data/spec/mongoid/persistable/deletable_spec.rb +26 -6
  127. data/spec/mongoid/persistable/destroyable_spec.rb +26 -6
  128. data/spec/mongoid/persistable/incrementable_spec.rb +37 -0
  129. data/spec/mongoid/persistable/logical_spec.rb +37 -0
  130. data/spec/mongoid/persistable/poppable_spec.rb +36 -0
  131. data/spec/mongoid/persistable/pullable_spec.rb +72 -0
  132. data/spec/mongoid/persistable/pushable_spec.rb +72 -0
  133. data/spec/mongoid/persistable/renamable_spec.rb +36 -0
  134. data/spec/mongoid/persistable/savable_spec.rb +96 -0
  135. data/spec/mongoid/persistable/settable_spec.rb +37 -0
  136. data/spec/mongoid/persistable/unsettable_spec.rb +36 -0
  137. data/spec/mongoid/persistable/updatable_spec.rb +20 -28
  138. data/spec/mongoid/persistable/upsertable_spec.rb +80 -6
  139. data/spec/mongoid/persistence_context_spec.rb +7 -57
  140. data/spec/mongoid/query_cache_spec.rb +56 -61
  141. data/spec/mongoid/reloadable_spec.rb +24 -28
  142. data/spec/mongoid/scopable_spec.rb +70 -0
  143. data/spec/mongoid/serializable_spec.rb +9 -30
  144. data/spec/mongoid/stateful_spec.rb +122 -8
  145. data/spec/mongoid/tasks/database_rake_spec.rb +74 -0
  146. data/spec/mongoid/tasks/database_spec.rb +127 -0
  147. data/spec/mongoid/timestamps_spec.rb +9 -11
  148. data/spec/mongoid/touchable_spec.rb +277 -5
  149. data/spec/mongoid/touchable_spec_models.rb +3 -1
  150. data/spec/mongoid/traversable_spec.rb +9 -24
  151. data/spec/mongoid/validatable/uniqueness_spec.rb +2 -3
  152. data/spec/mongoid_spec.rb +36 -10
  153. data/spec/shared/lib/mrss/docker_runner.rb +7 -0
  154. data/spec/shared/lib/mrss/event_subscriber.rb +15 -5
  155. data/spec/shared/lib/mrss/lite_constraints.rb +10 -2
  156. data/spec/shared/lib/mrss/server_version_registry.rb +16 -23
  157. data/spec/shared/lib/mrss/utils.rb +28 -6
  158. data/spec/shared/share/Dockerfile.erb +36 -40
  159. data/spec/shared/shlib/server.sh +32 -8
  160. data/spec/shared/shlib/set_env.sh +4 -4
  161. data/spec/spec_helper.rb +5 -0
  162. data/spec/support/immutable_ids.rb +118 -0
  163. data/spec/support/macros.rb +47 -15
  164. data/spec/support/models/artist.rb +0 -1
  165. data/spec/support/models/band.rb +1 -0
  166. data/spec/support/models/book.rb +1 -0
  167. data/spec/support/models/building.rb +2 -0
  168. data/spec/support/models/cover.rb +10 -0
  169. data/spec/support/models/product.rb +1 -0
  170. data.tar.gz.sig +0 -0
  171. metadata +686 -650
  172. metadata.gz.sig +0 -0
  173. data/spec/mongoid/criteria/queryable/extensions/bignum_spec.rb +0 -60
  174. data/spec/mongoid/criteria/queryable/extensions/fixnum_spec.rb +0 -60
@@ -561,6 +561,8 @@ describe Mongoid::Contextual::Mongo do
561
561
  end
562
562
 
563
563
  context "when getting a localized field" do
564
+ with_default_i18n_configs
565
+
564
566
  before do
565
567
  I18n.locale = :en
566
568
  d = Dictionary.create!(description: 'english-text')
@@ -660,13 +662,11 @@ describe Mongoid::Contextual::Mongo do
660
662
  end
661
663
 
662
664
  context 'when fallbacks are enabled with a locale list' do
663
- with_i18n_fallbacks
665
+ require_fallbacks
666
+ with_default_i18n_configs
664
667
 
665
- around(:all) do |example|
666
- prev_fallbacks = I18n.fallbacks.dup
668
+ before do
667
669
  I18n.fallbacks[:he] = [ :en ]
668
- example.run
669
- I18n.fallbacks = prev_fallbacks
670
670
  end
671
671
 
672
672
  let(:distinct) do
@@ -694,6 +694,8 @@ describe Mongoid::Contextual::Mongo do
694
694
  end
695
695
 
696
696
  context "when the localized field is embedded" do
697
+ with_default_i18n_configs
698
+
697
699
  before do
698
700
  p = Passport.new
699
701
  I18n.locale = :en
@@ -839,6 +841,8 @@ describe Mongoid::Contextual::Mongo do
839
841
  end
840
842
 
841
843
  context "when tallying a localized field" do
844
+ with_default_i18n_configs
845
+
842
846
  before do
843
847
  I18n.locale = :en
844
848
  d1 = Dictionary.create!(description: 'en1')
@@ -893,6 +897,7 @@ describe Mongoid::Contextual::Mongo do
893
897
  end
894
898
 
895
899
  context "when tallying an embedded localized field" do
900
+ with_default_i18n_configs
896
901
 
897
902
  before do
898
903
  I18n.locale = :en
@@ -1375,64 +1380,177 @@ describe Mongoid::Contextual::Mongo do
1375
1380
 
1376
1381
  describe "#exists?" do
1377
1382
 
1378
- before do
1379
- Band.create!(name: "Depeche Mode")
1383
+ let!(:band) do
1384
+ Band.create!(name: "Depeche Mode", active: true)
1380
1385
  end
1381
1386
 
1382
- context "when the count is zero" do
1387
+ context "when not passing options" do
1383
1388
 
1384
- let(:criteria) do
1385
- Band.where(name: "New Order")
1389
+ context "when the count is zero" do
1390
+
1391
+ let(:criteria) do
1392
+ Band.where(name: "New Order")
1393
+ end
1394
+
1395
+ let(:context) do
1396
+ described_class.new(criteria)
1397
+ end
1398
+
1399
+ it "returns false" do
1400
+ expect(context).to_not be_exists
1401
+ end
1386
1402
  end
1387
1403
 
1388
- let(:context) do
1389
- described_class.new(criteria)
1404
+ context "when the count is greater than zero" do
1405
+
1406
+ let(:criteria) do
1407
+ Band.where(name: "Depeche Mode")
1408
+ end
1409
+
1410
+ let(:context) do
1411
+ described_class.new(criteria)
1412
+ end
1413
+
1414
+ it "returns true" do
1415
+ expect(context).to be_exists
1416
+ end
1390
1417
  end
1391
1418
 
1392
- it "returns false" do
1393
- expect(context).to_not be_exists
1419
+ context "when caching is not enabled" do
1420
+
1421
+ let(:criteria) do
1422
+ Band.where(name: "Depeche Mode")
1423
+ end
1424
+
1425
+ let(:context) do
1426
+ described_class.new(criteria)
1427
+ end
1428
+
1429
+ context "when exists? already called and query cache is enabled" do
1430
+ query_cache_enabled
1431
+
1432
+ before do
1433
+ context.exists?
1434
+ end
1435
+
1436
+ it "does not hit the database again" do
1437
+ expect_no_queries do
1438
+ expect(context).to be_exists
1439
+ end
1440
+ end
1441
+ end
1394
1442
  end
1395
1443
  end
1396
1444
 
1397
- context "when the count is greater than zero" do
1445
+ context "when passing an _id" do
1398
1446
 
1399
- let(:criteria) do
1400
- Band.where(name: "Depeche Mode")
1401
- end
1447
+ context "when its of type BSON::ObjectId" do
1402
1448
 
1403
- let(:context) do
1404
- described_class.new(criteria)
1449
+ context "when calling it on the class" do
1450
+
1451
+ it "returns true" do
1452
+ expect(Band.exists?(band._id)).to be true
1453
+ end
1454
+ end
1455
+
1456
+ context "when calling it on a criteria that includes the object" do
1457
+
1458
+ it "returns true" do
1459
+ expect(Band.where(name: band.name).exists?(band._id)).to be true
1460
+ end
1461
+ end
1462
+
1463
+ context "when calling it on a criteria that does not include the object" do
1464
+
1465
+ it "returns false" do
1466
+ expect(Band.where(name: "bogus").exists?(band._id)).to be false
1467
+ end
1468
+ end
1469
+
1470
+ context "when the id does not exist" do
1471
+
1472
+ it "returns false" do
1473
+ expect(Band.exists?(BSON::ObjectId.new)).to be false
1474
+ end
1475
+ end
1405
1476
  end
1406
1477
 
1407
- it "returns true" do
1408
- expect(context).to be_exists
1478
+ context "when its of type String" do
1479
+
1480
+ context "when the id exists" do
1481
+
1482
+ it "returns true" do
1483
+ expect(Band.exists?(band._id.to_s)).to be true
1484
+ end
1485
+ end
1486
+
1487
+ context "when the id does not exist" do
1488
+
1489
+ it "returns false" do
1490
+ expect(Band.exists?(BSON::ObjectId.new.to_s)).to be false
1491
+ end
1492
+ end
1409
1493
  end
1410
1494
  end
1411
1495
 
1412
- context "when caching is not enabled" do
1496
+ context "when passing a hash" do
1413
1497
 
1414
- let(:criteria) do
1415
- Band.where(name: "Depeche Mode")
1498
+ context "when calling it on the class" do
1499
+
1500
+ it "returns true" do
1501
+ expect(Band.exists?(name: band.name)).to be true
1502
+ end
1416
1503
  end
1417
1504
 
1418
- let(:context) do
1419
- described_class.new(criteria)
1505
+ context "when calling it on a criteria that includes the object" do
1506
+
1507
+ it "returns true" do
1508
+ expect(Band.where(active: true).exists?(name: band.name)).to be true
1509
+ end
1420
1510
  end
1421
1511
 
1422
- context "when exists? already called and query cache is enabled" do
1423
- query_cache_enabled
1512
+ context "when calling it on a criteria that does not include the object" do
1424
1513
 
1425
- before do
1426
- context.exists?
1514
+ it "returns false" do
1515
+ expect(Band.where(active: false).exists?(name: band.name)).to be false
1427
1516
  end
1517
+ end
1428
1518
 
1429
- it "does not hit the database again" do
1430
- expect_no_queries do
1431
- expect(context).to be_exists
1432
- end
1519
+ context "when the conditions don't match" do
1520
+
1521
+ it "returns false" do
1522
+ expect(Band.exists?(name: "bogus")).to be false
1433
1523
  end
1434
1524
  end
1435
1525
  end
1526
+
1527
+ context "when passing false" do
1528
+
1529
+ it "returns false" do
1530
+ expect(Band.exists?(false)).to be false
1531
+ end
1532
+ end
1533
+
1534
+ context "when passing nil" do
1535
+
1536
+ it "returns false" do
1537
+ expect(Band.exists?(nil)).to be false
1538
+ end
1539
+ end
1540
+
1541
+ context "when the limit is 0" do
1542
+
1543
+ it "returns false" do
1544
+ expect(Band.limit(0).exists?).to be false
1545
+ end
1546
+ end
1547
+
1548
+ context "when the criteria limit is 0" do
1549
+
1550
+ it "returns false" do
1551
+ expect(Band.criteria.limit(0).exists?).to be false
1552
+ end
1553
+ end
1436
1554
  end
1437
1555
 
1438
1556
  describe "#explain" do
@@ -1446,7 +1564,16 @@ describe Mongoid::Contextual::Mongo do
1446
1564
  end
1447
1565
 
1448
1566
  it "returns the criteria explain path" do
1449
- expect(context.explain).to_not be_empty
1567
+ explain = context.explain
1568
+ expect(explain).to_not be_empty
1569
+ expect(explain.keys).to include("queryPlanner", "executionStats", "serverInfo")
1570
+ end
1571
+
1572
+ it "respects options passed to explain" do
1573
+ explain = context.explain(verbosity: :query_planner)
1574
+ expect(explain).to_not be_empty
1575
+ expect(explain.keys).to include("queryPlanner", "serverInfo")
1576
+ expect(explain.keys).not_to include("executionStats")
1450
1577
  end
1451
1578
  end
1452
1579
 
@@ -3674,4 +3801,836 @@ describe Mongoid::Contextual::Mongo do
3674
3801
  end
3675
3802
  end
3676
3803
  end
3804
+
3805
+ describe "#first!" do
3806
+
3807
+ let!(:depeche_mode) do
3808
+ Band.create!(name: "Depeche Mode")
3809
+ end
3810
+
3811
+ let!(:new_order) do
3812
+ Band.create!(name: "New Order")
3813
+ end
3814
+
3815
+ let!(:rolling_stones) do
3816
+ Band.create!(name: "The Rolling Stones")
3817
+ end
3818
+
3819
+ let!(:death_cab) do
3820
+ Band.create!(name: "Death Cab For Cutie")
3821
+ end
3822
+
3823
+ let(:context) do
3824
+ described_class.new(criteria)
3825
+ end
3826
+
3827
+ context "when there's no sort" do
3828
+ let(:criteria) do
3829
+ Band.all
3830
+ end
3831
+
3832
+ it "gets the first document" do
3833
+ expect(context.first!).to eq(depeche_mode)
3834
+ end
3835
+ end
3836
+
3837
+ context "when there's a custom sort" do
3838
+ let(:criteria) do
3839
+ Band.all
3840
+ end
3841
+
3842
+ it "gets the first document" do
3843
+ expect(context.sort(name: 1).first!).to eq(death_cab)
3844
+ end
3845
+ end
3846
+
3847
+ context "when there are no documents" do
3848
+ let(:criteria) do
3849
+ Band.where(name: "bogus")
3850
+ end
3851
+
3852
+ it "raises an error" do
3853
+ expect do
3854
+ context.first!
3855
+ end.to raise_error(Mongoid::Errors::DocumentNotFound, /Could not find a document of class Band./)
3856
+ end
3857
+ end
3858
+ end
3859
+
3860
+ describe "#last!" do
3861
+
3862
+ let!(:depeche_mode) do
3863
+ Band.create!(name: "Depeche Mode")
3864
+ end
3865
+
3866
+ let!(:new_order) do
3867
+ Band.create!(name: "New Order")
3868
+ end
3869
+
3870
+ let!(:rolling_stones) do
3871
+ Band.create!(name: "The Rolling Stones")
3872
+ end
3873
+
3874
+ let!(:death_cab) do
3875
+ Band.create!(name: "Death Cab For Cutie")
3876
+ end
3877
+
3878
+ let(:context) do
3879
+ described_class.new(criteria)
3880
+ end
3881
+
3882
+ context "when there's no sort" do
3883
+ let(:criteria) do
3884
+ Band.all
3885
+ end
3886
+
3887
+ it "gets the last document" do
3888
+ expect(context.last!).to eq(death_cab)
3889
+ end
3890
+ end
3891
+
3892
+ context "when there's a custom sort" do
3893
+ let(:criteria) do
3894
+ Band.all
3895
+ end
3896
+
3897
+ it "gets the last document" do
3898
+ expect(context.sort(name: 1).last!).to eq(rolling_stones)
3899
+ end
3900
+ end
3901
+
3902
+ context "when there are no documents" do
3903
+ let(:criteria) do
3904
+ Band.where(name: "bogus")
3905
+ end
3906
+
3907
+ it "raises an error" do
3908
+ expect do
3909
+ context.last!
3910
+ end.to raise_error(Mongoid::Errors::DocumentNotFound, /Could not find a document of class Band./)
3911
+ end
3912
+ end
3913
+ end
3914
+
3915
+ describe "#second" do
3916
+
3917
+ let!(:depeche_mode) do
3918
+ Band.create!(name: "Depeche Mode")
3919
+ end
3920
+
3921
+ let!(:new_order) do
3922
+ Band.create!(name: "New Order")
3923
+ end
3924
+
3925
+ let!(:rolling_stones) do
3926
+ Band.create!(name: "The Rolling Stones")
3927
+ end
3928
+
3929
+ let!(:death_cab) do
3930
+ Band.create!(name: "Death Cab For Cutie")
3931
+ end
3932
+
3933
+ let(:context) do
3934
+ described_class.new(criteria)
3935
+ end
3936
+
3937
+ context "when there's no sort" do
3938
+ let(:criteria) do
3939
+ Band.all
3940
+ end
3941
+
3942
+ it "gets the second document" do
3943
+ expect(context.second).to eq(new_order)
3944
+ end
3945
+ end
3946
+
3947
+ context "when there's a custom sort" do
3948
+ let(:criteria) do
3949
+ Band.all
3950
+ end
3951
+
3952
+ it "gets the second document" do
3953
+ expect(context.sort(name: 1).second).to eq(depeche_mode)
3954
+ end
3955
+ end
3956
+
3957
+ context "when there are no documents" do
3958
+ let(:criteria) do
3959
+ Band.where(name: "bogus")
3960
+ end
3961
+
3962
+ it "returns nil" do
3963
+ expect(context.second).to be_nil
3964
+ end
3965
+ end
3966
+ end
3967
+
3968
+ describe "#second!" do
3969
+
3970
+ let!(:depeche_mode) do
3971
+ Band.create!(name: "Depeche Mode")
3972
+ end
3973
+
3974
+ let!(:new_order) do
3975
+ Band.create!(name: "New Order")
3976
+ end
3977
+
3978
+ let!(:rolling_stones) do
3979
+ Band.create!(name: "The Rolling Stones")
3980
+ end
3981
+
3982
+ let!(:death_cab) do
3983
+ Band.create!(name: "Death Cab For Cutie")
3984
+ end
3985
+
3986
+ let(:context) do
3987
+ described_class.new(criteria)
3988
+ end
3989
+
3990
+ context "when there's no sort" do
3991
+ let(:criteria) do
3992
+ Band.all
3993
+ end
3994
+
3995
+ it "gets the second document" do
3996
+ expect(context.second!).to eq(new_order)
3997
+ end
3998
+ end
3999
+
4000
+ context "when there's a custom sort" do
4001
+ let(:criteria) do
4002
+ Band.all
4003
+ end
4004
+
4005
+ it "gets the second document" do
4006
+ expect(context.sort(name: 1).second!).to eq(depeche_mode)
4007
+ end
4008
+ end
4009
+
4010
+ context "when there are no documents" do
4011
+ let(:criteria) do
4012
+ Band.where(name: "bogus")
4013
+ end
4014
+
4015
+ it "raises an error" do
4016
+ expect do
4017
+ context.second!
4018
+ end.to raise_error(Mongoid::Errors::DocumentNotFound, /Could not find a document of class Band./)
4019
+ end
4020
+ end
4021
+ end
4022
+
4023
+ describe "#third" do
4024
+
4025
+ let!(:depeche_mode) do
4026
+ Band.create!(name: "Depeche Mode")
4027
+ end
4028
+
4029
+ let!(:new_order) do
4030
+ Band.create!(name: "New Order")
4031
+ end
4032
+
4033
+ let!(:rolling_stones) do
4034
+ Band.create!(name: "The Rolling Stones")
4035
+ end
4036
+
4037
+ let!(:death_cab) do
4038
+ Band.create!(name: "Death Cab For Cutie")
4039
+ end
4040
+
4041
+ let(:context) do
4042
+ described_class.new(criteria)
4043
+ end
4044
+
4045
+ context "when there's no sort" do
4046
+ let(:criteria) do
4047
+ Band.all
4048
+ end
4049
+
4050
+ it "gets the third document" do
4051
+ expect(context.third).to eq(rolling_stones)
4052
+ end
4053
+ end
4054
+
4055
+ context "when there's a custom sort" do
4056
+ let(:criteria) do
4057
+ Band.all
4058
+ end
4059
+
4060
+ it "gets the third document" do
4061
+ expect(context.sort(name: 1).third).to eq(new_order)
4062
+ end
4063
+ end
4064
+
4065
+ context "when there are no documents" do
4066
+ let(:criteria) do
4067
+ Band.where(name: "bogus")
4068
+ end
4069
+
4070
+ it "returns nil" do
4071
+ expect(context.third).to be_nil
4072
+ end
4073
+ end
4074
+ end
4075
+
4076
+ describe "#third!" do
4077
+
4078
+ let!(:depeche_mode) do
4079
+ Band.create!(name: "Depeche Mode")
4080
+ end
4081
+
4082
+ let!(:new_order) do
4083
+ Band.create!(name: "New Order")
4084
+ end
4085
+
4086
+ let!(:rolling_stones) do
4087
+ Band.create!(name: "The Rolling Stones")
4088
+ end
4089
+
4090
+ let!(:death_cab) do
4091
+ Band.create!(name: "Death Cab For Cutie")
4092
+ end
4093
+
4094
+ let(:context) do
4095
+ described_class.new(criteria)
4096
+ end
4097
+
4098
+ context "when there's no sort" do
4099
+ let(:criteria) do
4100
+ Band.all
4101
+ end
4102
+
4103
+ it "gets the third document" do
4104
+ expect(context.third!).to eq(rolling_stones)
4105
+ end
4106
+ end
4107
+
4108
+ context "when there's a custom sort" do
4109
+ let(:criteria) do
4110
+ Band.all
4111
+ end
4112
+
4113
+ it "gets the third document" do
4114
+ expect(context.sort(name: 1).third!).to eq(new_order)
4115
+ end
4116
+ end
4117
+
4118
+ context "when there are no documents" do
4119
+ let(:criteria) do
4120
+ Band.where(name: "bogus")
4121
+ end
4122
+
4123
+ it "raises an error" do
4124
+ expect do
4125
+ context.third!
4126
+ end.to raise_error(Mongoid::Errors::DocumentNotFound, /Could not find a document of class Band./)
4127
+ end
4128
+ end
4129
+ end
4130
+
4131
+ describe "#fourth" do
4132
+
4133
+ let!(:depeche_mode) do
4134
+ Band.create!(name: "Depeche Mode")
4135
+ end
4136
+
4137
+ let!(:new_order) do
4138
+ Band.create!(name: "New Order")
4139
+ end
4140
+
4141
+ let!(:rolling_stones) do
4142
+ Band.create!(name: "The Rolling Stones")
4143
+ end
4144
+
4145
+ let!(:death_cab) do
4146
+ Band.create!(name: "Death Cab For Cutie")
4147
+ end
4148
+
4149
+ let(:context) do
4150
+ described_class.new(criteria)
4151
+ end
4152
+
4153
+ context "when there's no sort" do
4154
+ let(:criteria) do
4155
+ Band.all
4156
+ end
4157
+
4158
+ it "gets the fourth document" do
4159
+ expect(context.fourth).to eq(death_cab)
4160
+ end
4161
+ end
4162
+
4163
+ context "when there's a custom sort" do
4164
+ let(:criteria) do
4165
+ Band.all
4166
+ end
4167
+
4168
+ it "gets the fourth document" do
4169
+ expect(context.sort(name: 1).fourth).to eq(rolling_stones)
4170
+ end
4171
+ end
4172
+
4173
+ context "when there are no documents" do
4174
+ let(:criteria) do
4175
+ Band.where(name: "bogus")
4176
+ end
4177
+
4178
+ it "returns nil" do
4179
+ expect(context.fourth).to be_nil
4180
+ end
4181
+ end
4182
+ end
4183
+
4184
+ describe "#fourth!" do
4185
+
4186
+ let!(:depeche_mode) do
4187
+ Band.create!(name: "Depeche Mode")
4188
+ end
4189
+
4190
+ let!(:new_order) do
4191
+ Band.create!(name: "New Order")
4192
+ end
4193
+
4194
+ let!(:rolling_stones) do
4195
+ Band.create!(name: "The Rolling Stones")
4196
+ end
4197
+
4198
+ let!(:death_cab) do
4199
+ Band.create!(name: "Death Cab For Cutie")
4200
+ end
4201
+
4202
+ let(:context) do
4203
+ described_class.new(criteria)
4204
+ end
4205
+
4206
+ context "when there's no sort" do
4207
+ let(:criteria) do
4208
+ Band.all
4209
+ end
4210
+
4211
+ it "gets the fourth document" do
4212
+ expect(context.fourth!).to eq(death_cab)
4213
+ end
4214
+ end
4215
+
4216
+ context "when there's a custom sort" do
4217
+ let(:criteria) do
4218
+ Band.all
4219
+ end
4220
+
4221
+ it "gets the fourth document" do
4222
+ expect(context.sort(name: 1).fourth!).to eq(rolling_stones)
4223
+ end
4224
+ end
4225
+
4226
+ context "when there are no documents" do
4227
+ let(:criteria) do
4228
+ Band.where(name: "bogus")
4229
+ end
4230
+
4231
+ it "raises an error" do
4232
+ expect do
4233
+ context.fourth!
4234
+ end.to raise_error(Mongoid::Errors::DocumentNotFound, /Could not find a document of class Band./)
4235
+ end
4236
+ end
4237
+ end
4238
+
4239
+ describe "#fifth" do
4240
+
4241
+ let!(:depeche_mode) do
4242
+ Band.create!(name: "Depeche Mode")
4243
+ end
4244
+
4245
+ let!(:new_order) do
4246
+ Band.create!(name: "New Order")
4247
+ end
4248
+
4249
+ let!(:rolling_stones) do
4250
+ Band.create!(name: "The Rolling Stones")
4251
+ end
4252
+
4253
+ let!(:death_cab) do
4254
+ Band.create!(name: "Death Cab For Cutie")
4255
+ end
4256
+
4257
+ let!(:guns_and_roses) do
4258
+ Band.create!(name: "Guns and Roses")
4259
+ end
4260
+
4261
+ let(:context) do
4262
+ described_class.new(criteria)
4263
+ end
4264
+
4265
+ context "when there's no sort" do
4266
+ let(:criteria) do
4267
+ Band.all
4268
+ end
4269
+
4270
+ it "gets the fifth document" do
4271
+ expect(context.fifth).to eq(guns_and_roses)
4272
+ end
4273
+ end
4274
+
4275
+ context "when there's a custom sort" do
4276
+ let(:criteria) do
4277
+ Band.all
4278
+ end
4279
+
4280
+ it "gets the fifth document" do
4281
+ expect(context.sort(name: 1).fifth).to eq(rolling_stones)
4282
+ end
4283
+ end
4284
+
4285
+ context "when there are no documents" do
4286
+ let(:criteria) do
4287
+ Band.where(name: "bogus")
4288
+ end
4289
+
4290
+ it "returns nil" do
4291
+ expect(context.fifth).to be_nil
4292
+ end
4293
+ end
4294
+ end
4295
+
4296
+ describe "#fifth!" do
4297
+
4298
+ let!(:depeche_mode) do
4299
+ Band.create!(name: "Depeche Mode")
4300
+ end
4301
+
4302
+ let!(:new_order) do
4303
+ Band.create!(name: "New Order")
4304
+ end
4305
+
4306
+ let!(:rolling_stones) do
4307
+ Band.create!(name: "The Rolling Stones")
4308
+ end
4309
+
4310
+ let!(:death_cab) do
4311
+ Band.create!(name: "Death Cab For Cutie")
4312
+ end
4313
+
4314
+ let!(:guns_and_roses) do
4315
+ Band.create!(name: "Guns and Roses")
4316
+ end
4317
+
4318
+ let(:context) do
4319
+ described_class.new(criteria)
4320
+ end
4321
+
4322
+ context "when there's no sort" do
4323
+ let(:criteria) do
4324
+ Band.all
4325
+ end
4326
+
4327
+ it "gets the fifth document" do
4328
+ expect(context.fifth!).to eq(guns_and_roses)
4329
+ end
4330
+ end
4331
+
4332
+ context "when there's a custom sort" do
4333
+ let(:criteria) do
4334
+ Band.all
4335
+ end
4336
+
4337
+ it "gets the fifth document" do
4338
+ expect(context.sort(name: 1).fifth!).to eq(rolling_stones)
4339
+ end
4340
+ end
4341
+
4342
+ context "when there are no documents" do
4343
+ let(:criteria) do
4344
+ Band.where(name: "bogus")
4345
+ end
4346
+
4347
+ it "raises an error" do
4348
+ expect do
4349
+ context.fifth!
4350
+ end.to raise_error(Mongoid::Errors::DocumentNotFound, /Could not find a document of class Band./)
4351
+ end
4352
+ end
4353
+ end
4354
+
4355
+ describe "#second_to_last" do
4356
+
4357
+ let!(:depeche_mode) do
4358
+ Band.create!(name: "Depeche Mode")
4359
+ end
4360
+
4361
+ let!(:new_order) do
4362
+ Band.create!(name: "New Order")
4363
+ end
4364
+
4365
+ let!(:rolling_stones) do
4366
+ Band.create!(name: "The Rolling Stones")
4367
+ end
4368
+
4369
+ let!(:death_cab) do
4370
+ Band.create!(name: "Death Cab For Cutie")
4371
+ end
4372
+
4373
+ let(:context) do
4374
+ described_class.new(criteria)
4375
+ end
4376
+
4377
+ context "when there's no sort" do
4378
+ let(:criteria) do
4379
+ Band.all
4380
+ end
4381
+
4382
+ it "gets the second_to_last document" do
4383
+ expect(context.second_to_last).to eq(rolling_stones)
4384
+ end
4385
+ end
4386
+
4387
+ context "when there's a custom sort" do
4388
+ let(:criteria) do
4389
+ Band.all
4390
+ end
4391
+
4392
+ it "gets the second_to_last document" do
4393
+ expect(context.sort(name: 1).second_to_last).to eq(new_order)
4394
+ end
4395
+ end
4396
+
4397
+ context "when there are no documents" do
4398
+ let(:criteria) do
4399
+ Band.where(name: "bogus")
4400
+ end
4401
+
4402
+ it "returns nil" do
4403
+ expect(context.second_to_last).to be_nil
4404
+ end
4405
+ end
4406
+ end
4407
+
4408
+ describe "#second_to_last!" do
4409
+
4410
+ let!(:depeche_mode) do
4411
+ Band.create!(name: "Depeche Mode")
4412
+ end
4413
+
4414
+ let!(:new_order) do
4415
+ Band.create!(name: "New Order")
4416
+ end
4417
+
4418
+ let!(:rolling_stones) do
4419
+ Band.create!(name: "The Rolling Stones")
4420
+ end
4421
+
4422
+ let!(:death_cab) do
4423
+ Band.create!(name: "Death Cab For Cutie")
4424
+ end
4425
+
4426
+ let(:context) do
4427
+ described_class.new(criteria)
4428
+ end
4429
+
4430
+ context "when there's no sort" do
4431
+ let(:criteria) do
4432
+ Band.all
4433
+ end
4434
+
4435
+ it "gets the second_to_last document" do
4436
+ expect(context.second_to_last!).to eq(rolling_stones)
4437
+ end
4438
+ end
4439
+
4440
+ context "when there's a custom sort" do
4441
+ let(:criteria) do
4442
+ Band.all
4443
+ end
4444
+
4445
+ it "gets the second_to_last document" do
4446
+ expect(context.sort(name: 1).second_to_last!).to eq(new_order)
4447
+ end
4448
+ end
4449
+
4450
+ context "when there are no documents" do
4451
+ let(:criteria) do
4452
+ Band.where(name: "bogus")
4453
+ end
4454
+
4455
+ it "raises an error" do
4456
+ expect do
4457
+ context.second_to_last!
4458
+ end.to raise_error(Mongoid::Errors::DocumentNotFound, /Could not find a document of class Band./)
4459
+ end
4460
+ end
4461
+ end
4462
+
4463
+ describe "#third_to_last" do
4464
+
4465
+ let!(:depeche_mode) do
4466
+ Band.create!(name: "Depeche Mode")
4467
+ end
4468
+
4469
+ let!(:new_order) do
4470
+ Band.create!(name: "New Order")
4471
+ end
4472
+
4473
+ let!(:rolling_stones) do
4474
+ Band.create!(name: "The Rolling Stones")
4475
+ end
4476
+
4477
+ let!(:death_cab) do
4478
+ Band.create!(name: "Death Cab For Cutie")
4479
+ end
4480
+
4481
+ let(:context) do
4482
+ described_class.new(criteria)
4483
+ end
4484
+
4485
+ context "when there's no sort" do
4486
+ let(:criteria) do
4487
+ Band.all
4488
+ end
4489
+
4490
+ it "gets the third_to_last document" do
4491
+ expect(context.third_to_last).to eq(new_order)
4492
+ end
4493
+ end
4494
+
4495
+ context "when there's a custom sort" do
4496
+ let(:criteria) do
4497
+ Band.all
4498
+ end
4499
+
4500
+ it "gets the third_to_last document" do
4501
+ expect(context.sort(name: 1).third_to_last).to eq(depeche_mode)
4502
+ end
4503
+ end
4504
+
4505
+ context "when there are no documents" do
4506
+ let(:criteria) do
4507
+ Band.where(name: "bogus")
4508
+ end
4509
+
4510
+ it "returns nil" do
4511
+ expect(context.third_to_last).to be_nil
4512
+ end
4513
+ end
4514
+ end
4515
+
4516
+ describe "#third_to_last!" do
4517
+
4518
+ let!(:depeche_mode) do
4519
+ Band.create!(name: "Depeche Mode")
4520
+ end
4521
+
4522
+ let!(:new_order) do
4523
+ Band.create!(name: "New Order")
4524
+ end
4525
+
4526
+ let!(:rolling_stones) do
4527
+ Band.create!(name: "The Rolling Stones")
4528
+ end
4529
+
4530
+ let!(:death_cab) do
4531
+ Band.create!(name: "Death Cab For Cutie")
4532
+ end
4533
+
4534
+ let(:context) do
4535
+ described_class.new(criteria)
4536
+ end
4537
+
4538
+ context "when there's no sort" do
4539
+ let(:criteria) do
4540
+ Band.all
4541
+ end
4542
+
4543
+ it "gets the third_to_last document" do
4544
+ expect(context.third_to_last!).to eq(new_order)
4545
+ end
4546
+ end
4547
+
4548
+ context "when there's a custom sort" do
4549
+ let(:criteria) do
4550
+ Band.all
4551
+ end
4552
+
4553
+ it "gets the third_to_last document" do
4554
+ expect(context.sort(name: 1).third_to_last!).to eq(depeche_mode)
4555
+ end
4556
+ end
4557
+
4558
+ context "when there are no documents" do
4559
+ let(:criteria) do
4560
+ Band.where(name: "bogus")
4561
+ end
4562
+
4563
+ it "raises an error" do
4564
+ expect do
4565
+ context.third_to_last!
4566
+ end.to raise_error(Mongoid::Errors::DocumentNotFound, /Could not find a document of class Band./)
4567
+ end
4568
+ end
4569
+ end
4570
+
4571
+ describe '#load_async' do
4572
+ let!(:band) do
4573
+ Band.create!(name: "Depeche Mode")
4574
+ end
4575
+
4576
+ let(:criteria) do
4577
+ Band.where(name: "Depeche Mode")
4578
+ end
4579
+
4580
+ let(:context) do
4581
+ described_class.new(criteria)
4582
+ end
4583
+
4584
+ context 'with global thread pool async query executor' do
4585
+ config_override :async_query_executor, :global_thread_pool
4586
+
4587
+ it 'preloads the documents' do
4588
+ context.load_async
4589
+ context.documents_loader.wait
4590
+
4591
+ expect(context.view).not_to receive(:map)
4592
+ expect(context.to_a).to eq([band])
4593
+ end
4594
+
4595
+ it 're-raises exception during preload' do
4596
+ expect_any_instance_of(Mongoid::Contextual::Mongo::DocumentsLoader)
4597
+ .to receive(:execute)
4598
+ .at_least(:once)
4599
+ .and_raise(Mongo::Error::OperationFailure)
4600
+
4601
+ context.load_async
4602
+ context.documents_loader.wait
4603
+
4604
+ expect do
4605
+ context.to_a
4606
+ end.to raise_error(Mongo::Error::OperationFailure)
4607
+ end
4608
+ end
4609
+
4610
+ context 'with immediate thread pool async query executor' do
4611
+ config_override :async_query_executor, :immediate
4612
+
4613
+ it 'preloads the documents' do
4614
+ context.load_async
4615
+ context.documents_loader.wait
4616
+
4617
+ expect(context.view).not_to receive(:map)
4618
+ expect(context.to_a).to eq([band])
4619
+ end
4620
+
4621
+ it 're-raises exception during preload' do
4622
+ expect_any_instance_of(Mongoid::Contextual::Mongo::DocumentsLoader)
4623
+ .to receive(:execute)
4624
+ .at_least(:once)
4625
+ .and_raise(Mongo::Error::OperationFailure)
4626
+
4627
+ context.load_async
4628
+ context.documents_loader.wait
4629
+
4630
+ expect do
4631
+ context.to_a
4632
+ end.to raise_error(Mongo::Error::OperationFailure)
4633
+ end
4634
+ end
4635
+ end
3677
4636
  end