mongoid 8.0.10 → 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 (212) 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 +18 -67
  6. data/lib/config/locales/en.yml +46 -14
  7. data/lib/mongoid/association/accessors.rb +3 -7
  8. data/lib/mongoid/association/builders.rb +1 -1
  9. data/lib/mongoid/association/eager_loadable.rb +0 -3
  10. data/lib/mongoid/association/embedded/batchable.rb +2 -2
  11. data/lib/mongoid/association/embedded/embedded_in/buildable.rb +2 -2
  12. data/lib/mongoid/association/embedded/embedded_in/proxy.rb +2 -1
  13. data/lib/mongoid/association/embedded/embeds_many/buildable.rb +3 -2
  14. data/lib/mongoid/association/embedded/embeds_many/proxy.rb +6 -6
  15. data/lib/mongoid/association/embedded/embeds_one/buildable.rb +1 -1
  16. data/lib/mongoid/association/embedded/embeds_one/proxy.rb +1 -1
  17. data/lib/mongoid/association/macros.rb +0 -6
  18. data/lib/mongoid/association/nested/one.rb +40 -2
  19. data/lib/mongoid/association/proxy.rb +1 -1
  20. data/lib/mongoid/association/referenced/counter_cache.rb +2 -2
  21. data/lib/mongoid/association/referenced/has_and_belongs_to_many/proxy.rb +1 -1
  22. data/lib/mongoid/association/referenced/has_many/enumerable.rb +6 -23
  23. data/lib/mongoid/association/referenced/has_many/proxy.rb +3 -3
  24. data/lib/mongoid/association/reflections.rb +2 -2
  25. data/lib/mongoid/atomic.rb +7 -16
  26. data/lib/mongoid/attributes/dynamic.rb +1 -1
  27. data/lib/mongoid/attributes/nested.rb +2 -2
  28. data/lib/mongoid/attributes/processing.rb +5 -29
  29. data/lib/mongoid/attributes/projector.rb +1 -1
  30. data/lib/mongoid/attributes/readonly.rb +1 -1
  31. data/lib/mongoid/attributes.rb +8 -2
  32. data/lib/mongoid/changeable.rb +107 -5
  33. data/lib/mongoid/clients/storage_options.rb +2 -5
  34. data/lib/mongoid/clients/validators/storage.rb +1 -13
  35. data/lib/mongoid/collection_configurable.rb +58 -0
  36. data/lib/mongoid/composable.rb +2 -0
  37. data/lib/mongoid/config/defaults.rb +60 -0
  38. data/lib/mongoid/config/options.rb +0 -3
  39. data/lib/mongoid/config/validators/async_query_executor.rb +24 -0
  40. data/lib/mongoid/config/validators.rb +1 -0
  41. data/lib/mongoid/config.rb +88 -27
  42. data/lib/mongoid/contextual/atomic.rb +1 -1
  43. data/lib/mongoid/contextual/memory.rb +233 -33
  44. data/lib/mongoid/contextual/mongo/documents_loader.rb +177 -0
  45. data/lib/mongoid/contextual/mongo.rb +370 -133
  46. data/lib/mongoid/contextual/none.rb +162 -7
  47. data/lib/mongoid/contextual.rb +12 -0
  48. data/lib/mongoid/criteria/findable.rb +2 -2
  49. data/lib/mongoid/criteria/includable.rb +4 -3
  50. data/lib/mongoid/criteria/queryable/extensions/numeric.rb +1 -15
  51. data/lib/mongoid/criteria/queryable/key.rb +1 -1
  52. data/lib/mongoid/criteria/queryable/mergeable.rb +1 -1
  53. data/lib/mongoid/criteria/queryable/optional.rb +8 -8
  54. data/lib/mongoid/criteria/queryable/selectable.rb +43 -12
  55. data/lib/mongoid/criteria/queryable/selector.rb +1 -1
  56. data/lib/mongoid/criteria/queryable/storable.rb +1 -1
  57. data/lib/mongoid/criteria.rb +6 -5
  58. data/lib/mongoid/deprecable.rb +1 -2
  59. data/lib/mongoid/deprecation.rb +3 -3
  60. data/lib/mongoid/document.rb +1 -8
  61. data/lib/mongoid/errors/create_collection_failure.rb +33 -0
  62. data/lib/mongoid/errors/drop_collection_failure.rb +27 -0
  63. data/lib/mongoid/errors/immutable_attribute.rb +26 -0
  64. data/lib/mongoid/errors/invalid_async_query_executor.rb +25 -0
  65. data/lib/mongoid/errors/invalid_global_executor_concurrency.rb +22 -0
  66. data/lib/mongoid/errors/invalid_storage_parent.rb +2 -0
  67. data/lib/mongoid/errors.rb +4 -1
  68. data/lib/mongoid/extensions/hash.rb +2 -24
  69. data/lib/mongoid/extensions/object.rb +2 -2
  70. data/lib/mongoid/extensions/time.rb +2 -0
  71. data/lib/mongoid/fields/localized.rb +10 -0
  72. data/lib/mongoid/fields/standard.rb +10 -0
  73. data/lib/mongoid/fields.rb +59 -35
  74. data/lib/mongoid/findable.rb +27 -3
  75. data/lib/mongoid/interceptable.rb +6 -116
  76. data/lib/mongoid/matcher/eq_impl.rb +1 -1
  77. data/lib/mongoid/matcher/type.rb +1 -1
  78. data/lib/mongoid/persistable/creatable.rb +1 -0
  79. data/lib/mongoid/persistable/deletable.rb +1 -1
  80. data/lib/mongoid/persistable/savable.rb +13 -1
  81. data/lib/mongoid/persistable/unsettable.rb +2 -2
  82. data/lib/mongoid/persistable/updatable.rb +51 -1
  83. data/lib/mongoid/persistable/upsertable.rb +20 -1
  84. data/lib/mongoid/persistable.rb +3 -0
  85. data/lib/mongoid/query_cache.rb +5 -1
  86. data/lib/mongoid/railties/database.rake +7 -2
  87. data/lib/mongoid/reloadable.rb +5 -3
  88. data/lib/mongoid/stateful.rb +22 -1
  89. data/lib/mongoid/tasks/database.rake +12 -0
  90. data/lib/mongoid/tasks/database.rb +20 -0
  91. data/lib/mongoid/timestamps/created.rb +1 -8
  92. data/lib/mongoid/traversable.rb +0 -12
  93. data/lib/mongoid/utils.rb +22 -0
  94. data/lib/mongoid/validatable/associated.rb +17 -98
  95. data/lib/mongoid/validatable/macros.rb +5 -5
  96. data/lib/mongoid/validatable.rb +4 -9
  97. data/lib/mongoid/version.rb +1 -1
  98. data/lib/mongoid/warnings.rb +17 -1
  99. data/lib/mongoid.rb +16 -3
  100. data/spec/integration/app_spec.rb +2 -6
  101. data/spec/integration/associations/has_and_belongs_to_many_spec.rb +0 -40
  102. data/spec/integration/callbacks_spec.rb +99 -12
  103. data/spec/integration/discriminator_key_spec.rb +4 -5
  104. data/spec/integration/i18n_fallbacks_spec.rb +3 -2
  105. data/spec/mongoid/association/eager_spec.rb +2 -24
  106. data/spec/mongoid/association/embedded/embedded_in/proxy_spec.rb +27 -0
  107. data/spec/mongoid/association/embedded/embeds_many/proxy_spec.rb +20 -25
  108. data/spec/mongoid/association/embedded/embeds_many_models.rb +1 -0
  109. data/spec/mongoid/association/embedded/embeds_many_query_spec.rb +0 -4
  110. data/spec/mongoid/association/embedded/embeds_one/proxy_spec.rb +15 -2
  111. data/spec/mongoid/association/referenced/belongs_to_spec.rb +2 -18
  112. data/spec/mongoid/association/referenced/has_and_belongs_to_many/proxy_spec.rb +42 -55
  113. data/spec/mongoid/association/referenced/has_many/proxy_spec.rb +9 -50
  114. data/spec/mongoid/association/syncable_spec.rb +1 -1
  115. data/spec/mongoid/association_spec.rb +0 -60
  116. data/spec/mongoid/attributes_spec.rb +3 -33
  117. data/spec/mongoid/changeable_spec.rb +299 -24
  118. data/spec/mongoid/clients_spec.rb +122 -13
  119. data/spec/mongoid/collection_configurable_spec.rb +158 -0
  120. data/spec/mongoid/config/defaults_spec.rb +160 -0
  121. data/spec/mongoid/config_spec.rb +154 -27
  122. data/spec/mongoid/contextual/memory_spec.rb +332 -76
  123. data/spec/mongoid/contextual/mongo/documents_loader_spec.rb +187 -0
  124. data/spec/mongoid/contextual/mongo_spec.rb +1009 -125
  125. data/spec/mongoid/contextual/none_spec.rb +49 -2
  126. data/spec/mongoid/copyable_spec.rb +2 -10
  127. data/spec/mongoid/criteria/queryable/extensions/string_spec.rb +4 -10
  128. data/spec/mongoid/criteria/queryable/options_spec.rb +1 -1
  129. data/spec/mongoid/criteria/queryable/selectable_logical_spec.rb +419 -0
  130. data/spec/mongoid/criteria/queryable/selectable_spec.rb +1 -1
  131. data/spec/mongoid/criteria/queryable/selector_spec.rb +3 -76
  132. data/spec/mongoid/criteria/queryable/storable_spec.rb +0 -72
  133. data/spec/mongoid/criteria_projection_spec.rb +1 -4
  134. data/spec/mongoid/criteria_spec.rb +5 -9
  135. data/spec/mongoid/document_spec.rb +0 -27
  136. data/spec/mongoid/errors/readonly_document_spec.rb +2 -2
  137. data/spec/mongoid/extensions/hash_spec.rb +3 -3
  138. data/spec/mongoid/extensions/time_spec.rb +8 -43
  139. data/spec/mongoid/extensions/time_with_zone_spec.rb +7 -52
  140. data/spec/mongoid/fields/localized_spec.rb +46 -28
  141. data/spec/mongoid/fields_spec.rb +136 -77
  142. data/spec/mongoid/findable_spec.rb +391 -34
  143. data/spec/mongoid/indexable_spec.rb +16 -10
  144. data/spec/mongoid/interceptable_spec.rb +153 -442
  145. data/spec/mongoid/interceptable_spec_models.rb +111 -51
  146. data/spec/mongoid/persistable/deletable_spec.rb +26 -6
  147. data/spec/mongoid/persistable/destroyable_spec.rb +26 -6
  148. data/spec/mongoid/persistable/incrementable_spec.rb +37 -0
  149. data/spec/mongoid/persistable/logical_spec.rb +37 -0
  150. data/spec/mongoid/persistable/poppable_spec.rb +36 -0
  151. data/spec/mongoid/persistable/pullable_spec.rb +72 -0
  152. data/spec/mongoid/persistable/pushable_spec.rb +72 -0
  153. data/spec/mongoid/persistable/renamable_spec.rb +36 -0
  154. data/spec/mongoid/persistable/savable_spec.rb +96 -0
  155. data/spec/mongoid/persistable/settable_spec.rb +37 -0
  156. data/spec/mongoid/persistable/unsettable_spec.rb +36 -0
  157. data/spec/mongoid/persistable/updatable_spec.rb +20 -28
  158. data/spec/mongoid/persistable/upsertable_spec.rb +80 -6
  159. data/spec/mongoid/persistence_context_spec.rb +7 -57
  160. data/spec/mongoid/query_cache_spec.rb +56 -61
  161. data/spec/mongoid/reloadable_spec.rb +24 -28
  162. data/spec/mongoid/scopable_spec.rb +70 -0
  163. data/spec/mongoid/serializable_spec.rb +23 -44
  164. data/spec/mongoid/stateful_spec.rb +122 -8
  165. data/spec/mongoid/tasks/database_rake_spec.rb +74 -0
  166. data/spec/mongoid/tasks/database_spec.rb +127 -0
  167. data/spec/mongoid/timestamps/created_spec.rb +0 -23
  168. data/spec/mongoid/timestamps_spec.rb +9 -11
  169. data/spec/mongoid/touchable_spec.rb +277 -5
  170. data/spec/mongoid/touchable_spec_models.rb +3 -1
  171. data/spec/mongoid/traversable_spec.rb +9 -24
  172. data/spec/mongoid/validatable/associated_spec.rb +34 -27
  173. data/spec/mongoid/validatable/uniqueness_spec.rb +2 -3
  174. data/spec/mongoid_spec.rb +36 -10
  175. data/spec/shared/LICENSE +20 -0
  176. data/spec/shared/bin/get-mongodb-download-url +17 -0
  177. data/spec/shared/bin/s3-copy +45 -0
  178. data/spec/shared/bin/s3-upload +69 -0
  179. data/spec/shared/lib/mrss/child_process_helper.rb +80 -0
  180. data/spec/shared/lib/mrss/cluster_config.rb +231 -0
  181. data/spec/shared/lib/mrss/constraints.rb +378 -0
  182. data/spec/shared/lib/mrss/docker_runner.rb +298 -0
  183. data/spec/shared/lib/mrss/eg_config_utils.rb +51 -0
  184. data/spec/shared/lib/mrss/event_subscriber.rb +210 -0
  185. data/spec/shared/lib/mrss/lite_constraints.rb +238 -0
  186. data/spec/shared/lib/mrss/server_version_registry.rb +113 -0
  187. data/spec/shared/lib/mrss/session_registry.rb +69 -0
  188. data/spec/shared/lib/mrss/session_registry_legacy.rb +60 -0
  189. data/spec/shared/lib/mrss/spec_organizer.rb +179 -0
  190. data/spec/shared/lib/mrss/utils.rb +37 -0
  191. data/spec/shared/share/Dockerfile.erb +321 -0
  192. data/spec/shared/share/haproxy-1.conf +16 -0
  193. data/spec/shared/share/haproxy-2.conf +17 -0
  194. data/spec/shared/shlib/config.sh +27 -0
  195. data/spec/shared/shlib/distro.sh +74 -0
  196. data/spec/shared/shlib/server.sh +416 -0
  197. data/spec/shared/shlib/set_env.sh +169 -0
  198. data/spec/spec_helper.rb +5 -0
  199. data/spec/support/immutable_ids.rb +118 -0
  200. data/spec/support/macros.rb +47 -15
  201. data/spec/support/models/artist.rb +0 -1
  202. data/spec/support/models/band.rb +1 -0
  203. data/spec/support/models/building.rb +2 -0
  204. data/spec/support/models/name.rb +0 -10
  205. data/spec/support/models/person.rb +0 -1
  206. data/spec/support/models/product.rb +1 -0
  207. data.tar.gz.sig +0 -0
  208. metadata +745 -637
  209. metadata.gz.sig +2 -0
  210. data/spec/mongoid/criteria/queryable/extensions/bignum_spec.rb +0 -60
  211. data/spec/mongoid/criteria/queryable/extensions/fixnum_spec.rb +0 -60
  212. data/spec/support/models/purse.rb +0 -9
