mongoid 7.5.4 → 8.0.1

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 (298) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/README.md +3 -3
  4. data/Rakefile +0 -25
  5. data/lib/config/locales/en.yml +46 -30
  6. data/lib/mongoid/association/accessors.rb +32 -3
  7. data/lib/mongoid/association/bindable.rb +48 -0
  8. data/lib/mongoid/association/builders.rb +4 -2
  9. data/lib/mongoid/association/eager_loadable.rb +29 -7
  10. data/lib/mongoid/association/embedded/batchable.rb +28 -5
  11. data/lib/mongoid/association/embedded/embedded_in/binding.rb +24 -2
  12. data/lib/mongoid/association/embedded/embedded_in.rb +2 -1
  13. data/lib/mongoid/association/embedded/embeds_many/binding.rb +1 -0
  14. data/lib/mongoid/association/embedded/embeds_many/buildable.rb +1 -1
  15. data/lib/mongoid/association/embedded/embeds_many/proxy.rb +40 -18
  16. data/lib/mongoid/association/embedded/embeds_one/buildable.rb +18 -4
  17. data/lib/mongoid/association/embedded/embeds_one/proxy.rb +21 -2
  18. data/lib/mongoid/association/macros.rb +2 -1
  19. data/lib/mongoid/association/many.rb +5 -0
  20. data/lib/mongoid/association/nested/many.rb +2 -1
  21. data/lib/mongoid/association/proxy.rb +12 -0
  22. data/lib/mongoid/association/referenced/auto_save.rb +3 -2
  23. data/lib/mongoid/association/referenced/belongs_to/binding.rb +1 -0
  24. data/lib/mongoid/association/referenced/belongs_to/buildable.rb +1 -1
  25. data/lib/mongoid/association/referenced/belongs_to.rb +1 -1
  26. data/lib/mongoid/association/referenced/counter_cache.rb +8 -8
  27. data/lib/mongoid/association/referenced/has_and_belongs_to_many/proxy.rb +64 -11
  28. data/lib/mongoid/association/referenced/has_and_belongs_to_many.rb +4 -1
  29. data/lib/mongoid/association/referenced/has_many/enumerable.rb +10 -18
  30. data/lib/mongoid/association/referenced/has_many/proxy.rb +12 -9
  31. data/lib/mongoid/association/referenced/has_one/buildable.rb +1 -1
  32. data/lib/mongoid/association/referenced/has_one/proxy.rb +8 -11
  33. data/lib/mongoid/association/referenced/syncable.rb +2 -2
  34. data/lib/mongoid/association/relatable.rb +38 -4
  35. data/lib/mongoid/attributes/processing.rb +9 -2
  36. data/lib/mongoid/attributes.rb +30 -27
  37. data/lib/mongoid/cacheable.rb +2 -2
  38. data/lib/mongoid/changeable.rb +37 -2
  39. data/lib/mongoid/clients/options.rb +4 -0
  40. data/lib/mongoid/clients/sessions.rb +2 -14
  41. data/lib/mongoid/config.rb +15 -11
  42. data/lib/mongoid/contextual/aggregable/memory.rb +23 -15
  43. data/lib/mongoid/contextual/aggregable/mongo.rb +1 -1
  44. data/lib/mongoid/contextual/map_reduce.rb +2 -2
  45. data/lib/mongoid/contextual/memory.rb +55 -28
  46. data/lib/mongoid/contextual/mongo.rb +173 -262
  47. data/lib/mongoid/contextual/none.rb +33 -15
  48. data/lib/mongoid/copyable.rb +32 -8
  49. data/lib/mongoid/criteria/includable.rb +24 -20
  50. data/lib/mongoid/criteria/marshalable.rb +10 -2
  51. data/lib/mongoid/criteria/queryable/extensions/array.rb +2 -15
  52. data/lib/mongoid/criteria/queryable/extensions/big_decimal.rb +25 -4
  53. data/lib/mongoid/criteria/queryable/extensions/boolean.rb +1 -1
  54. data/lib/mongoid/criteria/queryable/extensions/date.rb +6 -1
  55. data/lib/mongoid/criteria/queryable/extensions/date_time.rb +6 -1
  56. data/lib/mongoid/criteria/queryable/extensions/hash.rb +0 -16
  57. data/lib/mongoid/criteria/queryable/extensions/numeric.rb +1 -1
  58. data/lib/mongoid/criteria/queryable/extensions/object.rb +2 -1
  59. data/lib/mongoid/criteria/queryable/extensions/range.rb +13 -5
  60. data/lib/mongoid/criteria/queryable/extensions/regexp.rb +1 -1
  61. data/lib/mongoid/criteria/queryable/extensions/symbol.rb +3 -1
  62. data/lib/mongoid/criteria/queryable/extensions/time.rb +6 -1
  63. data/lib/mongoid/criteria/queryable/extensions/time_with_zone.rb +6 -1
  64. data/lib/mongoid/criteria/queryable/optional.rb +3 -9
  65. data/lib/mongoid/criteria/queryable/options.rb +1 -1
  66. data/lib/mongoid/criteria/queryable/selectable.rb +2 -24
  67. data/lib/mongoid/criteria/queryable/selector.rb +90 -5
  68. data/lib/mongoid/criteria/queryable/smash.rb +39 -6
  69. data/lib/mongoid/criteria/queryable/storable.rb +1 -1
  70. data/lib/mongoid/criteria/queryable.rb +11 -6
  71. data/lib/mongoid/criteria.rb +1 -28
  72. data/lib/mongoid/deprecable.rb +36 -0
  73. data/lib/mongoid/deprecation.rb +25 -0
  74. data/lib/mongoid/document.rb +88 -33
  75. data/lib/mongoid/equality.rb +4 -4
  76. data/lib/mongoid/errors/document_not_found.rb +6 -2
  77. data/lib/mongoid/errors/invalid_dot_dollar_assignment.rb +23 -0
  78. data/lib/mongoid/errors/invalid_field.rb +5 -1
  79. data/lib/mongoid/errors/invalid_field_type.rb +26 -0
  80. data/lib/mongoid/errors/too_many_nested_attribute_records.rb +1 -1
  81. data/lib/mongoid/errors.rb +2 -2
  82. data/lib/mongoid/extensions/array.rb +8 -6
  83. data/lib/mongoid/extensions/big_decimal.rb +29 -10
  84. data/lib/mongoid/extensions/binary.rb +42 -0
  85. data/lib/mongoid/extensions/boolean.rb +8 -2
  86. data/lib/mongoid/extensions/date.rb +26 -20
  87. data/lib/mongoid/extensions/date_time.rb +1 -1
  88. data/lib/mongoid/extensions/float.rb +4 -5
  89. data/lib/mongoid/extensions/hash.rb +12 -5
  90. data/lib/mongoid/extensions/integer.rb +4 -5
  91. data/lib/mongoid/extensions/object.rb +2 -0
  92. data/lib/mongoid/extensions/range.rb +41 -10
  93. data/lib/mongoid/extensions/regexp.rb +11 -4
  94. data/lib/mongoid/extensions/set.rb +11 -4
  95. data/lib/mongoid/extensions/string.rb +2 -13
  96. data/lib/mongoid/extensions/symbol.rb +3 -14
  97. data/lib/mongoid/extensions/time.rb +27 -16
  98. data/lib/mongoid/extensions/time_with_zone.rb +1 -2
  99. data/lib/mongoid/extensions.rb +1 -0
  100. data/lib/mongoid/factory.rb +42 -7
  101. data/lib/mongoid/fields/foreign_key.rb +7 -0
  102. data/lib/mongoid/fields/validators/macro.rb +3 -9
  103. data/lib/mongoid/fields.rb +49 -7
  104. data/lib/mongoid/findable.rb +21 -16
  105. data/lib/mongoid/indexable/specification.rb +1 -1
  106. data/lib/mongoid/indexable/validators/options.rb +4 -1
  107. data/lib/mongoid/interceptable.rb +69 -9
  108. data/lib/mongoid/persistable/creatable.rb +14 -5
  109. data/lib/mongoid/persistable/updatable.rb +12 -5
  110. data/lib/mongoid/persistence_context.rb +8 -42
  111. data/lib/mongoid/query_cache.rb +6 -258
  112. data/lib/mongoid/railties/controller_runtime.rb +1 -1
  113. data/lib/mongoid/reloadable.rb +7 -3
  114. data/lib/mongoid/scopable.rb +9 -11
  115. data/lib/mongoid/selectable.rb +1 -2
  116. data/lib/mongoid/shardable.rb +11 -35
  117. data/lib/mongoid/stateful.rb +27 -1
  118. data/lib/mongoid/timestamps/created.rb +1 -1
  119. data/lib/mongoid/timestamps/updated.rb +1 -1
  120. data/lib/mongoid/touchable.rb +2 -3
  121. data/lib/mongoid/traversable.rb +1 -0
  122. data/lib/mongoid/validatable/uniqueness.rb +2 -1
  123. data/lib/mongoid/version.rb +1 -1
  124. data/lib/mongoid/warnings.rb +3 -4
  125. data/lib/mongoid.rb +1 -0
  126. data/spec/config/mongoid.yml +16 -0
  127. data/spec/integration/app_spec.rb +8 -12
  128. data/spec/integration/associations/belongs_to_spec.rb +18 -0
  129. data/spec/integration/associations/embedded_spec.rb +15 -0
  130. data/spec/integration/associations/embeds_many_spec.rb +15 -2
  131. data/spec/integration/associations/embeds_one_spec.rb +18 -0
  132. data/spec/integration/associations/foreign_key_spec.rb +9 -0
  133. data/spec/integration/associations/has_and_belongs_to_many_spec.rb +21 -0
  134. data/spec/integration/associations/has_one_spec.rb +97 -1
  135. data/spec/integration/associations/scope_option_spec.rb +1 -1
  136. data/spec/integration/callbacks_models.rb +95 -1
  137. data/spec/integration/callbacks_spec.rb +226 -4
  138. data/spec/integration/criteria/range_spec.rb +95 -1
  139. data/spec/integration/discriminator_key_spec.rb +115 -76
  140. data/spec/integration/dots_and_dollars_spec.rb +277 -0
  141. data/spec/integration/i18n_fallbacks_spec.rb +1 -15
  142. data/spec/integration/matcher_examples_spec.rb +20 -13
  143. data/spec/integration/matcher_operator_data/type_decimal.yml +3 -2
  144. data/spec/integration/matcher_operator_spec.rb +3 -5
  145. data/spec/integration/persistence/range_field_spec.rb +350 -0
  146. data/spec/mongoid/association/counter_cache_spec.rb +1 -1
  147. data/spec/mongoid/association/depending_spec.rb +9 -9
  148. data/spec/mongoid/association/eager_spec.rb +2 -1
  149. data/spec/mongoid/association/embedded/embedded_in/binding_spec.rb +2 -1
  150. data/spec/mongoid/association/embedded/embedded_in/buildable_spec.rb +54 -0
  151. data/spec/mongoid/association/embedded/embedded_in/proxy_spec.rb +69 -9
  152. data/spec/mongoid/association/embedded/embeds_many/buildable_spec.rb +112 -0
  153. data/spec/mongoid/association/embedded/embeds_many/proxy_spec.rb +198 -8
  154. data/spec/mongoid/association/embedded/embeds_many_models.rb +36 -0
  155. data/spec/mongoid/association/embedded/embeds_many_query_spec.rb +12 -0
  156. data/spec/mongoid/association/embedded/embeds_many_spec.rb +68 -0
  157. data/spec/mongoid/association/embedded/embeds_one/buildable_spec.rb +25 -0
  158. data/spec/mongoid/association/embedded/embeds_one_models.rb +19 -0
  159. data/spec/mongoid/association/embedded/embeds_one_spec.rb +28 -0
  160. data/spec/mongoid/association/referenced/belongs_to/binding_spec.rb +2 -1
  161. data/spec/mongoid/association/referenced/belongs_to/buildable_spec.rb +54 -0
  162. data/spec/mongoid/association/referenced/belongs_to/proxy_spec.rb +15 -0
  163. data/spec/mongoid/association/referenced/belongs_to_models.rb +11 -0
  164. data/spec/mongoid/association/referenced/belongs_to_spec.rb +2 -2
  165. data/spec/mongoid/association/referenced/has_and_belongs_to_many/proxy_spec.rb +38 -5
  166. data/spec/mongoid/association/referenced/has_and_belongs_to_many_models.rb +25 -0
  167. data/spec/mongoid/association/referenced/has_and_belongs_to_many_spec.rb +35 -2
  168. data/spec/mongoid/association/referenced/has_many/buildable_spec.rb +109 -0
  169. data/spec/mongoid/association/referenced/has_many/enumerable_spec.rb +2 -56
  170. data/spec/mongoid/association/referenced/has_many/proxy_spec.rb +62 -13
  171. data/spec/mongoid/association/referenced/has_many_models.rb +3 -1
  172. data/spec/mongoid/association/referenced/has_many_spec.rb +25 -0
  173. data/spec/mongoid/association/referenced/has_one/buildable_spec.rb +2 -2
  174. data/spec/mongoid/association/referenced/has_one/proxy_spec.rb +107 -1
  175. data/spec/mongoid/association/referenced/has_one_models.rb +16 -0
  176. data/spec/mongoid/association/syncable_spec.rb +14 -0
  177. data/spec/mongoid/atomic/paths_spec.rb +0 -14
  178. data/spec/mongoid/attributes/nested_spec.rb +80 -11
  179. data/spec/mongoid/attributes/nested_spec_models.rb +48 -0
  180. data/spec/mongoid/attributes/projector_spec.rb +1 -5
  181. data/spec/mongoid/attributes_spec.rb +480 -27
  182. data/spec/mongoid/cacheable_spec.rb +3 -3
  183. data/spec/mongoid/changeable_spec.rb +130 -13
  184. data/spec/mongoid/clients/factory_spec.rb +23 -30
  185. data/spec/mongoid/clients/sessions_spec.rb +0 -38
  186. data/spec/mongoid/clients_spec.rb +2 -2
  187. data/spec/mongoid/config_spec.rb +52 -14
  188. data/spec/mongoid/contextual/aggregable/memory_spec.rb +396 -158
  189. data/spec/mongoid/contextual/aggregable/memory_table.yml +88 -0
  190. data/spec/mongoid/contextual/aggregable/memory_table_spec.rb +62 -0
  191. data/spec/mongoid/contextual/map_reduce_spec.rb +2 -16
  192. data/spec/mongoid/contextual/memory_spec.rb +521 -14
  193. data/spec/mongoid/contextual/mongo_spec.rb +566 -416
  194. data/spec/mongoid/contextual/none_spec.rb +11 -19
  195. data/spec/mongoid/copyable_spec.rb +451 -1
  196. data/spec/mongoid/criteria/findable_spec.rb +86 -210
  197. data/spec/mongoid/criteria/includable_spec.rb +1492 -0
  198. data/spec/mongoid/criteria/includable_spec_models.rb +54 -0
  199. data/spec/mongoid/criteria/marshalable_spec.rb +18 -1
  200. data/spec/mongoid/criteria/queryable/extensions/array_spec.rb +7 -19
  201. data/spec/mongoid/criteria/queryable/extensions/big_decimal_spec.rb +134 -26
  202. data/spec/mongoid/criteria/queryable/extensions/date_spec.rb +11 -0
  203. data/spec/mongoid/criteria/queryable/extensions/date_time_spec.rb +11 -0
  204. data/spec/mongoid/criteria/queryable/extensions/hash_spec.rb +0 -15
  205. data/spec/mongoid/criteria/queryable/extensions/numeric_spec.rb +73 -7
  206. data/spec/mongoid/criteria/queryable/extensions/time_spec.rb +11 -0
  207. data/spec/mongoid/criteria/queryable/extensions/time_with_zone_spec.rb +11 -0
  208. data/spec/mongoid/criteria/queryable/optional_spec.rb +0 -484
  209. data/spec/mongoid/criteria/queryable/selectable_logical_spec.rb +50 -0
  210. data/spec/mongoid/criteria/queryable/selectable_spec.rb +77 -85
  211. data/spec/mongoid/criteria/queryable/selector_spec.rb +16 -77
  212. data/spec/mongoid/criteria/queryable/storable_spec.rb +0 -72
  213. data/spec/mongoid/criteria_spec.rb +469 -1201
  214. data/spec/mongoid/document_fields_spec.rb +173 -24
  215. data/spec/mongoid/document_spec.rb +32 -41
  216. data/spec/mongoid/equality_spec.rb +12 -12
  217. data/spec/mongoid/errors/document_not_found_spec.rb +29 -2
  218. data/spec/mongoid/errors/invalid_field_spec.rb +1 -1
  219. data/spec/mongoid/errors/invalid_field_type_spec.rb +55 -0
  220. data/spec/mongoid/errors/mongoid_error_spec.rb +3 -1
  221. data/spec/mongoid/errors/no_environment_spec.rb +3 -3
  222. data/spec/mongoid/errors/too_many_nested_attribute_records_spec.rb +1 -1
  223. data/spec/mongoid/extensions/array_spec.rb +16 -2
  224. data/spec/mongoid/extensions/big_decimal_spec.rb +697 -212
  225. data/spec/mongoid/extensions/binary_spec.rb +44 -9
  226. data/spec/mongoid/extensions/boolean_spec.rb +68 -82
  227. data/spec/mongoid/extensions/date_class_mongoize_spec.rb +7 -3
  228. data/spec/mongoid/extensions/date_spec.rb +71 -1
  229. data/spec/mongoid/extensions/date_time_spec.rb +15 -9
  230. data/spec/mongoid/extensions/float_spec.rb +48 -76
  231. data/spec/mongoid/extensions/hash_spec.rb +30 -0
  232. data/spec/mongoid/extensions/integer_spec.rb +45 -66
  233. data/spec/mongoid/extensions/range_spec.rb +255 -54
  234. data/spec/mongoid/extensions/regexp_spec.rb +58 -33
  235. data/spec/mongoid/extensions/set_spec.rb +106 -0
  236. data/spec/mongoid/extensions/string_spec.rb +53 -25
  237. data/spec/mongoid/extensions/symbol_spec.rb +18 -25
  238. data/spec/mongoid/extensions/time_spec.rb +634 -66
  239. data/spec/mongoid/extensions/time_with_zone_spec.rb +17 -31
  240. data/spec/mongoid/factory_spec.rb +61 -1
  241. data/spec/mongoid/fields_spec.rb +321 -50
  242. data/spec/mongoid/findable_spec.rb +64 -29
  243. data/spec/mongoid/indexable/specification_spec.rb +2 -2
  244. data/spec/mongoid/indexable_spec.rb +16 -19
  245. data/spec/mongoid/interceptable_spec.rb +584 -5
  246. data/spec/mongoid/interceptable_spec_models.rb +235 -4
  247. data/spec/mongoid/matcher/extract_attribute_spec.rb +1 -5
  248. data/spec/mongoid/mongoizable_spec.rb +285 -0
  249. data/spec/mongoid/persistable/creatable_spec.rb +2 -2
  250. data/spec/mongoid/persistable/deletable_spec.rb +2 -2
  251. data/spec/mongoid/persistable/destroyable_spec.rb +2 -2
  252. data/spec/mongoid/persistable/upsertable_spec.rb +14 -0
  253. data/spec/mongoid/persistence_context_spec.rb +24 -0
  254. data/spec/mongoid/query_cache_middleware_spec.rb +0 -18
  255. data/spec/mongoid/query_cache_spec.rb +0 -154
  256. data/spec/mongoid/reloadable_spec.rb +35 -2
  257. data/spec/mongoid/scopable_spec.rb +36 -34
  258. data/spec/mongoid/shardable_models.rb +0 -14
  259. data/spec/mongoid/shardable_spec.rb +61 -153
  260. data/spec/mongoid/stateful_spec.rb +28 -0
  261. data/spec/mongoid/timestamps_spec.rb +390 -0
  262. data/spec/mongoid/timestamps_spec_models.rb +67 -0
  263. data/spec/mongoid/touchable_spec.rb +116 -0
  264. data/spec/mongoid/touchable_spec_models.rb +12 -8
  265. data/spec/mongoid/traversable_spec.rb +4 -11
  266. data/spec/mongoid/validatable/presence_spec.rb +1 -1
  267. data/spec/mongoid/validatable/uniqueness_spec.rb +60 -31
  268. data/spec/mongoid/warnings_spec.rb +35 -0
  269. data/spec/mongoid_spec.rb +1 -7
  270. data/spec/rails/controller_extension/controller_runtime_spec.rb +2 -2
  271. data/spec/rails/mongoid_spec.rb +4 -16
  272. data/spec/shared/lib/mrss/event_subscriber.rb +5 -15
  273. data/spec/shared/lib/mrss/lite_constraints.rb +0 -8
  274. data/spec/shared/shlib/server.sh +5 -5
  275. data/spec/support/constraints.rb +24 -0
  276. data/spec/support/macros.rb +30 -0
  277. data/spec/support/models/augmentation.rb +12 -0
  278. data/spec/support/models/band.rb +3 -0
  279. data/spec/support/models/catalog.rb +24 -0
  280. data/spec/support/models/circus.rb +3 -0
  281. data/spec/support/models/fanatic.rb +8 -0
  282. data/spec/support/models/implant.rb +9 -0
  283. data/spec/support/models/label.rb +2 -0
  284. data/spec/support/models/passport.rb +9 -0
  285. data/spec/support/models/person.rb +1 -0
  286. data/spec/support/models/player.rb +2 -0
  287. data/spec/support/models/powerup.rb +12 -0
  288. data/spec/support/models/registry.rb +1 -0
  289. data/spec/support/models/school.rb +14 -0
  290. data/spec/support/models/shield.rb +18 -0
  291. data/spec/support/models/student.rb +14 -0
  292. data/spec/support/models/weapon.rb +12 -0
  293. data.tar.gz.sig +0 -0
  294. metadata +689 -657
  295. metadata.gz.sig +0 -0
  296. data/lib/mongoid/errors/eager_load.rb +0 -23
  297. data/lib/mongoid/errors/invalid_value.rb +0 -17
  298. data/spec/mongoid/errors/eager_load_spec.rb +0 -31
