mongoid 7.6.0 → 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 (313) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +2 -0
  3. data/README.md +3 -3
  4. data/Rakefile +21 -85
  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 -287
  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 -5
  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 -15
  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 -426
  194. data/spec/mongoid/contextual/none_spec.rb +11 -19
  195. data/spec/mongoid/copyable_spec.rb +451 -2
  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/bignum_spec.rb +1 -2
  203. data/spec/mongoid/criteria/queryable/extensions/date_spec.rb +11 -0
  204. data/spec/mongoid/criteria/queryable/extensions/date_time_spec.rb +11 -0
  205. data/spec/mongoid/criteria/queryable/extensions/fixnum_spec.rb +1 -2
  206. data/spec/mongoid/criteria/queryable/extensions/hash_spec.rb +0 -15
  207. data/spec/mongoid/criteria/queryable/extensions/numeric_spec.rb +73 -7
  208. data/spec/mongoid/criteria/queryable/extensions/time_spec.rb +11 -0
  209. data/spec/mongoid/criteria/queryable/extensions/time_with_zone_spec.rb +11 -0
  210. data/spec/mongoid/criteria/queryable/optional_spec.rb +0 -484
  211. data/spec/mongoid/criteria/queryable/selectable_logical_spec.rb +50 -0
  212. data/spec/mongoid/criteria/queryable/selectable_spec.rb +77 -85
  213. data/spec/mongoid/criteria/queryable/selector_spec.rb +16 -77
  214. data/spec/mongoid/criteria/queryable/storable_spec.rb +0 -72
  215. data/spec/mongoid/criteria_spec.rb +469 -1201
  216. data/spec/mongoid/document_fields_spec.rb +173 -24
  217. data/spec/mongoid/document_spec.rb +32 -41
  218. data/spec/mongoid/equality_spec.rb +12 -12
  219. data/spec/mongoid/errors/document_not_found_spec.rb +29 -2
  220. data/spec/mongoid/errors/invalid_field_spec.rb +1 -1
  221. data/spec/mongoid/errors/invalid_field_type_spec.rb +55 -0
  222. data/spec/mongoid/errors/mongoid_error_spec.rb +3 -1
  223. data/spec/mongoid/errors/no_environment_spec.rb +3 -3
  224. data/spec/mongoid/errors/too_many_nested_attribute_records_spec.rb +1 -1
  225. data/spec/mongoid/extensions/array_spec.rb +16 -2
  226. data/spec/mongoid/extensions/big_decimal_spec.rb +697 -212
  227. data/spec/mongoid/extensions/binary_spec.rb +44 -9
  228. data/spec/mongoid/extensions/boolean_spec.rb +68 -82
  229. data/spec/mongoid/extensions/date_class_mongoize_spec.rb +7 -3
  230. data/spec/mongoid/extensions/date_spec.rb +71 -1
  231. data/spec/mongoid/extensions/date_time_spec.rb +15 -9
  232. data/spec/mongoid/extensions/float_spec.rb +48 -76
  233. data/spec/mongoid/extensions/hash_spec.rb +30 -0
  234. data/spec/mongoid/extensions/integer_spec.rb +45 -66
  235. data/spec/mongoid/extensions/range_spec.rb +255 -54
  236. data/spec/mongoid/extensions/regexp_spec.rb +58 -33
  237. data/spec/mongoid/extensions/set_spec.rb +106 -0
  238. data/spec/mongoid/extensions/string_spec.rb +53 -25
  239. data/spec/mongoid/extensions/symbol_spec.rb +18 -25
  240. data/spec/mongoid/extensions/time_spec.rb +634 -66
  241. data/spec/mongoid/extensions/time_with_zone_spec.rb +17 -31
  242. data/spec/mongoid/factory_spec.rb +61 -1
  243. data/spec/mongoid/fields_spec.rb +321 -50
  244. data/spec/mongoid/findable_spec.rb +64 -29
  245. data/spec/mongoid/indexable/specification_spec.rb +2 -2
  246. data/spec/mongoid/indexable_spec.rb +16 -19
  247. data/spec/mongoid/interceptable_spec.rb +584 -5
  248. data/spec/mongoid/interceptable_spec_models.rb +235 -4
  249. data/spec/mongoid/matcher/extract_attribute_spec.rb +1 -5
  250. data/spec/mongoid/mongoizable_spec.rb +285 -0
  251. data/spec/mongoid/persistable/creatable_spec.rb +2 -2
  252. data/spec/mongoid/persistable/deletable_spec.rb +2 -2
  253. data/spec/mongoid/persistable/destroyable_spec.rb +2 -2
  254. data/spec/mongoid/persistable/upsertable_spec.rb +14 -0
  255. data/spec/mongoid/persistence_context_spec.rb +24 -0
  256. data/spec/mongoid/query_cache_middleware_spec.rb +0 -18
  257. data/spec/mongoid/query_cache_spec.rb +1 -156
  258. data/spec/mongoid/reloadable_spec.rb +35 -2
  259. data/spec/mongoid/scopable_spec.rb +36 -34
  260. data/spec/mongoid/serializable_spec.rb +14 -7
  261. data/spec/mongoid/shardable_models.rb +0 -14
  262. data/spec/mongoid/shardable_spec.rb +61 -153
  263. data/spec/mongoid/stateful_spec.rb +28 -0
  264. data/spec/mongoid/timestamps_spec.rb +390 -0
  265. data/spec/mongoid/timestamps_spec_models.rb +67 -0
  266. data/spec/mongoid/touchable_spec.rb +116 -0
  267. data/spec/mongoid/touchable_spec_models.rb +12 -8
  268. data/spec/mongoid/traversable_spec.rb +4 -11
  269. data/spec/mongoid/validatable/presence_spec.rb +1 -1
  270. data/spec/mongoid/validatable/uniqueness_spec.rb +60 -31
  271. data/spec/mongoid/warnings_spec.rb +35 -0
  272. data/spec/mongoid_spec.rb +1 -7
  273. data/spec/rails/controller_extension/controller_runtime_spec.rb +2 -2
  274. data/spec/rails/mongoid_spec.rb +4 -16
  275. data/spec/shared/lib/mrss/docker_runner.rb +1 -8
  276. data/spec/shared/lib/mrss/event_subscriber.rb +5 -15
  277. data/spec/shared/lib/mrss/lite_constraints.rb +2 -10
  278. data/spec/shared/lib/mrss/server_version_registry.rb +24 -17
  279. data/spec/shared/lib/mrss/spec_organizer.rb +3 -32
  280. data/spec/shared/lib/mrss/utils.rb +6 -28
  281. data/spec/shared/share/Dockerfile.erb +107 -33
  282. data/spec/shared/shlib/distro.sh +0 -10
  283. data/spec/shared/shlib/server.sh +33 -64
  284. data/spec/shared/shlib/set_env.sh +71 -12
  285. data/spec/support/constraints.rb +24 -0
  286. data/spec/support/expectations.rb +17 -20
  287. data/spec/support/macros.rb +30 -0
  288. data/spec/support/models/augmentation.rb +12 -0
  289. data/spec/support/models/band.rb +3 -0
  290. data/spec/support/models/catalog.rb +24 -0
  291. data/spec/support/models/circus.rb +3 -0
  292. data/spec/support/models/fanatic.rb +8 -0
  293. data/spec/support/models/implant.rb +9 -0
  294. data/spec/support/models/label.rb +2 -0
  295. data/spec/support/models/passport.rb +9 -0
  296. data/spec/support/models/person.rb +1 -0
  297. data/spec/support/models/player.rb +2 -0
  298. data/spec/support/models/powerup.rb +12 -0
  299. data/spec/support/models/registry.rb +1 -0
  300. data/spec/support/models/school.rb +14 -0
  301. data/spec/support/models/shield.rb +18 -0
  302. data/spec/support/models/student.rb +14 -0
  303. data/spec/support/models/weapon.rb +12 -0
  304. data.tar.gz.sig +0 -0
  305. metadata +695 -641
  306. metadata.gz.sig +0 -0
  307. data/lib/mongoid/errors/eager_load.rb +0 -23
  308. data/lib/mongoid/errors/invalid_value.rb +0 -17
  309. data/spec/mongoid/errors/eager_load_spec.rb +0 -31
  310. data/spec/shared/CANDIDATE.md +0 -28
  311. data/spec/shared/lib/mrss/release/candidate.rb +0 -281
  312. data/spec/shared/lib/mrss/release/product_data.rb +0 -144
  313. data/spec/shared/lib/tasks/candidate.rake +0 -64