@@ -158,16 +158,6 @@ describe Mongoid::Contextual::Mongo do
158
158
  end
159
159
  end
160
160
  end
161
-
162
- context 'when for_js is present' do
163
- let(:context) do
164
- Band.for_js('this.name == "Depeche Mode"')
165
- end
166
-
167
- it 'counts the expected records' do
168
- expect(context.count).to eq(1)
169
- end
170
- end
171
161
  end
172
162
 
173
163
  describe "#estimated_count" do
@@ -571,6 +561,8 @@ describe Mongoid::Contextual::Mongo do
571
561
  end
572
562
 
573
563
  context "when getting a localized field" do
564
+ with_default_i18n_configs
565
+
574
566
  before do
575
567
  I18n.locale = :en
576
568
  d = Dictionary.create!(description: 'english-text')
@@ -670,13 +662,11 @@ describe Mongoid::Contextual::Mongo do
670
662
  end
671
663
 
672
664
  context 'when fallbacks are enabled with a locale list' do
673
- with_i18n_fallbacks
665
+ require_fallbacks
666
+ with_default_i18n_configs
674
667
 
675
- around(:all) do |example|
676
- prev_fallbacks = I18n.fallbacks.dup
668
+ before do
677
669
  I18n.fallbacks[:he] = [ :en ]