@@ -44,39 +44,6 @@ describe Mongoid::Contextual::Mongo do
44
44
  end
45
45
  end
46
46
 
47
- describe "#cached?" do
48
-
49
- context "when the criteria is cached" do
50
-
51
- let(:criteria) do
52
- Band.all.cache
53
- end
54
-
55
- let(:context) do
56
- described_class.new(criteria)
57
- end
58
-
59
- it "returns true" do
60
- expect(context).to be_cached
61
- end
62
- end
63
-
64
- context "when the criteria is not cached" do
65
-
66
- let(:criteria) do
67
- Band.all
68
- end
69
-
70
- let(:context) do
71
- described_class.new(criteria)
72
- end
73
-
74
- it "returns false" do
75
- expect(context).to_not be_cached
76
- end
77
- end
78
- end
79
-
80
47
  describe "#count" do
81
48
 
82
49
  let!(:depeche) do
@@ -102,15 +69,17 @@ describe Mongoid::Contextual::Mongo do
102
69
  end
103
70
  end
104
71
 
105
- context "when context is cached" do
72
+ context "when the query cache is enabled" do
73
+ query_cache_enabled
106
74
 
107
75
  let(:context) do
108
- described_class.new(criteria.cache)
76
+ described_class.new(criteria)
109
77
  end