@@ -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
 
@@ -189,16 +158,6 @@ describe Mongoid::Contextual::Mongo do
189
158
  end
190
159
  end
191
160
  end
192
-
193
- context 'when for_js is present' do
194
- let(:context) do
195
- Band.for_js('this.name == "Depeche Mode"')
196
- end
197
-
198
- it 'counts the expected records' do
199
- expect(context.count).to eq(1)
200
- end
201
- end
202
161
  end
203
162
 
204
163
  describe "#estimated_count" do
@@ -227,16 +186,18 @@ describe Mongoid::Contextual::Mongo do
227
186
  end
228
187
  end
229
188
 
230
- context "when context is cached" do
189
+ context "when the query cache is enabled" do
190
+ query_cache_enabled
231
191
 
232
192
  let(:context) do
233
- described_class.new(criteria.cache)
193
+ described_class.new(criteria)
234
194
  end
235
195
 
236
- it "returns the count cached value after first call" do
237
- expect(context.view).to receive(:estimated_document_count).once.and_return(1)
238
- 2.times do
239
- 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
240
201
  end
241
202
  end
242
203
  end
@@ -571,8 +532,22 @@ describe Mongoid::Contextual::Mongo do
571
532
  context "when legacy_pluck_distinct is set" do
572
533
  config_override :legacy_pluck_distinct, true
