mongoid 8.0.4 → 8.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (171) 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/lib/config/locales/en.yml +46 -14
  6. data/lib/mongoid/association/accessors.rb +2 -2
  7. data/lib/mongoid/association/builders.rb +1 -1
  8. data/lib/mongoid/association/embedded/batchable.rb +2 -2
  9. data/lib/mongoid/association/embedded/embedded_in/buildable.rb +2 -2
  10. data/lib/mongoid/association/embedded/embedded_in/proxy.rb +2 -1
  11. data/lib/mongoid/association/embedded/embeds_many/buildable.rb +3 -2
  12. data/lib/mongoid/association/embedded/embeds_many/proxy.rb +6 -6
  13. data/lib/mongoid/association/embedded/embeds_one/buildable.rb +1 -1
  14. data/lib/mongoid/association/embedded/embeds_one/proxy.rb +1 -1
  15. data/lib/mongoid/association/nested/one.rb +40 -2
  16. data/lib/mongoid/association/proxy.rb +1 -1
  17. data/lib/mongoid/association/referenced/counter_cache.rb +2 -2
  18. data/lib/mongoid/association/referenced/has_and_belongs_to_many/proxy.rb +1 -1
  19. data/lib/mongoid/association/referenced/has_many/enumerable.rb +2 -2
  20. data/lib/mongoid/association/referenced/has_many/proxy.rb +3 -3
  21. data/lib/mongoid/association/reflections.rb +2 -2
  22. data/lib/mongoid/attributes/dynamic.rb +1 -1
  23. data/lib/mongoid/attributes/nested.rb +2 -2
  24. data/lib/mongoid/attributes/projector.rb +1 -1
  25. data/lib/mongoid/attributes/readonly.rb +1 -1
  26. data/lib/mongoid/attributes.rb +8 -2
  27. data/lib/mongoid/changeable.rb +104 -4
  28. data/lib/mongoid/clients/storage_options.rb +2 -5
  29. data/lib/mongoid/clients/validators/storage.rb +1 -13
  30. data/lib/mongoid/collection_configurable.rb +58 -0
  31. data/lib/mongoid/composable.rb +2 -0
  32. data/lib/mongoid/config/defaults.rb +60 -0
  33. data/lib/mongoid/config/validators/async_query_executor.rb +24 -0
  34. data/lib/mongoid/config/validators.rb +1 -0
  35. data/lib/mongoid/config.rb +101 -0
  36. data/lib/mongoid/contextual/atomic.rb +1 -1
  37. data/lib/mongoid/contextual/memory.rb +233 -33
  38. data/lib/mongoid/contextual/mongo/documents_loader.rb +177 -0
  39. data/lib/mongoid/contextual/mongo.rb +373 -113
  40. data/lib/mongoid/contextual/none.rb +162 -7
  41. data/lib/mongoid/contextual.rb +12 -0
  42. data/lib/mongoid/criteria/findable.rb +2 -2
  43. data/lib/mongoid/criteria/includable.rb +4 -3
  44. data/lib/mongoid/criteria/queryable/key.rb +1 -1
  45. data/lib/mongoid/criteria/queryable/mergeable.rb +1 -1
  46. data/lib/mongoid/criteria/queryable/optional.rb +8 -8
  47. data/lib/mongoid/criteria/queryable/selectable.rb +43 -12
  48. data/lib/mongoid/criteria.rb +6 -5
  49. data/lib/mongoid/deprecable.rb +1 -1
  50. data/lib/mongoid/errors/create_collection_failure.rb +33 -0
  51. data/lib/mongoid/errors/drop_collection_failure.rb +27 -0
  52. data/lib/mongoid/errors/immutable_attribute.rb +26 -0
  53. data/lib/mongoid/errors/invalid_async_query_executor.rb +25 -0
  54. data/lib/mongoid/errors/invalid_global_executor_concurrency.rb +22 -0
  55. data/lib/mongoid/errors/invalid_storage_parent.rb +2 -0
  56. data/lib/mongoid/errors.rb +4 -1
  57. data/lib/mongoid/extensions/object.rb +2 -2
  58. data/lib/mongoid/extensions/time.rb +2 -0
  59. data/lib/mongoid/fields/localized.rb +10 -0
  60. data/lib/mongoid/fields/standard.rb +10 -0
  61. data/lib/mongoid/fields.rb +69 -13
  62. data/lib/mongoid/findable.rb +27 -3
  63. data/lib/mongoid/interceptable.rb +7 -6
  64. data/lib/mongoid/matcher/eq_impl.rb +1 -1
  65. data/lib/mongoid/matcher/type.rb +1 -1
  66. data/lib/mongoid/persistable/creatable.rb +1 -0
  67. data/lib/mongoid/persistable/deletable.rb +1 -1
  68. data/lib/mongoid/persistable/savable.rb +13 -1
  69. data/lib/mongoid/persistable/unsettable.rb +2 -2
  70. data/lib/mongoid/persistable/updatable.rb +51 -1
  71. data/lib/mongoid/persistable/upsertable.rb +20 -1
  72. data/lib/mongoid/persistable.rb +3 -0
  73. data/lib/mongoid/query_cache.rb +5 -1
  74. data/lib/mongoid/railties/database.rake +7 -2
  75. data/lib/mongoid/stateful.rb +22 -1
  76. data/lib/mongoid/tasks/database.rake +12 -0
  77. data/lib/mongoid/tasks/database.rb +20 -0
  78. data/lib/mongoid/utils.rb +22 -0
  79. data/lib/mongoid/validatable/macros.rb +5 -5
  80. data/lib/mongoid/validatable.rb +4 -1
  81. data/lib/mongoid/version.rb +1 -1
  82. data/lib/mongoid/warnings.rb +17 -1
  83. data/lib/mongoid.rb +16 -3
  84. data/spec/integration/app_spec.rb +2 -2
  85. data/spec/integration/callbacks_models.rb +37 -0
  86. data/spec/integration/callbacks_spec.rb +134 -0
  87. data/spec/integration/discriminator_key_spec.rb +4 -5
  88. data/spec/integration/i18n_fallbacks_spec.rb +3 -2
  89. data/spec/mongoid/association/embedded/embedded_in/proxy_spec.rb +27 -0
  90. data/spec/mongoid/association/embedded/embeds_many/proxy_spec.rb +20 -25
  91. data/spec/mongoid/association/embedded/embeds_many_models.rb +1 -0
  92. data/spec/mongoid/association/embedded/embeds_one/proxy_spec.rb +15 -2
  93. data/spec/mongoid/association/referenced/belongs_to_spec.rb +2 -18
  94. data/spec/mongoid/association/referenced/has_and_belongs_to_many/proxy_spec.rb +5 -27
  95. data/spec/mongoid/association/referenced/has_many/proxy_spec.rb +9 -50
  96. data/spec/mongoid/association/syncable_spec.rb +1 -1
  97. data/spec/mongoid/attributes_spec.rb +3 -6
  98. data/spec/mongoid/changeable_spec.rb +299 -24
  99. data/spec/mongoid/clients_spec.rb +122 -13
  100. data/spec/mongoid/collection_configurable_spec.rb +158 -0
  101. data/spec/mongoid/config/defaults_spec.rb +160 -0
  102. data/spec/mongoid/config_spec.rb +154 -18
  103. data/spec/mongoid/contextual/memory_spec.rb +332 -76
  104. data/spec/mongoid/contextual/mongo/documents_loader_spec.rb +187 -0
  105. data/spec/mongoid/contextual/mongo_spec.rb +995 -36
  106. data/spec/mongoid/contextual/none_spec.rb +49 -2
  107. data/spec/mongoid/copyable_spec.rb +3 -11
  108. data/spec/mongoid/criteria/queryable/extensions/string_spec.rb +4 -10
  109. data/spec/mongoid/criteria/queryable/options_spec.rb +1 -1
  110. data/spec/mongoid/criteria/queryable/selectable_logical_spec.rb +419 -0
  111. data/spec/mongoid/criteria/queryable/selectable_spec.rb +1 -1
  112. data/spec/mongoid/criteria/queryable/selector_spec.rb +1 -1
  113. data/spec/mongoid/criteria_projection_spec.rb +1 -4
  114. data/spec/mongoid/criteria_spec.rb +5 -9
  115. data/spec/mongoid/errors/readonly_document_spec.rb +2 -2
  116. data/spec/mongoid/extensions/time_spec.rb +8 -43
  117. data/spec/mongoid/extensions/time_with_zone_spec.rb +7 -52
  118. data/spec/mongoid/fields/localized_spec.rb +46 -28
  119. data/spec/mongoid/fields_spec.rb +136 -34
  120. data/spec/mongoid/findable_spec.rb +391 -34
  121. data/spec/mongoid/indexable_spec.rb +16 -10
  122. data/spec/mongoid/interceptable_spec.rb +15 -3
  123. data/spec/mongoid/persistable/deletable_spec.rb +26 -6
  124. data/spec/mongoid/persistable/destroyable_spec.rb +26 -6
  125. data/spec/mongoid/persistable/incrementable_spec.rb +37 -0
  126. data/spec/mongoid/persistable/logical_spec.rb +37 -0
  127. data/spec/mongoid/persistable/poppable_spec.rb +36 -0
  128. data/spec/mongoid/persistable/pullable_spec.rb +72 -0
  129. data/spec/mongoid/persistable/pushable_spec.rb +72 -0
  130. data/spec/mongoid/persistable/renamable_spec.rb +36 -0
  131. data/spec/mongoid/persistable/savable_spec.rb +96 -0
  132. data/spec/mongoid/persistable/settable_spec.rb +37 -0
  133. data/spec/mongoid/persistable/unsettable_spec.rb +36 -0
  134. data/spec/mongoid/persistable/updatable_spec.rb +20 -28
  135. data/spec/mongoid/persistable/upsertable_spec.rb +80 -6
  136. data/spec/mongoid/persistence_context_spec.rb +7 -57
  137. data/spec/mongoid/query_cache_spec.rb +56 -61
  138. data/spec/mongoid/reloadable_spec.rb +24 -4
  139. data/spec/mongoid/scopable_spec.rb +70 -0
  140. data/spec/mongoid/serializable_spec.rb +9 -30
  141. data/spec/mongoid/stateful_spec.rb +122 -8
  142. data/spec/mongoid/tasks/database_rake_spec.rb +74 -0
  143. data/spec/mongoid/tasks/database_spec.rb +127 -0
  144. data/spec/mongoid/timestamps_spec.rb +9 -11
  145. data/spec/mongoid/touchable_spec.rb +277 -5
  146. data/spec/mongoid/touchable_spec_models.rb +3 -1
  147. data/spec/mongoid/traversable_spec.rb +9 -24
  148. data/spec/mongoid/validatable/uniqueness_spec.rb +2 -3
  149. data/spec/mongoid_spec.rb +35 -9
  150. data/spec/shared/lib/mrss/docker_runner.rb +7 -0
  151. data/spec/shared/lib/mrss/event_subscriber.rb +15 -5
  152. data/spec/shared/lib/mrss/lite_constraints.rb +10 -2
  153. data/spec/shared/lib/mrss/server_version_registry.rb +16 -23
  154. data/spec/shared/lib/mrss/utils.rb +28 -6
  155. data/spec/shared/share/Dockerfile.erb +36 -40
  156. data/spec/shared/shlib/server.sh +32 -8
  157. data/spec/shared/shlib/set_env.sh +4 -4
  158. data/spec/spec_helper.rb +5 -0
  159. data/spec/support/immutable_ids.rb +118 -0
  160. data/spec/support/macros.rb +47 -15
  161. data/spec/support/models/artist.rb +0 -1
  162. data/spec/support/models/band.rb +1 -0
  163. data/spec/support/models/book.rb +1 -0
  164. data/spec/support/models/building.rb +2 -0
  165. data/spec/support/models/cover.rb +10 -0
  166. data/spec/support/models/product.rb +1 -0
  167. data.tar.gz.sig +0 -0
  168. metadata +43 -7
  169. metadata.gz.sig +0 -0
  170. data/spec/mongoid/criteria/queryable/extensions/bignum_spec.rb +0 -60
  171. 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