678
- example.run
679
- I18n.fallbacks = prev_fallbacks
680
670
  end
681
671
 
682
672
  let(:distinct) do
@@ -704,6 +694,8 @@ describe Mongoid::Contextual::Mongo do
704
694
  end
705
695
 
706
696
  context "when the localized field is embedded" do
697
+ with_default_i18n_configs
698
+
707
699
  before do
708
700
  p = Passport.new
709
701
  I18n.locale = :en
@@ -849,6 +841,8 @@ describe Mongoid::Contextual::Mongo do
849
841
  end
850
842
 
851
843
  context "when tallying a localized field" do
844
+ with_default_i18n_configs
845
+
852
846
  before do
853
847
  I18n.locale = :en
854
848
  d1 = Dictionary.create!(description: 'en1')
@@ -903,6 +897,7 @@ describe Mongoid::Contextual::Mongo do
903
897
  end
904
898
 
905
899
  context "when tallying an embedded localized field" do
900
+ with_default_i18n_configs
906
901
 
907
902
  before do
908
903
  I18n.locale = :en
@@ -1189,49 +1184,33 @@ describe Mongoid::Contextual::Mongo do
1189
1184
  let!(:person2) { Person.create!(ssn: BSON::Decimal128.new("1")) }
1190
1185
  let(:tally) { Person.tally("ssn") }