110
78
 
111
- it "returns the count cached value after first call" do
112
- expect(context.view).to receive(:count_documents).once.and_return(1)
113
- 2.times { expect(context.count).to eq(1) }
79
+ it "only executes the count query once" do
80
+ expect_query(1) do
81
+ 2.times { expect(context.count).to eq(1) }
82
+ end
114
83
  end
115
84
  end
116
85
 
@@ -217,16 +186,18 @@ describe Mongoid::Contextual::Mongo do
217
186
  end
218
187
  end
219
188
 
220
- context "when context is cached" do
189
+ context "when the query cache is enabled" do
190
+ query_cache_enabled
221
191
 
222
192
  let(:context) do
223
- described_class.new(criteria.cache)
193
+ described_class.new(criteria)
224
194
  end
225
195
 
226
- it "returns the count cached value after first call" do
227
- expect(context.view).to receive(:estimated_document_count).once.and_return(1)
228
- 2.times do
229
- context.estimated_count
196
+ it "the results are not cached" do
197
+ expect_query(2) do
198
+ 2.times do
199
+ context.estimated_count
200
+ end
230
201
  end
231
202
  end
232
203
  end
@@ -561,8 +532,22 @@ describe Mongoid::Contextual::Mongo do
561
532
  context "when legacy_pluck_distinct is set" do
562
533
  config_override :legacy_pluck_distinct, true
563
534
 
564
- it "returns the non-demongoized distinct field values" do
565
- expect(context.distinct(:sales).sort).to eq([ "1E2", "2E3" ])
535
+ context 'when storing BigDecimal as string' do
536
+ config_override :map_big_decimal_to_decimal128, false
537
+
538
+ it "returns the non-demongoized distinct field values" do
539
+ expect(context.distinct(:sales).sort).to eq([ "1E2", "2E3" ])
540
+ end
541
+ end
542
+
543
+ context 'when storing BigDecimal as decimal128' do
544
+ config_override :map_big_decimal_to_decimal128, true
545
+ min_bson_version '4.15.0'
546
+ max_bson_version '4.99.99'
547
+
548
+ it "returns the non-demongoized distinct field values" do
549
+ expect(context.distinct(:sales).sort).to eq([ BSON::Decimal128.new("1E2"), BSON::Decimal128.new("2E3") ])
550
+ end
566
551
  end
567
552
  end
568
553
 
@@ -584,10 +569,6 @@ describe Mongoid::Contextual::Mongo do
584
569
  d.save!
585
570
  end
586
571
 
587
- after do
588
- I18n.locale = :en
589
- end
590
-
591
572
  let(:criteria) do
592
573
  Dictionary.criteria
593
574
  end
@@ -688,10 +669,6 @@ describe Mongoid::Contextual::Mongo do
688
669
  I18n.fallbacks = prev_fallbacks
689
670
  end
690
671
 
691
- after do
692
- I18n.locale = :en
693
- end
694
-
695
672
  let(:distinct) do
696
673
  context.distinct(:description).first
697
674
  end
@@ -727,10 +704,6 @@ describe Mongoid::Contextual::Mongo do
727
704
  Person.create!(passport: p, employer_id: 12345)
728
705
  end
729
706
 
730
- after do
731
- I18n.locale = :en
732
- end
733
-
734
707
  let(:criteria) do
735
708
  Person.where(employer_id: 12345)
736
709
  end
@@ -794,9 +767,11 @@ describe Mongoid::Contextual::Mongo do
794
767
 