573
534
 
574
- it "returns the non-demongoized distinct field values" do
575
- 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
576
551
  end
577
552
  end
578
553
 
@@ -594,10 +569,6 @@ describe Mongoid::Contextual::Mongo do
594
569
  d.save!
595
570
  end
596
571
 
597
- after do
598
- I18n.locale = :en
599
- end
600
-
601
572
  let(:criteria) do
602
573
  Dictionary.criteria
603
574
  end
@@ -698,10 +669,6 @@ describe Mongoid::Contextual::Mongo do
698
669
  I18n.fallbacks = prev_fallbacks
699
670
  end
700
671
 
701
- after do
702
- I18n.locale = :en
703
- end
704
-
705
672
  let(:distinct) do
706
673
  context.distinct(:description).first
707
674
  end
@@ -737,10 +704,6 @@ describe Mongoid::Contextual::Mongo do
737
704
  Person.create!(passport: p, employer_id: 12345)
738
705
  end
739
706
 
740
- after do
741
- I18n.locale = :en
742
- end
743
-
744
707
  let(:criteria) do
745
708
  Person.where(employer_id: 12345)
746
709
  end
@@ -804,9 +767,11 @@ describe Mongoid::Contextual::Mongo do
804
767
 
805
768
  context "when legacy_pluck_distinct is set" do
806
769
  config_override :legacy_pluck_distinct, true
770
+ config_override :map_big_decimal_to_decimal128, true
771
+ max_bson_version '4.99.99'
807
772
 
808
773
  it "returns the distinct matching fields" do
809
- expect(context.distinct("label.sales")).to eq([ "1E2" ])
774
+ expect(context.distinct("label.sales")).to eq([ BSON::Decimal128.new('1E+2') ])
810
775
  end
811
776
  end
812
777
 
@@ -819,6 +784,435 @@ describe Mongoid::Contextual::Mongo do
819
784
  end
820
785
  end
821
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
+
822
1216
  describe "#each" do
823
1217
 
824
1218
  before do
@@ -1027,51 +1421,15 @@ describe Mongoid::Contextual::Mongo do
1027
1421
  described_class.new(criteria)
1028
1422
  end
1029
1423
 
1030
- context "when exists? already called" do
1424
+ context "when exists? already called and query cache is enabled" do
1425
+ query_cache_enabled
1031
1426
 
1032
1427
  before do
1033
1428
  context.exists?
1034
1429
  end
1035
1430
 
1036
- it "hits the database again" do
1037
- expect(context).to receive(:view).once.and_call_original
1038
- expect(context).to be_exists
1039
- end
1040
- end
1041
- end
1042
-
1043
- context "when caching is enabled" do
1044
-
1045
- let(:criteria) do
1046
- Band.where(name: "Depeche Mode").cache
1047
- end
1048
-
1049
- let(:context) do
1050
- described_class.new(criteria)
1051
- end
1052
-
1053
- context "when the cache is loaded" do
1054
-
1055
- before do
1056
- context.to_a
1057
- end
1058
-
1059
- it "does not hit the database" do
1060
- expect(context).to receive(:view).never
1061
- expect(context).to be_exists
1062
- end
1063
- end
1064
-
1065
- context "when the cache is not loaded" do
1066
-
1067
- context "when a count has been executed" do
1068
-
1069
- before do
1070
- context.count
1071
- end
1072
-
1073
- it "does not hit the database" do
1074
- expect(context).to receive(:view).never
1431
+ it "does not hit the database again" do
1432
+ expect_no_queries do
1075
1433
  expect(context).to be_exists
1076
1434
  end
1077
1435
  end
@@ -1430,7 +1788,7 @@ describe Mongoid::Contextual::Mongo do
1430
1788
  it "deletes the document from the database" do
1431
1789
  expect {
1432
1790
  depeche.reload
1433
- }.to raise_error(Mongoid::Errors::DocumentNotFound)
1791
+ }.to raise_error(Mongoid::Errors::DocumentNotFound, /Document\(s\) not found for class Band with id\(s\)/)
1434
1792
  end
