mongoid 7.5.4 → 8.0.1

Sign up to get free protection for your applications and to get access to all the features.
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