795
768
  context "when legacy_pluck_distinct is set" do
796
769
  config_override :legacy_pluck_distinct, true
770
+ config_override :map_big_decimal_to_decimal128, true
771
+ max_bson_version '4.99.99'
797
772
 
798
773
  it "returns the distinct matching fields" do
799
- expect(context.distinct("label.sales")).to eq([ "1E2" ])
774
+ expect(context.distinct("label.sales")).to eq([ BSON::Decimal128.new('1E+2') ])
800
775
  end
801
776
  end
802
777
 
@@ -809,6 +784,435 @@ describe Mongoid::Contextual::Mongo do
809
784
  end
810
785
  end
811
786
 
787
+ describe "#tally" do
788
+ let(:fans1) { [ Fanatic.new(age:1), Fanatic.new(age:2) ] }
789
+ let(:fans2) { [ Fanatic.new(age:1), Fanatic.new(age:2) ] }
790
+ let(:fans3) { [ Fanatic.new(age:1), Fanatic.new(age:3) ] }
791
+
792
+ let(:genres1) { [ { x: 1, y: { z: 1 } }, { x: 2, y: { z: 2 } }, { y: 3 } ]}
793
+ let(:genres2) { [ { x: 1, y: { z: 1 } }, { x: 2, y: { z: 2 } }, { y: 4 } ]}
794
+ let(:genres3) { [ { x: 1, y: { z: 1 } }, { x: 3, y: { z: 3 } }, { y: 5 } ]}
795
+
796
+ let(:label1) { Label.new(name: "Atlantic") }
797
+ let(:label2) { Label.new(name: "Atlantic") }
798
+ let(:label3) { Label.new(name: "Columbia") }
799
+
800
+ before do
801
+ Band.create!(origin: "tally", name: "Depeche Mode", years: 30, sales: "1E2", label: label1, genres: genres1)
802
+ Band.create!(origin: "tally", name: "New Order", years: 30, sales: "2E3", label: label2, genres: genres2)
803
+ Band.create!(origin: "tally", name: "10,000 Maniacs", years: 30, sales: "1E2", label: label3, genres: genres3)
804
+ Band.create!(origin: "tally2", fanatics: fans1, genres: [1, 2])
805
+ Band.create!(origin: "tally2", fanatics: fans2, genres: [1, 2])
806
+ Band.create!(origin: "tally2", fanatics: fans3, genres: [1, 3])
807
+ end
808
+
809
+ let(:criteria) { Band.where(origin: "tally") }
810
+
811
+ context "when tallying a string" do
812
+ let(:tally) do
813
+ criteria.tally(:name)
814
+ end
815
+
816
+ it "returns the correct hash" do
817
+ expect(tally).to eq("Depeche Mode" => 1, "New Order" => 1, "10,000 Maniacs" => 1)
818
+ end
819
+ end
820
+
821
+ context "using an aliased field" do
822
+ let(:tally) do
823
+ criteria.tally(:years)
824
+ end
825
+
826
+ it "returns the correct hash" do
827
+ expect(tally).to eq(30 => 3)
828
+ end
829
+ end
830
+
831
+ context "when tallying a demongoizable field" do
832
+ let(:tally) do
833
+ criteria.tally(:sales)
834
+ end
835
+
836
+ it "returns the correct hash" do
837
+ expect(tally).to eq(BigDecimal("1E2") => 2, BigDecimal("2E3") => 1)
838
+ end
839
+ end
840
+
841
+ context "when tallying a localized field" do
842
+ before do
843
+ I18n.locale = :en
844
+ d1 = Dictionary.create!(description: 'en1')
845
+ d2 = Dictionary.create!(description: 'en1')
846
+ d3 = Dictionary.create!(description: 'en1')
847
+ d4 = Dictionary.create!(description: 'en2')
848
+ I18n.locale = :de
849
+ d1.description = 'de1'
850
+ d2.description = 'de1'
851
+ d3.description = 'de2'
852
+ d4.description = 'de3'
853
+ d1.save!
854
+ d2.save!
855
+ d3.save!
856
+ d4.save!
857
+
858
+ I18n.locale = :en
859
+ end
860
+
861
+ context "when getting the demongoized field" do
862
+ let(:tallied) do
863
+ Dictionary.tally(:description)
864
+ end
865
+
866
+ it "returns the translation for the current locale" do
867
+ expect(tallied).to eq("en1" => 3, "en2" => 1)
868
+ end
869
+ end
870
+
871
+ context "when getting a specific locale" do
872
+ let(:tallied) do
873
+ Dictionary.tally("description.de")
874
+ end
875
+
876
+ it "returns the translation for the the specific locale" do
877
+ expect(tallied).to eq("de1" => 2, "de2" => 1, "de3" => 1)
878
+ end
879
+ end
880
+
881
+ context "when getting the full hash" do
882
+ let(:tallied) do
883
+ Dictionary.tally("description_translations")
884
+ end
885
+
886
+ it "returns the correct hash" do
887
+ expect(tallied).to eq(
888
+ {"de" => "de1", "en" => "en1" } => 2,
889
+ {"de" => "de2", "en" => "en1" } => 1,
890
+ {"de" => "de3", "en" => "en2" } => 1
891
+ )
892
+ end
893
+ end
894
+ end
895
+
896
+ context "when tallying an embedded localized field" do
897
+
898
+ before do
899
+ I18n.locale = :en
900
+ address1a = Address.new(name: "en1")
901
+ address1b = Address.new(name: "en2")
902
+ address2a = Address.new(name: "en1")
903
+ address2b = Address.new(name: "en3")
904
+ I18n.locale = :de
905
+ address1a.name = "de1"
906
+ address1b.name = "de2"
907
+ address2a.name = "de1"
908
+ address2b.name = "de3"
909
+ Person.create!(addresses: [ address1a, address1b ])
910
+ Person.create!(addresses: [ address2a, address2b ])
911
+
912
+ I18n.locale = :en
913
+ end
914
+
915
+ context "when getting the demongoized field" do
916
+ let(:tallied) do
917
+ Person.tally("addresses.name")
918
+ end
919
+
920
+ it "returns the translation for the current locale" do
921
+ expect(tallied).to eq(
922
+ [ "en1", "en2" ] => 1,
923
+ [ "en1", "en3" ] => 1,
924
+ )
925
+ end
926
+ end
927
+
928
+ context "when getting a specific locale" do
929
+ let(:tallied) do
930
+ Person.tally("addresses.name.de")
931
+ end
932
+
933
+ it "returns the translation for the the specific locale" do
934
+ expect(tallied).to eq(
935
+ [ "de1", "de2" ] => 1,
936
+ [ "de1", "de3" ] => 1,
937
+ )
938
+ end
939
+ end
940
+
941
+ context "when getting the full hash" do
942
+ let(:tallied) do
943
+ Person.tally("addresses.name_translations")
944
+ end
945
+
946
+ it "returns the correct hash" do
947
+ expect(tallied).to eq(
948
+ [{ "de" => "de1", "en" => "en1" }, { "de" => "de2", "en" => "en2" }] => 1,
949
+ [{ "de" => "de1", "en" => "en1" }, { "de" => "de3", "en" => "en3" }] => 1,
950
+ )
951
+ end
952
+ end
953
+
954
+ end
955
+
956
+ context "when tallying an embedded field" do
957
+ let(:tally) do
958
+ criteria.tally("label.name")
959
+ end
960
+
961
+ it "returns the correct hash" do
962
+ expect(tally).to eq("Atlantic" => 2, "Columbia" => 1)
963
+ end
964
+ end
965
+
966
+ context "when tallying an element in an embeds_many field" do
967
+ let(:criteria) { Band.where(origin: "tally2") }
968
+
969
+ let(:tally) do
970
+ criteria.tally("fanatics.age")
971
+ end
972
+
973
+ it "returns the correct hash" do
974
+ expect(tally).to eq(
975
+ [1, 2] => 2,
976
+ [1, 3] => 1
977
+ )
978
+ end
979
+ end
980
+
981
+ context "when tallying an embeds_many field" do
982
+ let(:criteria) { Band.where(origin: "tally2") }
983
+
984
+ let(:tally) do
985
+ criteria.tally("fanatics")
986
+ end
987
+
988
+ it "returns the correct hash" do
989
+ expect(tally).to eq(
990
+ fans1.map(&:attributes) => 1,
991
+ fans2.map(&:attributes) => 1,
992
+ fans3.map(&:attributes) => 1,
993
+ )
994
+ end
995
+ end
996
+
997
+ context "when tallying a field of type array" do
998
+ let(:criteria) { Band.where(origin: "tally2") }
999
+
1000
+ let(:tally) do
1001
+ criteria.tally("genres")
1002
+ end
1003
+
1004
+ it "returns the correct hash" do
1005
+ expect(tally).to eq(
1006
+ [1, 2] => 2,
1007
+ [1, 3] => 1
1008
+ )
1009
+ end
1010
+ end
1011
+
1012
+ context "when tallying an element from an array of hashes" do
1013
+ let(:criteria) { Band.where(origin: "tally") }
1014
+
1015
+ let(:tally) do
1016
+ criteria.tally("genres.x")
1017
+ end
1018
+
1019
+ it "returns the correct hash without the nil keys" do
1020
+ expect(tally).to eq(
1021
+ [1, 2] => 2,
1022
+ [1, 3] => 1
1023
+ )
1024
+ end
1025
+ end
1026
+
1027
+ context "when tallying an element from an array of hashes; with duplicate" do
1028
+
1029
+ before do
1030
+ Band.create!(origin: "tally", genres: [ { x: 1 }, {x: 1} ] )
1031
+ end
1032
+
1033
+ let(:criteria) { Band.where(origin: "tally") }
1034
+
1035
+ let(:tally) do
1036
+ criteria.tally("genres.x")
1037
+ end
1038
+
1039
+ it "returns the correct hash without the nil keys" do
1040
+ expect(tally).to eq(
1041
+ [1, 2] => 2,
1042
+ [1, 3] => 1,
1043
+ [1, 1] => 1,
1044
+ )
1045
+ end
1046
+ end
1047
+
1048
+ context "when tallying an aliased field of type array" do
1049
+
1050
+ before do
1051
+ Person.create!(array: [ 1, 2 ])
1052
+ Person.create!(array: [ 1, 3 ])
1053
+ end
1054
+
1055
+ let(:tally) do
1056
+ Person.tally("array")
1057
+ end
1058
+
1059
+ it "returns the correct hash" do
1060
+ expect(tally).to eq(
1061
+ [1, 2] => 1,
1062
+ [1, 3] => 1
1063
+ )
1064
+ end
1065
+ end
1066
+
1067
+ context "when going multiple levels deep in arrays" do
1068
+ let(:criteria) { Band.where(origin: "tally") }
1069
+
1070
+ let(:tally) do
1071
+ criteria.tally("genres.y.z")
1072
+ end
1073
+
1074
+ it "returns the correct hash" do
1075
+ expect(tally).to eq(
1076
+ [1, 2] => 2,
1077
+ [1, 3] => 1
1078
+ )
1079
+ end
1080
+ end
1081
+
1082
+ context "when going multiple levels deep in an array" do
1083
+ let(:criteria) { Band.where(origin: "tally") }
1084
+
1085
+ let(:tally) do
1086
+ criteria.tally("genres.y.z")
1087
+ end
1088
+
1089
+ it "returns the correct hash" do
1090
+ expect(tally).to eq(
1091
+ [1, 2] => 2,
1092
+ [1, 3] => 1
1093
+ )
1094
+ end
1095
+ end
1096
+
1097
+ context "when tallying deeply nested arrays/embedded associations" do
1098
+
1099
+ before do
1100
+ Person.create!(addresses: [ Address.new(code: Code.new(deepest: Deepest.new(array: [ { y: { z: 1 } }, { y: { z: 2 } } ]))) ])
1101
+ Person.create!(addresses: [ Address.new(code: Code.new(deepest: Deepest.new(array: [ { y: { z: 1 } }, { y: { z: 2 } } ]))) ])
1102
+ Person.create!(addresses: [ Address.new(code: Code.new(deepest: Deepest.new(array: [ { y: { z: 1 } }, { y: { z: 3 } } ]))) ])
1103
+ end
1104
+
1105
+ let(:tally) do
1106
+ Person.tally("addresses.code.deepest.array.y.z")
1107
+ end
1108
+
1109
+ it "returns the correct hash" do
1110
+ expect(tally).to eq(
1111
+ [ [ 1, 2 ] ] => 2,
1112
+ [ [ 1, 3 ] ] => 1
1113
+ )
1114
+ end
1115
+ end
1116
+
1117
+ context "when tallying deeply nested arrays/embedded associations" do
1118
+
1119
+ before do
1120
+ Person.create!(addresses: [ Address.new(code: Code.new(deepest: Deepest.new(array: [ { y: { z: 1 } }, { y: { z: 2 } } ]))),
1121
+ Address.new(code: Code.new(deepest: Deepest.new(array: [ { y: { z: 1 } }, { y: { z: 2 } } ]))) ])
1122
+ Person.create!(addresses: [ Address.new(code: Code.new(deepest: Deepest.new(array: [ { y: { z: 1 } }, { y: { z: 2 } } ]))),
1123
+ Address.new(code: Code.new(deepest: Deepest.new(array: [ { y: { z: 1 } }, { y: { z: 2 } } ]))) ])
1124
+ Person.create!(addresses: [ Address.new(code: Code.new(deepest: Deepest.new(array: [ { y: { z: 1 } }, { y: { z: 3 } } ]))),
1125
+ Address.new(code: Code.new(deepest: Deepest.new(array: [ { y: { z: 1 } }, { y: { z: 3 } } ]))) ])
1126
+ end
1127
+
1128
+ let(:tally) do
1129
+ Person.tally("addresses.code.deepest.array.y.z")
1130
+ end
1131
+
1132
+ it "returns the correct hash" do
1133
+ expect(tally).to eq(
1134
+ [ [ 1, 2 ], [ 1, 2 ] ] => 2,
1135
+ [ [ 1, 3 ], [ 1, 3 ] ] => 1
1136
+ )
1137
+ end
1138
+ end
1139
+
1140
+ context "when some keys are missing" do
1141
+ before do
1142
+ 3.times { Band.create!(origin: "tally") }
1143
+ end
1144
+
1145
+ let(:tally) do
1146
+ criteria.tally(:name)
1147
+ end
1148
+
1149
+ it "returns the correct hash" do
1150
+ expect(tally).to eq(
1151
+ "Depeche Mode" => 1,
1152
+ "New Order" => 1,
1153
+ "10,000 Maniacs" => 1,
1154
+ nil => 3
1155
+ )
1156
+ end
1157
+ end
1158
+
1159
+ context "when the first element is an embeds_one" do
1160
+ before do
1161
+ Person.create!(name: Name.new(translations: [ Translation.new(language: 1), Translation.new(language: 2) ]))
1162
+ Person.create!(name: Name.new(translations: [ Translation.new(language: 1), Translation.new(language: 2) ]))
1163
+ Person.create!(name: Name.new(translations: [ Translation.new(language: 1), Translation.new(language: 3) ]))
1164
+ end
1165
+
1166
+ let(:tally) do
1167
+ Person.tally("name.translations.language")
1168
+ end
1169
+
1170
+ it "returns the correct hash" do
1171
+ expect(tally).to eq(
1172
+ [1, 2] => 2,
1173
+ [1, 3] => 1
1174
+ )
1175
+ end
1176
+ end
1177
+
1178
+ context "when tallying demongoizable values from typeless fields" do
1179
+
1180
+ let!(:person1) { Person.create!(ssn: /hello/) }
1181
+ let!(:person2) { Person.create!(ssn: BSON::Decimal128.new("1")) }
1182
+ let(:tally) { Person.tally("ssn") }
1183
+
1184
+ context "< BSON 5" do
1185
+ max_bson_version '4.99.99'
1186
+
1187
+ it "stores the correct types in the database" do
1188
+ Person.find(person1.id).attributes["ssn"].should be_a BSON::Regexp::Raw
1189
+ Person.find(person2.id).attributes["ssn"].should be_a BSON::Decimal128
1190
+ end
1191
+
1192
+ it "tallies the correct type" do
1193
+ tally.keys.map(&:class).sort do |a,b|
1194
+ a.to_s <=> b.to_s
1195
+ end.should == [BSON::Decimal128, BSON::Regexp::Raw]
1196
+ end
1197
+ end
1198
+
1199
+ context ">= BSON 5" do
1200
+ min_bson_version "5.0"
1201
+
1202
+ it "stores the correct types in the database" do
1203
+ Person.find(person1.id).ssn.should be_a BSON::Regexp::Raw
1204
+ Person.find(person2.id).ssn.should be_a BigDeimal
1205
+ end
1206
+
1207
+ it "tallies the correct type" do
1208
+ tally.keys.map(&:class).sort do |a,b|
1209
+ a.to_s <=> b.to_s
1210
+ end.should == [BigDecimal, BSON::Regexp::Raw]
1211
+ end
1212
+ end
1213
+ end
1214
+ end
1215
+
812
1216
  describe "#each" do