1435
1793
 
1436
1794
  context 'when a collation is specified on the criteria' do
@@ -1455,7 +1813,7 @@ describe Mongoid::Contextual::Mongo do
1455
1813
  it "deletes the document from the database" do
1456
1814
  expect {
1457
1815
  depeche.reload
1458
- }.to raise_error(Mongoid::Errors::DocumentNotFound)
1816
+ }.to raise_error(Mongoid::Errors::DocumentNotFound, /Document\(s\) not found for class Band with id\(s\)/)
1459
1817
  end
1460
1818
  end
1461
1819
  end
@@ -1564,31 +1922,13 @@ describe Mongoid::Contextual::Mongo do
1564
1922
  expect(context.send(method)).to eq(depeche_mode)
1565
1923
  end
1566
1924
 
1567
- context "when calling ##{method}" do
1925
+ context 'when calling #last' do
1568
1926
 
1569
- it 'returns the requested document, sorted by _id' do
1927
+ it 'returns the last document, sorted by _id' do
1570
1928
  expect(context.send(method)).to eq(depeche_mode)
1571
1929
  expect(context.last).to eq(rolling_stones)
1572
1930
  end
1573
1931
  end
1574
-
1575
- context 'with option { id_sort: :none }' do
1576
- let(:opts) do
1577
- { id_sort: :none }
1578
- end
1579
-
1580
- it 'applies the sort on _id' do
1581
- expect(context.send(method, opts)).to eq(depeche_mode)
1582
- end
1583
-
1584
- context "when calling ##{method}" do
1585
-
1586
- it 'doesn\'t apply a sort on _id' do
1587
- expect(context.send(method, opts)).to eq(depeche_mode)
1588
- expect(context.last(opts)).to eq(depeche_mode)
1589
- end
1590
- end
1591
- end
1592
1932
  end
1593
1933
 
1594
1934
  context 'when the criteria has a sort' do
@@ -1612,25 +1952,6 @@ describe Mongoid::Contextual::Mongo do
1612
1952
  expect(context.last).to eq(depeche_mode)
1613
1953
  end
1614
1954
  end
1615
-
1616
- context 'with option { id_sort: :none }' do
1617
-
1618
- let(:opts) do
1619
- { id_sort: :none }
1620
- end
1621
-
1622
- it 'uses the preexisting sort' do
1623
- expect(context.send(method, opts)).to eq(rolling_stones)
1624
- end
1625
-
1626
- context 'when calling #last' do
1627
-
1628
- it 'uses the preexisting sort' do
1629
- expect(context.send(method, opts)).to eq(rolling_stones)
1630
- expect(context.last(opts)).to eq(depeche_mode)
1631
- end
1632
- end
1633
- end
1634
1955
  end
1635
1956
 
1636
1957
  context "when using .sort" do
@@ -1659,28 +1980,17 @@ describe Mongoid::Contextual::Mongo do
1659
1980
  end
1660
1981
  end
1661
1982
 
1662
- context "when the context is cached" do
1983
+ context "when the query cache is enabled" do
1984
+ query_cache_enabled
1663
1985
 
1664
1986
  let(:criteria) do
1665
- Band.where(name: "Depeche Mode").cache
1987
+ Band.where(name: "Depeche Mode")
1666
1988
  end
1667
1989
 
1668
1990
  let(:context) do
1669
1991
  described_class.new(criteria)
1670
1992
  end
1671
1993
 
1672
- context "when the cache is loaded" do
1673
-
1674
- before do
1675
- context.to_a
1676
- end
1677
-
1678
- it "returns the first document without touching the database" do
1679
- expect(context).to receive(:view).never
1680
- expect(context.send(method)).to eq(depeche_mode)
1681
- end
1682
- end
1683
-
1684
1994
  context "when first method was called before" do
1685
1995
 
1686
1996
  before do
@@ -1688,8 +1998,9 @@ describe Mongoid::Contextual::Mongo do
1688
1998
  end
1689
1999
 
1690
2000
  it "returns the first document without touching the database" do
1691
- expect(context).to receive(:view).never
1692
- expect(context.send(method)).to eq(depeche_mode)
2001
+ expect_no_queries do
2002
+ expect(context.send(method)).to eq(depeche_mode)
2003
+ end
1693
2004
  end
1694
2005
  end
1695
2006
  end
@@ -1743,77 +2054,21 @@ describe Mongoid::Contextual::Mongo do
1743
2054
  end
1744
2055
  end
1745
2056
 
1746
- context "when the context is cached" do
2057
+ context "when the query cache is enabled" do
1747
2058
 