1191
1186
 
1192
- let(:tallied_classes) do
1193
- tally.keys.map(&:class).sort do |a, b|
1194
- a.to_s.casecmp(b.to_s)
1195
- end
1196
- end
1197
-
1198
1187
  context "< BSON 5" do
1199
1188
  max_bson_version '4.99.99'
1200
1189
 
1201
1190
  it "stores the correct types in the database" do
1202
- expect(Person.find(person1.id).attributes["ssn"]).to be_a BSON::Regexp::Raw
1203
- expect(Person.find(person2.id).attributes["ssn"]).to be_a BSON::Decimal128
1204
- end
1205
-
1206
- it "tallies the correct type" do
1207
- expect(tallied_classes).to be == [ BSON::Decimal128, BSON::Regexp::Raw ]
1208
- end
1209
- end
1210
-
1211
- context '>= BSON 5' do
1212
- min_bson_version "5.0"
1213
-
1214
- it "stores the correct types in the database" do
1215
- expect(Person.find(person1.id).ssn).to be_a BSON::Regexp::Raw
1216
- expect(Person.find(person2.id).ssn).to be_a BigDecimal
1191
+ Person.find(person1.id).attributes["ssn"].should be_a BSON::Regexp::Raw
1192
+ Person.find(person2.id).attributes["ssn"].should be_a BSON::Decimal128
1217
1193
  end