813
1217
 
814
1218
  before do
@@ -1017,51 +1421,15 @@ describe Mongoid::Contextual::Mongo do
1017
1421
  described_class.new(criteria)
1018
1422
  end
1019
1423
 
1020
- context "when exists? already called" do
1424
+ context "when exists? already called and query cache is enabled" do
1425
+ query_cache_enabled
1021
1426
 
1022
1427
  before do
1023
1428
  context.exists?
1024
1429
  end
1025
1430
 
1026
- it "hits the database again" do
1027
- expect(context).to receive(:view).once.and_call_original
1028
- expect(context).to be_exists
1029
- end
1030
- end
1031
- end
1032
-
1033
- context "when caching is enabled" do
1034
-
1035
- let(:criteria) do
1036
- Band.where(name: "Depeche Mode").cache
1037
- end
1038
-
1039
- let(:context) do
1040
- described_class.new(criteria)
1041
- end
1042
-
1043
- context "when the cache is loaded" do
1044
-
1045
- before do
1046
- context.to_a
1047
- end
1048
-
1049
- it "does not hit the database" do
1050
- expect(context).to receive(:view).never
1051
- expect(context).to be_exists
1052
- end
1053
- end
1054
-
1055
- context "when the cache is not loaded" do
1056
-
1057
- context "when a count has been executed" do
1058
-
1059
- before do
1060
- context.count
1061
- end
1062
-
1063
- it "does not hit the database" do
1064
- expect(context).to receive(:view).never
1431
+ it "does not hit the database again" do
1432
+ expect_no_queries do
1065
1433
  expect(context).to be_exists