1748
2059
  let(:context) do
1749
2060
  described_class.new(criteria)
1750
2061
  end
1751
2062
 
1752
- context "when the whole context is loaded" do
1753
-
1754
- before do
1755
- context.to_a
1756
- end
1757
-
1758
- context "when all of the documents are cached" do
1759
-
1760
- let(:criteria) do
1761
- Band.all.cache
1762
- end
1763
-
1764
- context "when requesting all of the documents" do
1765
-
1766
- let(:docs) do
1767
- context.send(method, 3)
1768
- end
1769
-
1770
- it "returns all of the documents without touching the database" do
1771
- expect(context).to receive(:view).never
1772
- expect(docs).to eq([ depeche_mode, new_order, rolling_stones ])
1773
- end
1774
- end
1775
-
1776
- context "when requesting fewer than all of the documents" do
1777
-
1778
- let(:docs) do
1779
- context.send(method, 2)
1780
- end
1781
-
1782
- it "returns all of the documents without touching the database" do
1783
- expect(context).to receive(:view).never
1784
- expect(docs).to eq([ depeche_mode, new_order ])
1785
- end
1786
- end
1787
- end
1788
-
1789
- context "when only one document is cached" do
1790
-
1791
- let(:criteria) do
1792
- Band.where(name: "Depeche Mode").cache
1793
- end
1794
-
1795
- context "when requesting one document" do
1796
-
1797
- let(:docs) do
1798
- context.send(method, 1)
1799
- end
1800
-
1801
- it "returns one document without touching the database" do
1802
- expect(context).to receive(:view).never
1803
- expect(docs).to eq([ depeche_mode ])
1804
- end
1805
- end
1806
- end
1807
- end
1808
-
1809
- context "when the first method was called before" do
2063
+ context "when calling first beforehand" do
2064
+ query_cache_enabled
1810
2065
 
1811
2066
  let(:context) do
1812
2067
  described_class.new(criteria)
1813
2068
  end
1814
2069
 
1815
2070
  let(:criteria) do
1816
- Band.all.cache
2071
+ Band.all
1817
2072
  end
1818
2073
 
1819
2074
  before do
@@ -1831,8 +2086,9 @@ describe Mongoid::Contextual::Mongo do
1831
2086
  let(:limit) { 3 }
1832
2087
 
1833
2088
  it "returns all documents without touching the database" do
1834
- expect(context).to receive(:view).never
1835
- 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
1836
2092
  end
1837
2093
  end
1838
2094
 
@@ -1840,8 +2096,9 @@ describe Mongoid::Contextual::Mongo do
1840
2096
  let(:limit) { 2 }
1841
2097
 
1842
2098
  it "returns the correct documents without touching the database" do
1843
- expect(context).to receive(:view).never
1844
- expect(docs).to eq([ depeche_mode, new_order ])
2099
+ expect_no_queries do
2100
+ expect(docs).to eq([ depeche_mode, new_order ])
2101
+ end
1845
2102
  end
1846
2103
  end
1847
2104
  end
@@ -1853,8 +2110,9 @@ describe Mongoid::Contextual::Mongo do
1853
2110
  let(:limit) { 2 }
1854
2111
 
1855
2112
  it "returns the correct documents without touching the database" do
1856
- expect(context).to receive(:view).never
1857
- expect(docs).to eq([ depeche_mode, new_order ])
2113
+ expect_no_queries do
2114
+ expect(docs).to eq([ depeche_mode, new_order ])
2115
+ end
1858
2116
  end
1859
2117
  end
1860
2118
 
@@ -1862,8 +2120,9 @@ describe Mongoid::Contextual::Mongo do
1862
2120
  let(:limit) { 3 }
1863
2121
 
1864
2122
  it "returns the correct documents and touches the database" do
1865
- expect(context).to receive(:view).exactly(3).times.and_call_original
1866
- 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
1867
2126
  end
1868
2127
  end
1869
2128
  end
@@ -1875,8 +2134,9 @@ describe Mongoid::Contextual::Mongo do
1875
2134
  let(:limit) { 1 }
1876
2135
 
1877
2136
  it "returns the correct documents without touching the database" do
1878
- expect(context).to receive(:view).never
1879
- expect(docs).to eq([ depeche_mode ])
2137
+ expect_no_queries do
2138
+ expect(docs).to eq([ depeche_mode ])
2139
+ end
1880
2140
  end
1881
2141
  end
1882
2142
 
@@ -1884,8 +2144,9 @@ describe Mongoid::Contextual::Mongo do
1884
2144
  let(:limit) { 3 }
1885
2145
 