1218
1194
 
1219
1195
  it "tallies the correct type" do
1220
- expect(tallied_classes).to be == [ BigDecimal, BSON::Regexp::Raw ]
1196
+ tally.keys.map(&:class).sort do |a,b|
1197
+ a.to_s <=> b.to_s
1198
+ end.should == [BSON::Decimal128, BSON::Regexp::Raw]
1221
1199
  end
1222
1200
  end
1223
1201
 
1224
- context '>= BSON 5 with decimal128 allowed' do
1202
+ context ">= BSON 5" do
1225
1203
  min_bson_version "5.0"
1226
- config_override :allow_bson5_decimal128, true
1227
1204
 
1228
1205
  it "stores the correct types in the database" do
1229
- expect(Person.find(person1.id).ssn).to be_a BSON::Regexp::Raw
1230
- expect(Person.find(person2.id).ssn).to be_a BSON::Decimal128
1206
+ Person.find(person1.id).ssn.should be_a BSON::Regexp::Raw
1207
+ Person.find(person2.id).ssn.should be_a BigDeimal
1231
1208
  end
1232
1209
 
1233
1210
  it "tallies the correct type" do
1234
- expect(tallied_classes).to be == [ BSON::Decimal128, BSON::Regexp::Raw ]
1211
+ tally.keys.map(&:class).sort do |a,b|
1212
+ a.to_s <=> b.to_s
1213
+ end.should == [BigDecimal, BSON::Regexp::Raw]
1235
1214
  end
1236
1215
  end
1237
1216
  end
@@ -1401,64 +1380,177 @@ describe Mongoid::Contextual::Mongo do
1401
1380
 
1402
1381
  describe "#exists?" do
1403
1382
 
1404
- before do
1405
- Band.create!(name: "Depeche Mode")
1383
+ let!(:band) do
1384
+ Band.create!(name: "Depeche Mode", active: true)
1406
1385
  end
1407
1386
 
1408
- context "when the count is zero" do
1387
+ context "when not passing options" do
1409
1388
 
1410
- let(:criteria) do
1411
- 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
1412
1402
  end
1413
1403
 
1414
- let(:context) do
1415
- 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
1416
1417
  end
1417
1418
 
1418
- it "returns false" do
1419
- 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
1420
1442
  end
1421
1443
  end