1066
1434
  end
1067
1435
  end
@@ -1420,7 +1788,7 @@ describe Mongoid::Contextual::Mongo do
1420
1788
  it "deletes the document from the database" do
1421
1789
  expect {
1422
1790
  depeche.reload
1423
- }.to raise_error(Mongoid::Errors::DocumentNotFound)
1791
+ }.to raise_error(Mongoid::Errors::DocumentNotFound, /Document\(s\) not found for class Band with id\(s\)/)
1424
1792
  end
1425
1793
 
1426
1794
  context 'when a collation is specified on the criteria' do
@@ -1445,7 +1813,7 @@ describe Mongoid::Contextual::Mongo do
1445
1813
  it "deletes the document from the database" do
1446
1814
  expect {
1447
1815
  depeche.reload
1448
- }.to raise_error(Mongoid::Errors::DocumentNotFound)
1816
+ }.to raise_error(Mongoid::Errors::DocumentNotFound, /Document\(s\) not found for class Band with id\(s\)/)
1449
1817
  end
1450
1818
  end
1451
1819
  end
@@ -1554,31 +1922,13 @@ describe Mongoid::Contextual::Mongo do
1554
1922
  expect(context.send(method)).to eq(depeche_mode)
1555
1923
  end
1556
1924
 
1557
- context "when calling ##{method}" do
1925
+ context 'when calling #last' do
1558
1926
 
1559
- it 'returns the requested document, sorted by _id' do
1927
+ it 'returns the last document, sorted by _id' do
1560
1928
  expect(context.send(method)).to eq(depeche_mode)
1561
1929
  expect(context.last).to eq(rolling_stones)
1562
1930
  end
1563
1931
  end
1564
-
1565
- context 'with option { id_sort: :none }' do
1566
- let(:opts) do
1567
- { id_sort: :none }
1568
- end
1569
-
1570
- it 'applies the sort on _id' do
1571
- expect(context.send(method, opts)).to eq(depeche_mode)
1572
- end
1573
-
1574
- context "when calling ##{method}" do
1575
-
1576
- it 'doesn\'t apply a sort on _id' do
1577
- expect(context.send(method, opts)).to eq(depeche_mode)
1578
- expect(context.last(opts)).to eq(depeche_mode)
1579
- end
1580
- end
1581
- end
1582
1932
  end
1583
1933
 
1584
1934
  context 'when the criteria has a sort' do
@@ -1602,25 +1952,6 @@ describe Mongoid::Contextual::Mongo do
1602
1952
  expect(context.last).to eq(depeche_mode)
1603
1953
  end
1604
1954
  end
1605
-
1606
- context 'with option { id_sort: :none }' do
1607
-
1608
- let(:opts) do
1609
- { id_sort: :none }
1610
- end
1611
-
1612
- it 'uses the preexisting sort' do
1613
- expect(context.send(method, opts)).to eq(rolling_stones)
1614
- end
1615
-
1616
- context 'when calling #last' do
1617
-
1618
- it 'uses the preexisting sort' do
1619
- expect(context.send(method, opts)).to eq(rolling_stones)
1620
- expect(context.last(opts)).to eq(depeche_mode)
1621
- end
1622
- end
1623
- end
1624
1955
  end
1625
1956
 
1626
1957
  context "when using .sort" do
@@ -1649,28 +1980,17 @@ describe Mongoid::Contextual::Mongo do
1649
1980
  end
1650
1981
  end
1651
1982
 
1652
- context "when the context is cached" do
1983
+ context "when the query cache is enabled" do
1984
+ query_cache_enabled
1653
1985
 
1654
1986
  let(:criteria) do
1655
- Band.where(name: "Depeche Mode").cache
1987
+ Band.where(name: "Depeche Mode")
1656
1988
  end
1657
1989
 
1658
1990
  let(:context) do
1659
1991
  described_class.new(criteria)
1660
1992
  end
1661
1993
 
1662
- context "when the cache is loaded" do
1663
-
1664
- before do
1665
- context.to_a
1666
- end
1667
-
1668
- it "returns the first document without touching the database" do
1669
- expect(context).to receive(:view).never
1670
- expect(context.send(method)).to eq(depeche_mode)
1671
- end
1672
- end
1673
-
1674
1994
  context "when first method was called before" do
1675
1995
 
1676
1996
  before do
@@ -1678,8 +1998,9 @@ describe Mongoid::Contextual::Mongo do
1678
1998
  end
1679
1999
 
1680
2000
  it "returns the first document without touching the database" do
1681
- expect(context).to receive(:view).never
1682
- expect(context.send(method)).to eq(depeche_mode)
2001
+ expect_no_queries do
2002
+ expect(context.send(method)).to eq(depeche_mode)
2003
+ end
1683
2004
  end
1684
2005
  end
1685
2006
  end
@@ -1733,77 +2054,21 @@ describe Mongoid::Contextual::Mongo do
1733
2054
  end
1734
2055
  end
1735
2056
 
1736
- context "when the context is cached" do
2057
+ context "when the query cache is enabled" do
1737
2058
 
1738
2059
  let(:context) do
1739
2060
  described_class.new(criteria)
1740
2061
  end
1741
2062
 
1742
- context "when the whole context is loaded" do
1743
-
1744
- before do
1745
- context.to_a
1746
- end
1747
-
1748
- context "when all of the documents are cached" do
1749
-
1750
- let(:criteria) do
1751
- Band.all.cache
1752
- end
1753
-
1754
- context "when requesting all of the documents" do
1755
-
1756
- let(:docs) do
1757
- context.send(method, 3)
1758
- end
1759
-
1760
- it "returns all of the documents without touching the database" do
1761
- expect(context).to receive(:view).never
1762
- expect(docs).to eq([ depeche_mode, new_order, rolling_stones ])
1763
- end
1764
- end
1765
-
1766
- context "when requesting fewer than all of the documents" do
1767
-
1768
- let(:docs) do
1769
- context.send(method, 2)
1770
- end
1771
-
1772
- it "returns all of the documents without touching the database" do
1773
- expect(context).to receive(:view).never
1774
- expect(docs).to eq([ depeche_mode, new_order ])
1775
- end
1776
- end
1777
- end
1778
-
1779
- context "when only one document is cached" do
1780
-
1781
- let(:criteria) do
1782
- Band.where(name: "Depeche Mode").cache
1783
- end
1784
-
1785
- context "when requesting one document" do
1786
-
1787
- let(:docs) do
1788
- context.send(method, 1)
1789
- end
1790
-
1791
- it "returns one document without touching the database" do
1792
- expect(context).to receive(:view).never
1793
- expect(docs).to eq([ depeche_mode ])
1794
- end
1795
- end
1796
- end
1797
- end
1798
-
1799
- context "when the first method was called before" do
2063
+ context "when calling first beforehand" do
2064
+ query_cache_enabled
1800
2065
 
1801
2066
  let(:context) do
1802
2067
  described_class.new(criteria)
1803
2068
  end
1804
2069
 
1805
2070
  let(:criteria) do
1806
- Band.all.cache
2071
+ Band.all
1807
2072
  end
1808
2073
 
1809
2074
  before do
@@ -1821,8 +2086,9 @@ describe Mongoid::Contextual::Mongo do
1821
2086
  let(:limit) { 3 }
1822
2087
 
1823
2088
  it "returns all documents without touching the database" do
1824
- expect(context).to receive(:view).never
1825
- expect(docs).to eq([ depeche_mode, new_order, rolling_stones ])
2089
+ expect_no_queries do
2090
+ expect(docs).to eq([ depeche_mode, new_order, rolling_stones ])
2091
+ end
1826
2092
  end
1827
2093
  end
1828
2094
 
@@ -1830,8 +2096,9 @@ describe Mongoid::Contextual::Mongo do
1830
2096
  let(:limit) { 2 }
1831
2097
 
1832
2098
  it "returns the correct documents without touching the database" do
1833
- expect(context).to receive(:view).never
1834
- expect(docs).to eq([ depeche_mode, new_order ])
2099
+ expect_no_queries do
2100
+ expect(docs).to eq([ depeche_mode, new_order ])
2101
+ end
1835
2102
  end
1836
2103
  end
1837
2104
  end
@@ -1843,8 +2110,9 @@ describe Mongoid::Contextual::Mongo do
1843
2110
  let(:limit) { 2 }