1886
2146
  it "returns the correct documents and touches the database" do
1887
- expect(context).to receive(:view).exactly(3).times.and_call_original
1888
- 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
1889
2150
  end
1890
2151
  end
1891
2152
  end
@@ -1893,24 +2154,15 @@ describe Mongoid::Contextual::Mongo do
1893
2154
  end
1894
2155
  end
1895
2156
 
1896
- context "when given an empty hash" do
1897
- let(:context) { described_class.new(criteria) }
1898
- let(:criteria) { Band.criteria }
1899
- let(:docs) { context.send(method, {}) }
1900
-
1901
- it "behaves as if limit is nil" do
1902
- expect(docs).to eq(depeche_mode)
1903
- end
1904
- end
1905
-
1906
- 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
1907
2159
 
1908
2160
  let(:context) do
1909
2161
  described_class.new(criteria)
1910
2162
  end
1911
2163
 
1912
2164
  let(:criteria) do
1913
- Band.all.cache
2165
+ Band.all
1914
2166
  end
1915
2167
 
1916
2168
  before do
@@ -1925,8 +2177,10 @@ describe Mongoid::Contextual::Mongo do
1925
2177
  let(:before_limit) { 2 }
1926
2178
  let(:limit) { 1 }
1927
2179
 
1928
- it "gets the correct document" do
1929
- 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
1930
2184
  end
1931
2185
  end
1932
2186
  end
@@ -2016,30 +2270,10 @@ describe Mongoid::Contextual::Mongo do
2016
2270
  context 'when calling #first' do
2017
2271
 
2018
2272
  it 'returns the first document, sorted by _id' do
2019
- pending "MONGOID-5416"
2020
2273
  expect(context.last).to eq(rolling_stones)
2021
2274
  expect(context.first).to eq(depeche_mode)
2022
2275
  end
2023
2276
  end
2024
-
2025
- context 'with option { id_sort: :none }' do
2026
- let(:opts) do
2027
- { id_sort: :none }
2028
- end
2029
-
2030
- it 'doesn\'t apply the sort on _id' do
2031
- expect(context.last(opts)).to eq(depeche_mode)
2032
- end
2033
-
2034
- context 'when calling #first' do
2035
-
2036
- it 'doesn\'t apply the sort on _id' do
2037
- pending "MONGOID-5416"
2038
- expect(context.last(opts)).to eq(rolling_stones)
2039
- expect(context.first(opts)).to eq(depeche_mode)
2040
- end
2041
- end
2042
- end
2043
2277
  end
2044
2278
 
2045
2279
  context 'when the criteria has a sort' do
@@ -2064,25 +2298,6 @@ describe Mongoid::Contextual::Mongo do
2064
2298
  expect(context.first).to eq(rolling_stones)
2065
2299
  end
2066
2300
  end
2067
-
2068
- context 'with option { id_sort: :none }' do
2069
-
2070
- let(:opts) do
2071
- { id_sort: :none }
2072
- end
2073
-
2074
- it 'uses the preexisting sort' do
2075
- expect(context.last(opts)).to eq(depeche_mode)
2076
- end
2077
-
2078
- context 'when calling #first' do
2079
-
2080
- it 'uses the preexisting sort' do
2081
- expect(context.last(opts)).to eq(depeche_mode)
2082
- expect(context.first(opts)).to eq(rolling_stones)
2083
- end
2084
- end
2085
- end
2086
2301
  end
2087
2302
 
2088
2303
  context "when using .sort" do
@@ -2111,28 +2326,17 @@ describe Mongoid::Contextual::Mongo do
2111
2326
  end
2112
2327
  end
2113
2328
 
2114
- context "when the context is cached" do
2329
+ context "when the query cache is enabled" do
2330
+ query_cache_enabled
2115
2331
 
2116
2332
  let(:criteria) do
2117
- Band.where(name: "Depeche Mode").cache
2333
+ Band.where(name: "Depeche Mode")
2118
2334
  end
2119
2335
 
2120
2336
  let(:context) do
2121
2337
  described_class.new(criteria)
2122
2338
  end
2123
2339
 
2124
- context "when the cache is loaded" do
2125
-
2126
- before do
2127
- context.to_a
2128
- end
2129
-
2130
- it "returns the last document without touching the database" do
2131
- expect(context).to receive(:view).never
2132
- expect(context.last).to eq(depeche_mode)
2133
- end
2134
- end
2135
-
2136
2340
  context "when last method was called before" do
2137
2341
 
2138
2342
  before do
@@ -2140,8 +2344,9 @@ describe Mongoid::Contextual::Mongo do
2140
2344
  end
2141
2345
 
2142
2346
  it "returns the last document without touching the database" do