1422
1444
 
1423
- context "when the count is greater than zero" do
1445
+ context "when passing an _id" do
1424
1446
 
1425
- let(:criteria) do
1426
- Band.where(name: "Depeche Mode")
1427
- end
1447
+ context "when its of type BSON::ObjectId" do
1428
1448
 
1429
- let(:context) do
1430
- 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
1431
1476
  end
1432
1477
 
1433
- it "returns true" do
1434
- 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
1435
1493
  end
1436
1494
  end
1437
1495
 
1438
- context "when caching is not enabled" do
1496
+ context "when passing a hash" do
1439
1497
 
1440
- let(:criteria) do
1441
- 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
1442
1503
  end
1443
1504
 
1444
- let(:context) do
1445
- 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
1446
1510
  end
1447
1511
 
1448
- context "when exists? already called and query cache is enabled" do
1449
- query_cache_enabled
1512
+ context "when calling it on a criteria that does not include the object" do
1450
1513
 
1451
- before do
1452
- context.exists?
1514
+ it "returns false" do
1515
+ expect(Band.where(active: false).exists?(name: band.name)).to be false
1453
1516
  end
1517
+ end
1454
1518
 
1455
- it "does not hit the database again" do
1456
- expect_no_queries do
1457
- expect(context).to be_exists
1458
- 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
1459
1523
  end
1460
1524
  end
1461
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
1462
1554
  end
1463
1555
 
1464
1556
  describe "#explain" do
@@ -1472,7 +1564,16 @@ describe Mongoid::Contextual::Mongo do
1472
1564
  end
1473
1565
 
1474
1566
  it "returns the criteria explain path" do
1475
- 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")
1476
1577
  end
1477
1578
  end
1478
1579
 
@@ -3573,65 +3674,16 @@ describe Mongoid::Contextual::Mongo do
3573
3674
 
3574
3675
  context "when the attributes are in the correct type" do
3575
3676
 
3576
- context "when operation is $set" do
3577
-
3578
- before do
3579
- context.update_all("$set" => { name: "Smiths" })
3580
- end
3581
-
3582
- it "updates the first matching document" do
3583
- expect(depeche_mode.reload.name).to eq("Smiths")
3584
- end
3585
-
3586
- it "updates the last matching document" do
3587
- expect(new_order.reload.name).to eq("Smiths")
3588
- end
3589
- end
3590
-
3591
- context "when operation is $push" do
3592
-
3593
- before do
3594
- depeche_mode.update_attribute(:genres, ["electronic"])
3595
- new_order.update_attribute(:genres, ["electronic"])
3596
- context.update_all("$push" => { genres: "pop" })
3597
- end
3598
-
3599
- it "updates the first matching document" do
3600
- expect(depeche_mode.reload.genres).to eq(["electronic", "pop"])
3601
- end
3602
-
3603
- it "updates the last matching document" do
3604
- expect(new_order.reload.genres).to eq(["electronic", "pop"])
3605
- end
3606
- end
3607
-
3608
- context "when operation is $addToSet" do
3609
-
3610
- before do
3611
- context.update_all("$addToSet" => { genres: "electronic" })
3612
- end
3613
-
3614
- it "updates the first matching document" do
3615
- expect(depeche_mode.reload.genres).to eq(["electronic"])
3616
- end
3617
-
3618
- it "updates the last matching document" do
3619
- expect(new_order.reload.genres).to eq(["electronic"])
3620
- end
3621
- end
3622
- end
3623
-
3624
- context 'when using aliased field names' do
3625
3677
  before do
3626
- context.update_all('$set' => { years: 100 })
3678
+ context.update_all("$set" => { name: "Smiths" })
3627
3679
  end
3628
3680
 
3629
3681
  it "updates the first matching document" do
3630
- expect(depeche_mode.reload.years).to eq(100)
3682
+ expect(depeche_mode.reload.name).to eq("Smiths")
3631
3683
  end
3632
3684
 
3633
3685
  it "updates the last matching document" do
3634
- expect(new_order.reload.years).to eq(100)
3686
+ expect(new_order.reload.name).to eq("Smiths")
3635
3687
  end
3636
3688
  end
3637
3689
 
@@ -3749,4 +3801,836 @@ describe Mongoid::Contextual::Mongo do
3749
3801
  end
3750
3802
  end
3751
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
3752
4636
  end