1844
2111
 
1845
2112
  it "returns the correct documents without touching the database" do
1846
- expect(context).to receive(:view).never
1847
- expect(docs).to eq([ depeche_mode, new_order ])
2113
+ expect_no_queries do
2114
+ expect(docs).to eq([ depeche_mode, new_order ])
2115
+ end
1848
2116
  end
1849
2117
  end
1850
2118
 
@@ -1852,8 +2120,9 @@ describe Mongoid::Contextual::Mongo do
1852
2120
  let(:limit) { 3 }
1853
2121
 
1854
2122
  it "returns the correct documents and touches the database" do
1855
- expect(context).to receive(:view).exactly(3).times.and_call_original
1856
- expect(docs).to eq([ depeche_mode, new_order, rolling_stones ])
2123
+ expect_query(1) do
2124
+ expect(docs).to eq([ depeche_mode, new_order, rolling_stones ])
2125
+ end
1857
2126
  end
1858
2127
  end
1859
2128
  end
@@ -1865,8 +2134,9 @@ describe Mongoid::Contextual::Mongo do
1865
2134
  let(:limit) { 1 }
1866
2135
 
1867
2136
  it "returns the correct documents without touching the database" do
1868
- expect(context).to receive(:view).never
1869
- expect(docs).to eq([ depeche_mode ])
2137
+ expect_no_queries do
2138
+ expect(docs).to eq([ depeche_mode ])
2139
+ end
1870
2140
  end
1871
2141
  end
1872
2142
 
@@ -1874,8 +2144,9 @@ describe Mongoid::Contextual::Mongo do
1874
2144
  let(:limit) { 3 }
1875
2145
 
1876
2146
  it "returns the correct documents and touches the database" do
1877
- expect(context).to receive(:view).exactly(3).times.and_call_original
1878
- expect(docs).to eq([ depeche_mode, new_order, rolling_stones ])
2147
+ expect_query(1) do
2148
+ expect(docs).to eq([ depeche_mode, new_order, rolling_stones ])
2149
+ end
1879
2150
  end
1880
2151
  end
1881
2152
  end
@@ -1883,24 +2154,15 @@ describe Mongoid::Contextual::Mongo do
1883
2154
  end
1884
2155
  end
1885
2156
 
1886
- context "when given an empty hash" do
1887
- let(:context) { described_class.new(criteria) }
1888
- let(:criteria) { Band.criteria }
1889
- let(:docs) { context.send(method, {}) }
1890
-
1891
- it "behaves as if limit is nil" do
1892
- expect(docs).to eq(depeche_mode)
1893
- end
1894
- end
1895
-
1896
- context "when calling #first then #last" do
2157
+ context "when calling #first then #last and the query cache is enabled" do
2158
+ query_cache_enabled
1897
2159
 
1898
2160
  let(:context) do
1899
2161
  described_class.new(criteria)
1900
2162
  end
1901
2163
 
1902
2164
  let(:criteria) do
1903
- Band.all.cache
2165
+ Band.all
1904
2166
  end
1905
2167
 
1906
2168
  before do
@@ -1915,8 +2177,10 @@ describe Mongoid::Contextual::Mongo do
1915
2177
  let(:before_limit) { 2 }
1916
2178
  let(:limit) { 1 }
1917
2179
 
1918
- it "gets the correct document" do
1919
- expect(docs).to eq([rolling_stones])
2180
+ it "gets the correct document and hits the database" do
2181
+ expect_query(1) do
2182
+ expect(docs).to eq([rolling_stones])
2183
+ end
1920
2184
  end
1921
2185
  end
1922
2186
  end
@@ -2006,30 +2270,10 @@ describe Mongoid::Contextual::Mongo do
2006
2270
  context 'when calling #first' do
2007
2271
 
2008
2272
  it 'returns the first document, sorted by _id' do
2009
- pending "MONGOID-5416"
2010
2273
  expect(context.last).to eq(rolling_stones)
2011
2274
  expect(context.first).to eq(depeche_mode)
2012
2275
  end
2013
2276
  end
2014
-
2015
- context 'with option { id_sort: :none }' do
2016
- let(:opts) do
2017
- { id_sort: :none }
2018
- end
2019
-
2020
- it 'doesn\'t apply the sort on _id' do
2021
- expect(context.last(opts)).to eq(depeche_mode)
2022
- end
2023
-
2024
- context 'when calling #first' do
2025
-
2026
- it 'doesn\'t apply the sort on _id' do
2027
- pending "MONGOID-5416"
2028
- expect(context.last(opts)).to eq(rolling_stones)
2029
- expect(context.first(opts)).to eq(depeche_mode)
2030
- end
2031
- end
2032
- end
2033
2277
  end
2034
2278
 
2035
2279
  context 'when the criteria has a sort' do
@@ -2054,25 +2298,6 @@ describe Mongoid::Contextual::Mongo do
2054
2298
  expect(context.first).to eq(rolling_stones)
2055
2299
  end
2056
2300
  end
2057
-
2058
- context 'with option { id_sort: :none }' do
2059
-
2060
- let(:opts) do
2061
- { id_sort: :none }
2062
- end
2063
-
2064
- it 'uses the preexisting sort' do
2065
- expect(context.last(opts)).to eq(depeche_mode)
2066
- end
2067
-
2068
- context 'when calling #first' do
2069
-
2070
- it 'uses the preexisting sort' do
2071
- expect(context.last(opts)).to eq(depeche_mode)
2072
- expect(context.first(opts)).to eq(rolling_stones)
2073
- end
2074
- end
2075
- end
2076
2301
  end
2077
2302
 
2078
2303
  context "when using .sort" do
@@ -2101,28 +2326,17 @@ describe Mongoid::Contextual::Mongo do
2101
2326
  end
2102
2327
  end
2103
2328
 
2104
- context "when the context is cached" do
2329
+ context "when the query cache is enabled" do
2330
+ query_cache_enabled
2105
2331
 
2106
2332
  let(:criteria) do
2107
- Band.where(name: "Depeche Mode").cache
2333
+ Band.where(name: "Depeche Mode")
2108
2334
  end
2109
2335
 
2110
2336
  let(:context) do
2111
2337
  described_class.new(criteria)
2112
2338
  end
2113
2339
 
2114
- context "when the cache is loaded" do
2115
-
2116
- before do
2117
- context.to_a
2118
- end
2119
-
2120
- it "returns the last document without touching the database" do
2121
- expect(context).to receive(:view).never
2122
- expect(context.last).to eq(depeche_mode)
2123
- end
2124
- end
2125
-
2126
2340
  context "when last method was called before" do
2127
2341
 
2128
2342
  before do
@@ -2130,8 +2344,9 @@ describe Mongoid::Contextual::Mongo do
2130
2344
  end
2131
2345
 
2132
2346
  it "returns the last document without touching the database" do
2133
- expect(context).to receive(:view).never
2134
- expect(context.last).to eq(depeche_mode)
2347
+ expect_no_queries do
2348
+ expect(context.last).to eq(depeche_mode)
2349
+ end
2135
2350
  end
2136
2351
  end
2137
2352
  end
@@ -2191,71 +2406,15 @@ describe Mongoid::Contextual::Mongo do
2191
2406
  described_class.new(criteria)
2192
2407
  end
2193
2408
 
2194
- context "when the whole context is loaded" do
2195
-
2196
- before do
2197
- context.to_a
2198
- end
2199
-
2200
- context "when all of the documents are cached" do
2201
-
2202
- let(:criteria) do
2203
- Band.all.cache
2204
- end
2205
-
2206
- context "when requesting all of the documents" do
2207
-
2208
- let(:docs) do
2209
- context.last(3)
2210
- end
2211
-
2212
- it "returns all of the documents without touching the database" do
2213
- expect(context).to receive(:view).never
2214
- expect(docs).to eq([ depeche_mode, new_order, rolling_stones ])
2215
- end
2216
- end
2217
-
2218
- context "when requesting fewer than all of the documents" do
2219
-
2220
- let(:docs) do
2221
- context.last(2)
2222
- end
2223
-
2224
- it "returns all of the documents without touching the database" do
2225
- expect(context).to receive(:view).never
2226
- expect(docs).to eq([ new_order, rolling_stones ])
2227
- end
2228
- end
2229
- end
2230
-
2231
- context "when only one document is cached" do
2232
-
2233
- let(:criteria) do
2234
- Band.where(name: "Depeche Mode").cache
2235
- end
2236
-
2237
- context "when requesting one document" do
2238
-
2239
- let(:docs) do
2240
- context.last(1)
2241
- end
2242
-
2243
- it "returns one document without touching the database" do
2244
- expect(context).to receive(:view).never
2245
- expect(docs).to eq([ depeche_mode ])
2246
- end
2247
- end
2248
- end
2249
- end
2250
-
2251
- context "when the last method was called before" do
2409
+ context "when query cache is enabled" do
2410
+ query_cache_enabled
2252
2411
 
2253
2412
  let(:context) do
2254
2413
  described_class.new(criteria)