2143
- expect(context).to receive(:view).never
2144
- expect(context.last).to eq(depeche_mode)
2347
+ expect_no_queries do
2348
+ expect(context.last).to eq(depeche_mode)
2349
+ end
2145
2350
  end
2146
2351
  end
2147
2352
  end
@@ -2201,71 +2406,15 @@ describe Mongoid::Contextual::Mongo do
2201
2406
  described_class.new(criteria)
2202
2407
  end
2203
2408
 
2204
- context "when the whole context is loaded" do
2205
-
2206
- before do
2207
- context.to_a
2208
- end
2209
-
2210
- context "when all of the documents are cached" do
2211
-
2212
- let(:criteria) do
2213
- Band.all.cache
2214
- end
2215
-
2216
- context "when requesting all of the documents" do
2217
-
2218
- let(:docs) do
2219
- context.last(3)
2220
- end
2221
-
2222
- it "returns all of the documents without touching the database" do
2223
- expect(context).to receive(:view).never
2224
- expect(docs).to eq([ depeche_mode, new_order, rolling_stones ])
2225
- end
2226
- end
2227
-
2228
- context "when requesting fewer than all of the documents" do
2229
-
2230
- let(:docs) do
2231
- context.last(2)
2232
- end
2233
-
2234
- it "returns all of the documents without touching the database" do
2235
- expect(context).to receive(:view).never
2236
- expect(docs).to eq([ new_order, rolling_stones ])
2237
- end
2238
- end
2239
- end
2240
-
2241
- context "when only one document is cached" do
2242
-
2243
- let(:criteria) do
2244
- Band.where(name: "Depeche Mode").cache
2245
- end
2246
-
2247
- context "when requesting one document" do
2248
-
2249
- let(:docs) do
2250
- context.last(1)
2251
- end
2252
-
2253
- it "returns one document without touching the database" do
2254
- expect(context).to receive(:view).never
2255
- expect(docs).to eq([ depeche_mode ])
2256
- end
2257
- end
2258
- end
2259
- end
2260
-
2261
- context "when the last method was called before" do
2409
+ context "when query cache is enabled" do
2410
+ query_cache_enabled
2262
2411
 
2263
2412
  let(:context) do
2264
2413
  described_class.new(criteria)
2265
2414
  end
2266
2415
 
2267
2416
  let(:criteria) do
2268
- Band.all.cache
2417
+ Band.all
2269
2418
  end
2270
2419
 
2271
2420
  before do
@@ -2282,18 +2431,20 @@ describe Mongoid::Contextual::Mongo do
2282
2431
  context "when getting all of the documents" do
2283
2432
  let(:limit) { 3 }
2284
2433
 
2285
- it "returns all documents without touching the database" do
2286
- expect(context).to receive(:view).never
2287
- 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
2288
2438
  end
2289
2439
  end
2290
2440
 
2291
2441
  context "when getting fewer documents" do
2292
2442
  let(:limit) { 2 }
2293
2443
 
2294
- it "returns the correct documents without touching the database" do
2295
- expect(context).to receive(:view).never
2296
- 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
2297
2448
  end
2298
2449
  end
2299
2450
  end
@@ -2304,9 +2455,10 @@ describe Mongoid::Contextual::Mongo do
2304
2455
  context "when getting the same number of documents" do
2305
2456
  let(:limit) { 2 }
2306
2457
 
2307
- it "returns the correct documents without touching the database" do
2308
- expect(context).to receive(:view).never
2309
- 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
2310
2462
  end
2311
2463
  end
2312
2464
 
@@ -2314,8 +2466,9 @@ describe Mongoid::Contextual::Mongo do
2314
2466
  let(:limit) { 3 }
2315
2467
 
2316
2468
  it "returns the correct documents and touches the database" do
2317
- expect(context).to receive(:view).twice.and_call_original
2318
- 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
2319
2472
  end
2320
2473
  end
2321
2474
  end
@@ -2327,8 +2480,9 @@ describe Mongoid::Contextual::Mongo do
2327
2480
  let(:limit) { 1 }
2328
2481
 
2329
2482
  it "returns the correct documents without touching the database" do
2330
- expect(context).to receive(:view).never
2331
- expect(docs).to eq([ rolling_stones ])
2483
+ expect_no_queries do
2484
+ expect(docs).to eq([ rolling_stones ])
2485
+ end
2332
2486
  end
2333
2487
  end
2334
2488
 
@@ -2336,8 +2490,9 @@ describe Mongoid::Contextual::Mongo do
2336
2490
  let(:limit) { 3 }
2337
2491
 
2338
2492
  it "returns the correct documents and touches the database" do
2339
- expect(context).to receive(:view).twice.and_call_original
2340
- 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
2341
2496
  end
2342
2497
  end
2343
2498
  end
@@ -2345,14 +2500,15 @@ describe Mongoid::Contextual::Mongo do
2345
2500
  end
2346
2501
  end
2347
2502
 
2348
- 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
2349
2505
 
2350
2506
  let(:context) do
2351
2507
  described_class.new(criteria)
2352
2508
  end
2353
2509
 
2354
2510
  let(:criteria) do
2355
- Band.all.cache
2511
+ Band.all
2356
2512
  end
2357
2513
 
2358
2514
  before do
@@ -2368,26 +2524,16 @@ describe Mongoid::Contextual::Mongo do
2368
2524
  let(:limit) { 1 }
2369
2525
 
2370
2526
  it "hits the database" do
2371
- expect(context).to receive(:view).exactly(3).times.and_call_original
2372
- docs
2527
+ expect_query(1) do
2528
+ docs
2529
+ end
2373
2530
  end
2374
2531
 
2375
2532
  it "gets the correct document" do
2376
- pending "MONGOID-5416"
2377
2533
  expect(docs).to eq([ depeche_mode ])
2378
2534
  end
2379
2535
  end
2380
2536
  end
2381
-
2382
- context "when given an empty hash" do
2383
- let(:context) { described_class.new(criteria) }
2384
- let(:criteria) { Band.criteria }
2385
- let(:docs) { context.last({}) }
2386
-
2387
- it "behaves as if limit is nil" do
2388
- expect(docs).to eq(rolling_stones)
2389
- end
2390
- end
2391
2537
  end
2392
2538
 
2393
2539
  describe "#initialize" do
@@ -2436,37 +2582,28 @@ describe Mongoid::Contextual::Mongo do
2436
2582
  described_class.new(criteria)
2437
2583
  end
2438
2584
 
2439
- it "returns the number of documents that match" do
2440
- expect(context.send(method)).to eq(2)
2441
- end
2585
+ context "when broken_view_options is false" do
2586
+ driver_config_override :broken_view_options, false
2442
2587
 
2443
- context "when calling more than once" do
2444
- it "returns the cached value for subsequent calls" do
2445
- expect(context.view).to receive(:count_documents).once.and_return(2)
2446
- 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)
2447
2590
  end
2448
2591
  end
2449
2592
 
2450
- context "when the results have been iterated over" do
2451
-
2452
- before do
2453
- context.entries
2454
- end
2593
+ context "when broken_view_options is true" do
2594
+ driver_config_override :broken_view_options, true
2455
2595
 
2456
- it "returns the cached value for all calls" do
2457
- expect(context.view).to receive(:count_documents).once.and_return(2)
2596
+ it "returns the number of documents that match" do
2458
2597
  expect(context.send(method)).to eq(2)
2459
2598
  end
2599
+ end
2460
2600
 
2461
- context "when the results have been iterated over multiple times" do
2462
-
2463
- before do
2464
- context.entries
2465
- end
2601
+ context "when calling more than once with different limits" do
2602
+ driver_config_override :broken_view_options, false
2466
2603
 
2467
- it "resets the length on each full iteration" do
2468
- expect(context.size).to eq(2)
2469
- 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)
2470
2607
  end
2471
2608
  end
2472
2609
  end
@@ -2485,10 +2622,12 @@ describe Mongoid::Contextual::Mongo do
2485
2622
  expect(context.send(method)).to eq(1)
2486
2623
  end
2487
2624
 
2488
- context "when calling more than once" do
2489
- it "returns the cached value for subsequent calls" do
2490
- expect(context.view).to receive(:count_documents).once.and_return(1)
2491
- 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)
2492
2631
  end
2493
2632
  end
2494
2633
 
@@ -2610,7 +2749,7 @@ describe Mongoid::Contextual::Mongo do
2610
2749
  it "raises an error" do
2611
2750
  expect do
2612
2751
  Person.take!
2613
- end.to raise_error(Mongoid::Errors::DocumentNotFound)
2752
+ end.to raise_error(Mongoid::Errors::DocumentNotFound, /Could not find a document of class Person./)
2614
2753
  end
2615
2754
  end
2616
2755
  end
@@ -2632,9 +2771,10 @@ describe Mongoid::Contextual::Mongo do
2632
2771
 
2633
2772
  context "when passed the symbol field name" do
2634
2773
 
2635
- it "performs mapping and warns" do
2636
- expect(Mongoid::Warnings).to receive(:warn_map_field_deprecated)
2637
- 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)
2638
2778
  end
2639
2779
  end
2640
2780