2255
2414
  end
2256
2415
 
2257
2416
  let(:criteria) do
2258
- Band.all.cache
2417
+ Band.all
2259
2418
  end
2260
2419
 
2261
2420
  before do
@@ -2272,18 +2431,20 @@ describe Mongoid::Contextual::Mongo do
2272
2431
  context "when getting all of the documents" do
2273
2432
  let(:limit) { 3 }
2274
2433
 
2275
- it "returns all documents without touching the database" do
2276
- expect(context).to receive(:view).never
2277
- expect(docs).to eq([ depeche_mode, new_order, rolling_stones ])
2434
+ it "returns all documents without touching the db" do
2435
+ expect_no_queries do
2436
+ expect(docs).to eq([ depeche_mode, new_order, rolling_stones ])
2437
+ end
2278
2438
  end
2279
2439
  end
2280
2440
 
2281
2441
  context "when getting fewer documents" do
2282
2442
  let(:limit) { 2 }
2283
2443
 
2284
- it "returns the correct documents without touching the database" do
2285
- expect(context).to receive(:view).never
2286
- expect(docs).to eq([ new_order, rolling_stones ])
2444
+ it "returns the correct documents without touching the db" do
2445
+ expect_no_queries do
2446
+ expect(docs).to eq([ new_order, rolling_stones ])
2447
+ end
2287
2448
  end
2288
2449
  end
2289
2450
  end
@@ -2294,9 +2455,10 @@ describe Mongoid::Contextual::Mongo do
2294
2455
  context "when getting the same number of documents" do
2295
2456
  let(:limit) { 2 }
2296
2457
 
2297
- it "returns the correct documents without touching the database" do
2298
- expect(context).to receive(:view).never
2299
- expect(docs).to eq([ new_order, rolling_stones ])
2458
+ it "returns the correct documents without touching the db" do
2459
+ expect_no_queries do
2460
+ expect(docs).to eq([ new_order, rolling_stones ])
2461
+ end
2300
2462
  end
2301
2463
  end
2302
2464
 
@@ -2304,8 +2466,9 @@ describe Mongoid::Contextual::Mongo do
2304
2466
  let(:limit) { 3 }
2305
2467
 
2306
2468
  it "returns the correct documents and touches the database" do
2307
- expect(context).to receive(:view).twice.and_call_original
2308
- expect(docs).to eq([ depeche_mode, new_order, rolling_stones ])
2469
+ expect_query(1) do
2470
+ expect(docs).to eq([ depeche_mode, new_order, rolling_stones ])
2471
+ end
2309
2472
  end
2310
2473
  end
2311
2474
  end
@@ -2317,8 +2480,9 @@ describe Mongoid::Contextual::Mongo do
2317
2480
  let(:limit) { 1 }
2318
2481
 
2319
2482
  it "returns the correct documents without touching the database" do
2320
- expect(context).to receive(:view).never
2321
- expect(docs).to eq([ rolling_stones ])
2483
+ expect_no_queries do
2484
+ expect(docs).to eq([ rolling_stones ])
2485
+ end
2322
2486
  end
2323
2487
  end
2324
2488
 
@@ -2326,8 +2490,9 @@ describe Mongoid::Contextual::Mongo do
2326
2490
  let(:limit) { 3 }
2327
2491
 
2328
2492
  it "returns the correct documents and touches the database" do
2329
- expect(context).to receive(:view).twice.and_call_original
2330
- expect(docs).to eq([ depeche_mode, new_order, rolling_stones ])
2493
+ expect_query(1) do
2494
+ expect(docs).to eq([ depeche_mode, new_order, rolling_stones ])
2495
+ end
2331
2496
  end
2332
2497
  end
2333
2498
  end
@@ -2335,14 +2500,15 @@ describe Mongoid::Contextual::Mongo do
2335
2500
  end
2336
2501
  end
2337
2502
 
2338
- context "when calling #last then #first" do
2503
+ context "when calling #last then #first and the query cache is enabled" do
2504
+ query_cache_enabled
2339
2505
 
2340
2506
  let(:context) do
2341
2507
  described_class.new(criteria)
2342
2508
  end
2343
2509
 
2344
2510
  let(:criteria) do
2345
- Band.all.cache
2511
+ Band.all
2346
2512
  end
2347
2513
 
2348
2514
  before do
@@ -2358,26 +2524,16 @@ describe Mongoid::Contextual::Mongo do
2358
2524
  let(:limit) { 1 }
2359
2525
 
2360
2526
  it "hits the database" do
2361
- expect(context).to receive(:view).exactly(3).times.and_call_original
2362
- docs
2527
+ expect_query(1) do
2528
+ docs
2529
+ end
2363
2530
  end
2364
2531
 
2365
2532
  it "gets the correct document" do
2366
- pending "MONGOID-5416"
2367
2533
  expect(docs).to eq([ depeche_mode ])
2368
2534
  end
2369
2535
  end
2370
2536
  end
2371
-
2372
- context "when given an empty hash" do
2373
- let(:context) { described_class.new(criteria) }
2374
- let(:criteria) { Band.criteria }
2375
- let(:docs) { context.last({}) }
2376
-
2377
- it "behaves as if limit is nil" do
2378
- expect(docs).to eq(rolling_stones)
2379
- end
2380
- end
2381
2537
  end
2382
2538
 
2383
2539
  describe "#initialize" do
@@ -2426,37 +2582,28 @@ describe Mongoid::Contextual::Mongo do
2426
2582
  described_class.new(criteria)
2427
2583
  end
2428
2584
 
2429
- it "returns the number of documents that match" do
2430
- expect(context.send(method)).to eq(2)
2431
- end
2585
+ context "when broken_view_options is false" do
2586
+ driver_config_override :broken_view_options, false
2432
2587
 
2433
- context "when calling more than once" do
2434
- it "returns the cached value for subsequent calls" do
2435
- expect(context.view).to receive(:count_documents).once.and_return(2)
2436
- 2.times { expect(context.send(method)).to eq(2) }
2588
+ it "returns the number of documents that match" do
2589
+ expect(context.send(method)).to eq(1)
2437
2590
  end
2438
2591
  end
2439
2592
 
2440
- context "when the results have been iterated over" do
2441
-
2442
- before do
2443
- context.entries
2444
- end
2593
+ context "when broken_view_options is true" do
2594
+ driver_config_override :broken_view_options, true
2445
2595
 
2446
- it "returns the cached value for all calls" do
2447
- expect(context.view).to receive(:count_documents).once.and_return(2)
2596
+ it "returns the number of documents that match" do
2448
2597
  expect(context.send(method)).to eq(2)
2449
2598
  end
2599
+ end
2450
2600
 
2451
- context "when the results have been iterated over multiple times" do
2452
-
2453
- before do
2454
- context.entries
2455
- end
2601
+ context "when calling more than once with different limits" do
2602
+ driver_config_override :broken_view_options, false
2456
2603
 
2457
- it "resets the length on each full iteration" do
2458
- expect(context.size).to eq(2)
2459
- end
2604
+ it "does not cache the value" do
2605
+ expect(context.limit(1).send(method)).to eq(1)
2606
+ expect(context.limit(2).send(method)).to eq(2)
2460
2607
  end
2461
2608
  end
2462
2609
  end
@@ -2475,10 +2622,12 @@ describe Mongoid::Contextual::Mongo do
2475
2622
  expect(context.send(method)).to eq(1)
2476
2623
  end
2477
2624
 
2478
- context "when calling more than once" do
2479
- it "returns the cached value for subsequent calls" do
2480
- expect(context.view).to receive(:count_documents).once.and_return(1)
2481
- 2.times { expect(context.send(method)).to eq(1) }
2625
+ context "when calling more than once with different skips" do
2626
+ driver_config_override :broken_view_options, false
2627
+
2628
+ it "does not cache the value" do
2629
+ expect(context.skip(0).send(method)).to eq(1)
2630
+ expect(context.skip(1).send(method)).to eq(0)
2482
2631
  end
2483
2632
  end
2484
2633
 
@@ -2600,7 +2749,7 @@ describe Mongoid::Contextual::Mongo do
2600
2749
  it "raises an error" do
2601
2750
  expect do
2602
2751
  Person.take!
2603
- end.to raise_error(Mongoid::Errors::DocumentNotFound)
2752
+ end.to raise_error(Mongoid::Errors::DocumentNotFound, /Could not find a document of class Person./)
2604
2753
  end
2605
2754
  end
2606
2755
  end
@@ -2622,9 +2771,10 @@ describe Mongoid::Contextual::Mongo do
2622
2771
 
2623
2772
  context "when passed the symbol field name" do
2624
2773
 
2625
- it "performs mapping and warns" do
2626
- expect(Mongoid::Warnings).to receive(:warn_map_field_deprecated)
2627
- expect(context.map(:name)).to eq ["Depeche Mode", "New Order"]
2774
+ it "raises an error" do
2775
+ expect do
2776
+ context.map(:name)
2777
+ end.to raise_error(ArgumentError)
2628
2778
  end
2629
2779
  end
2630
2780