mongoid 7.4.3 → 8.0.7

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 (383) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/README.md +3 -3
  4. data/Rakefile +25 -0
  5. data/lib/config/locales/en.yml +52 -28
  6. data/lib/mongoid/association/accessors.rb +38 -9
  7. data/lib/mongoid/association/bindable.rb +50 -2
  8. data/lib/mongoid/association/builders.rb +4 -2
  9. data/lib/mongoid/association/constrainable.rb +0 -1
  10. data/lib/mongoid/association/eager_loadable.rb +29 -7
  11. data/lib/mongoid/association/embedded/batchable.rb +33 -10
  12. data/lib/mongoid/association/embedded/cyclic.rb +1 -1
  13. data/lib/mongoid/association/embedded/embedded_in/binding.rb +24 -2
  14. data/lib/mongoid/association/embedded/embedded_in/proxy.rb +2 -2
  15. data/lib/mongoid/association/embedded/embedded_in.rb +3 -2
  16. data/lib/mongoid/association/embedded/embeds_many/binding.rb +1 -0
  17. data/lib/mongoid/association/embedded/embeds_many/buildable.rb +1 -1
  18. data/lib/mongoid/association/embedded/embeds_many/proxy.rb +65 -41
  19. data/lib/mongoid/association/embedded/embeds_many.rb +2 -2
  20. data/lib/mongoid/association/embedded/embeds_one/buildable.rb +18 -4
  21. data/lib/mongoid/association/embedded/embeds_one/proxy.rb +23 -4
  22. data/lib/mongoid/association/embedded/embeds_one.rb +3 -3
  23. data/lib/mongoid/association/macros.rb +28 -1
  24. data/lib/mongoid/association/many.rb +11 -7
  25. data/lib/mongoid/association/nested/many.rb +5 -4
  26. data/lib/mongoid/association/nested/nested_buildable.rb +4 -4
  27. data/lib/mongoid/association/nested/one.rb +5 -5
  28. data/lib/mongoid/association/one.rb +2 -2
  29. data/lib/mongoid/association/options.rb +9 -9
  30. data/lib/mongoid/association/proxy.rb +14 -3
  31. data/lib/mongoid/association/referenced/auto_save.rb +4 -3
  32. data/lib/mongoid/association/referenced/belongs_to/binding.rb +1 -0
  33. data/lib/mongoid/association/referenced/belongs_to/buildable.rb +1 -1
  34. data/lib/mongoid/association/referenced/belongs_to/proxy.rb +5 -6
  35. data/lib/mongoid/association/referenced/belongs_to.rb +2 -2
  36. data/lib/mongoid/association/referenced/counter_cache.rb +10 -10
  37. data/lib/mongoid/association/referenced/eager.rb +2 -2
  38. data/lib/mongoid/association/referenced/has_and_belongs_to_many/proxy.rb +70 -13
  39. data/lib/mongoid/association/referenced/has_and_belongs_to_many.rb +6 -3
  40. data/lib/mongoid/association/referenced/has_many/enumerable.rb +20 -24
  41. data/lib/mongoid/association/referenced/has_many/proxy.rb +26 -16
  42. data/lib/mongoid/association/referenced/has_many.rb +3 -3
  43. data/lib/mongoid/association/referenced/has_one/buildable.rb +1 -1
  44. data/lib/mongoid/association/referenced/has_one/nested_builder.rb +5 -5
  45. data/lib/mongoid/association/referenced/has_one/proxy.rb +9 -12
  46. data/lib/mongoid/association/referenced/has_one.rb +3 -3
  47. data/lib/mongoid/association/referenced/syncable.rb +4 -4
  48. data/lib/mongoid/association/reflections.rb +2 -2
  49. data/lib/mongoid/association/relatable.rb +44 -10
  50. data/lib/mongoid/association.rb +5 -5
  51. data/lib/mongoid/atomic/modifiers.rb +2 -2
  52. data/lib/mongoid/atomic.rb +7 -0
  53. data/lib/mongoid/attributes/dynamic.rb +3 -3
  54. data/lib/mongoid/attributes/nested.rb +5 -5
  55. data/lib/mongoid/attributes/processing.rb +37 -6
  56. data/lib/mongoid/attributes/projector.rb +1 -1
  57. data/lib/mongoid/attributes/readonly.rb +2 -2
  58. data/lib/mongoid/attributes.rb +43 -40
  59. data/lib/mongoid/cacheable.rb +2 -2
  60. data/lib/mongoid/changeable.rb +43 -10
  61. data/lib/mongoid/clients/options.rb +5 -1
  62. data/lib/mongoid/clients/sessions.rb +2 -14
  63. data/lib/mongoid/clients/validators/storage.rb +3 -3
  64. data/lib/mongoid/config/options.rb +3 -0
  65. data/lib/mongoid/config/validators/client.rb +6 -6
  66. data/lib/mongoid/config.rb +62 -17
  67. data/lib/mongoid/contextual/aggregable/memory.rb +24 -16
  68. data/lib/mongoid/contextual/aggregable/mongo.rb +5 -5
  69. data/lib/mongoid/contextual/aggregable/none.rb +1 -1
  70. data/lib/mongoid/contextual/atomic.rb +1 -1
  71. data/lib/mongoid/contextual/geo_near.rb +7 -7
  72. data/lib/mongoid/contextual/map_reduce.rb +2 -2
  73. data/lib/mongoid/contextual/memory.rb +180 -21
  74. data/lib/mongoid/contextual/mongo.rb +260 -217
  75. data/lib/mongoid/contextual/none.rb +67 -5
  76. data/lib/mongoid/contextual/queryable.rb +1 -1
  77. data/lib/mongoid/contextual.rb +2 -2
  78. data/lib/mongoid/copyable.rb +32 -8
  79. data/lib/mongoid/criteria/findable.rb +7 -4
  80. data/lib/mongoid/criteria/includable.rb +24 -20
  81. data/lib/mongoid/criteria/marshalable.rb +10 -2
  82. data/lib/mongoid/criteria/permission.rb +1 -1
  83. data/lib/mongoid/criteria/queryable/aggregable.rb +2 -2
  84. data/lib/mongoid/criteria/queryable/extensions/array.rb +3 -14
  85. data/lib/mongoid/criteria/queryable/extensions/big_decimal.rb +25 -4
  86. data/lib/mongoid/criteria/queryable/extensions/boolean.rb +2 -2
  87. data/lib/mongoid/criteria/queryable/extensions/date.rb +6 -1
  88. data/lib/mongoid/criteria/queryable/extensions/date_time.rb +6 -1
  89. data/lib/mongoid/criteria/queryable/extensions/hash.rb +1 -15
  90. data/lib/mongoid/criteria/queryable/extensions/numeric.rb +1 -9
  91. data/lib/mongoid/criteria/queryable/extensions/object.rb +2 -1
  92. data/lib/mongoid/criteria/queryable/extensions/range.rb +13 -5
  93. data/lib/mongoid/criteria/queryable/extensions/regexp.rb +3 -3
  94. data/lib/mongoid/criteria/queryable/extensions/set.rb +1 -1
  95. data/lib/mongoid/criteria/queryable/extensions/string.rb +4 -14
  96. data/lib/mongoid/criteria/queryable/extensions/symbol.rb +4 -12
  97. data/lib/mongoid/criteria/queryable/extensions/time.rb +6 -1
  98. data/lib/mongoid/criteria/queryable/extensions/time_with_zone.rb +6 -1
  99. data/lib/mongoid/criteria/queryable/key.rb +3 -3
  100. data/lib/mongoid/criteria/queryable/mergeable.rb +21 -0
  101. data/lib/mongoid/criteria/queryable/optional.rb +5 -11
  102. data/lib/mongoid/criteria/queryable/options.rb +2 -2
  103. data/lib/mongoid/criteria/queryable/pipeline.rb +1 -1
  104. data/lib/mongoid/criteria/queryable/selectable.rb +31 -37
  105. data/lib/mongoid/criteria/queryable/selector.rb +93 -8
  106. data/lib/mongoid/criteria/queryable/smash.rb +40 -7
  107. data/lib/mongoid/criteria/queryable/storable.rb +1 -1
  108. data/lib/mongoid/criteria/queryable.rb +12 -7
  109. data/lib/mongoid/criteria/scopable.rb +2 -2
  110. data/lib/mongoid/criteria/translator.rb +45 -0
  111. data/lib/mongoid/criteria.rb +16 -35
  112. data/lib/mongoid/deprecable.rb +37 -0
  113. data/lib/mongoid/deprecation.rb +25 -0
  114. data/lib/mongoid/document.rb +135 -34
  115. data/lib/mongoid/equality.rb +8 -8
  116. data/lib/mongoid/errors/document_not_found.rb +33 -12
  117. data/lib/mongoid/errors/invalid_config_option.rb +1 -1
  118. data/lib/mongoid/errors/invalid_dependent_strategy.rb +1 -1
  119. data/lib/mongoid/errors/invalid_dot_dollar_assignment.rb +23 -0
  120. data/lib/mongoid/errors/invalid_field.rb +6 -2
  121. data/lib/mongoid/errors/invalid_field_type.rb +26 -0
  122. data/lib/mongoid/errors/invalid_relation.rb +1 -1
  123. data/lib/mongoid/errors/invalid_relation_option.rb +1 -1
  124. data/lib/mongoid/errors/invalid_session_use.rb +1 -1
  125. data/lib/mongoid/errors/invalid_storage_options.rb +1 -1
  126. data/lib/mongoid/errors/mongoid_error.rb +3 -3
  127. data/lib/mongoid/errors/nested_attributes_metadata_not_found.rb +1 -1
  128. data/lib/mongoid/errors/no_client_database.rb +1 -1
  129. data/lib/mongoid/errors/no_client_hosts.rb +1 -1
  130. data/lib/mongoid/errors/readonly_attribute.rb +1 -1
  131. data/lib/mongoid/errors/too_many_nested_attribute_records.rb +1 -1
  132. data/lib/mongoid/errors/unknown_attribute.rb +1 -1
  133. data/lib/mongoid/errors.rb +2 -2
  134. data/lib/mongoid/extensions/array.rb +9 -7
  135. data/lib/mongoid/extensions/big_decimal.rb +33 -10
  136. data/lib/mongoid/extensions/binary.rb +42 -0
  137. data/lib/mongoid/extensions/boolean.rb +8 -2
  138. data/lib/mongoid/extensions/date.rb +26 -20
  139. data/lib/mongoid/extensions/date_time.rb +1 -1
  140. data/lib/mongoid/extensions/false_class.rb +1 -1
  141. data/lib/mongoid/extensions/float.rb +7 -4
  142. data/lib/mongoid/extensions/hash.rb +37 -8
  143. data/lib/mongoid/extensions/integer.rb +7 -4
  144. data/lib/mongoid/extensions/module.rb +1 -1
  145. data/lib/mongoid/extensions/object.rb +8 -6
  146. data/lib/mongoid/extensions/range.rb +41 -10
  147. data/lib/mongoid/extensions/regexp.rb +11 -4
  148. data/lib/mongoid/extensions/set.rb +11 -4
  149. data/lib/mongoid/extensions/string.rb +11 -22
  150. data/lib/mongoid/extensions/symbol.rb +4 -15
  151. data/lib/mongoid/extensions/time.rb +27 -16
  152. data/lib/mongoid/extensions/time_with_zone.rb +1 -2
  153. data/lib/mongoid/extensions/true_class.rb +1 -1
  154. data/lib/mongoid/extensions.rb +1 -0
  155. data/lib/mongoid/factory.rb +55 -7
  156. data/lib/mongoid/fields/foreign_key.rb +11 -4
  157. data/lib/mongoid/fields/localized.rb +9 -4
  158. data/lib/mongoid/fields/standard.rb +7 -7
  159. data/lib/mongoid/fields/validators/macro.rb +3 -9
  160. data/lib/mongoid/fields.rb +233 -40
  161. data/lib/mongoid/findable.rb +34 -13
  162. data/lib/mongoid/indexable/specification.rb +2 -2
  163. data/lib/mongoid/indexable/validators/options.rb +6 -2
  164. data/lib/mongoid/interceptable.rb +185 -16
  165. data/lib/mongoid/matchable.rb +1 -1
  166. data/lib/mongoid/matcher.rb +33 -13
  167. data/lib/mongoid/persistable/creatable.rb +18 -9
  168. data/lib/mongoid/persistable/deletable.rb +1 -1
  169. data/lib/mongoid/persistable/destroyable.rb +1 -1
  170. data/lib/mongoid/persistable/savable.rb +2 -2
  171. data/lib/mongoid/persistable/unsettable.rb +1 -1
  172. data/lib/mongoid/persistable/updatable.rb +19 -12
  173. data/lib/mongoid/persistable/upsertable.rb +1 -1
  174. data/lib/mongoid/persistable.rb +3 -3
  175. data/lib/mongoid/persistence_context.rb +63 -10
  176. data/lib/mongoid/query_cache.rb +8 -260
  177. data/lib/mongoid/railties/controller_runtime.rb +1 -1
  178. data/lib/mongoid/reloadable.rb +10 -8
  179. data/lib/mongoid/scopable.rb +26 -22
  180. data/lib/mongoid/selectable.rb +1 -2
  181. data/lib/mongoid/serializable.rb +10 -6
  182. data/lib/mongoid/shardable.rb +35 -11
  183. data/lib/mongoid/stateful.rb +35 -9
  184. data/lib/mongoid/tasks/database.rb +0 -2
  185. data/lib/mongoid/threaded/lifecycle.rb +5 -5
  186. data/lib/mongoid/threaded.rb +42 -12
  187. data/lib/mongoid/timestamps/created.rb +1 -1
  188. data/lib/mongoid/timestamps/updated.rb +2 -2
  189. data/lib/mongoid/touchable.rb +2 -3
  190. data/lib/mongoid/traversable.rb +5 -4
  191. data/lib/mongoid/validatable/localizable.rb +1 -1
  192. data/lib/mongoid/validatable/macros.rb +0 -2
  193. data/lib/mongoid/validatable/presence.rb +2 -2
  194. data/lib/mongoid/validatable/uniqueness.rb +9 -8
  195. data/lib/mongoid/validatable.rb +6 -6
  196. data/lib/mongoid/version.rb +1 -1
  197. data/lib/mongoid/warnings.rb +28 -0
  198. data/lib/mongoid.rb +2 -0
  199. data/lib/rails/generators/mongoid/config/templates/mongoid.yml +4 -3
  200. data/spec/config/mongoid.yml +16 -0
  201. data/spec/integration/app_spec.rb +8 -12
  202. data/spec/integration/associations/belongs_to_spec.rb +18 -0
  203. data/spec/integration/associations/embedded_spec.rb +15 -0
  204. data/spec/integration/associations/embeds_many_spec.rb +15 -2
  205. data/spec/integration/associations/embeds_one_spec.rb +18 -0
  206. data/spec/integration/associations/foreign_key_spec.rb +9 -0
  207. data/spec/integration/associations/has_and_belongs_to_many_spec.rb +21 -0
  208. data/spec/integration/associations/has_one_spec.rb +97 -1
  209. data/spec/integration/associations/scope_option_spec.rb +1 -1
  210. data/spec/integration/callbacks_models.rb +95 -1
  211. data/spec/integration/callbacks_spec.rb +246 -4
  212. data/spec/integration/criteria/range_spec.rb +95 -1
  213. data/spec/integration/discriminator_key_spec.rb +115 -76
  214. data/spec/integration/dots_and_dollars_spec.rb +277 -0
  215. data/spec/integration/i18n_fallbacks_spec.rb +1 -17
  216. data/spec/integration/matcher_examples_spec.rb +20 -13
  217. data/spec/integration/matcher_operator_data/type_decimal.yml +3 -2
  218. data/spec/integration/matcher_operator_spec.rb +3 -5
  219. data/spec/integration/persistence/range_field_spec.rb +350 -0
  220. data/spec/mongoid/association/counter_cache_spec.rb +1 -1
  221. data/spec/mongoid/association/depending_spec.rb +9 -9
  222. data/spec/mongoid/association/eager_spec.rb +2 -1
  223. data/spec/mongoid/association/embedded/embedded_in/binding_spec.rb +2 -1
  224. data/spec/mongoid/association/embedded/embedded_in/buildable_spec.rb +54 -0
  225. data/spec/mongoid/association/embedded/embedded_in/proxy_spec.rb +69 -9
  226. data/spec/mongoid/association/embedded/embeds_many/buildable_spec.rb +112 -0
  227. data/spec/mongoid/association/embedded/embeds_many/proxy_spec.rb +235 -40
  228. data/spec/mongoid/association/embedded/embeds_many_models.rb +36 -0
  229. data/spec/mongoid/association/embedded/embeds_many_query_spec.rb +12 -0
  230. data/spec/mongoid/association/embedded/embeds_many_spec.rb +68 -0
  231. data/spec/mongoid/association/embedded/embeds_one/buildable_spec.rb +25 -0
  232. data/spec/mongoid/association/embedded/embeds_one_models.rb +19 -0
  233. data/spec/mongoid/association/embedded/embeds_one_spec.rb +28 -0
  234. data/spec/mongoid/association/referenced/belongs_to/binding_spec.rb +2 -1
  235. data/spec/mongoid/association/referenced/belongs_to/buildable_spec.rb +54 -0
  236. data/spec/mongoid/association/referenced/belongs_to/proxy_spec.rb +15 -0
  237. data/spec/mongoid/association/referenced/belongs_to_models.rb +11 -0
  238. data/spec/mongoid/association/referenced/belongs_to_spec.rb +2 -2
  239. data/spec/mongoid/association/referenced/has_and_belongs_to_many/proxy_spec.rb +202 -201
  240. data/spec/mongoid/association/referenced/has_and_belongs_to_many_models.rb +25 -0
  241. data/spec/mongoid/association/referenced/has_and_belongs_to_many_spec.rb +35 -2
  242. data/spec/mongoid/association/referenced/has_many/buildable_spec.rb +109 -0
  243. data/spec/mongoid/association/referenced/has_many/enumerable_spec.rb +8 -8
  244. data/spec/mongoid/association/referenced/has_many/proxy_spec.rb +160 -119
  245. data/spec/mongoid/association/referenced/has_many_models.rb +3 -1
  246. data/spec/mongoid/association/referenced/has_many_spec.rb +25 -0
  247. data/spec/mongoid/association/referenced/has_one/buildable_spec.rb +2 -2
  248. data/spec/mongoid/association/referenced/has_one/proxy_spec.rb +107 -1
  249. data/spec/mongoid/association/referenced/has_one_models.rb +16 -0
  250. data/spec/mongoid/association/syncable_spec.rb +14 -0
  251. data/spec/mongoid/atomic/paths_spec.rb +0 -14
  252. data/spec/mongoid/attributes/nested_spec.rb +80 -11
  253. data/spec/mongoid/attributes/nested_spec_models.rb +48 -0
  254. data/spec/mongoid/attributes/projector_spec.rb +1 -5
  255. data/spec/mongoid/attributes_spec.rb +551 -27
  256. data/spec/mongoid/cacheable_spec.rb +3 -3
  257. data/spec/mongoid/changeable_spec.rb +130 -13
  258. data/spec/mongoid/clients/factory_spec.rb +23 -30
  259. data/spec/mongoid/clients/options_spec.rb +1 -0
  260. data/spec/mongoid/clients/sessions_spec.rb +0 -38
  261. data/spec/mongoid/clients_spec.rb +57 -2
  262. data/spec/mongoid/config_spec.rb +78 -18
  263. data/spec/mongoid/contextual/aggregable/memory_spec.rb +396 -158
  264. data/spec/mongoid/contextual/aggregable/memory_table.yml +88 -0
  265. data/spec/mongoid/contextual/aggregable/memory_table_spec.rb +62 -0
  266. data/spec/mongoid/contextual/map_reduce_spec.rb +2 -16
  267. data/spec/mongoid/contextual/memory_spec.rb +1336 -69
  268. data/spec/mongoid/contextual/mongo_spec.rb +1253 -247
  269. data/spec/mongoid/contextual/none_spec.rb +38 -0
  270. data/spec/mongoid/copyable_spec.rb +451 -1
  271. data/spec/mongoid/criteria/findable_spec.rb +86 -210
  272. data/spec/mongoid/criteria/includable_spec.rb +1492 -0
  273. data/spec/mongoid/criteria/includable_spec_models.rb +54 -0
  274. data/spec/mongoid/criteria/marshalable_spec.rb +18 -1
  275. data/spec/mongoid/criteria/queryable/extensions/array_spec.rb +7 -19
  276. data/spec/mongoid/criteria/queryable/extensions/big_decimal_spec.rb +134 -26
  277. data/spec/mongoid/criteria/queryable/extensions/date_spec.rb +11 -0
  278. data/spec/mongoid/criteria/queryable/extensions/date_time_spec.rb +11 -0
  279. data/spec/mongoid/criteria/queryable/extensions/hash_spec.rb +0 -15
  280. data/spec/mongoid/criteria/queryable/extensions/numeric_spec.rb +73 -7
  281. data/spec/mongoid/criteria/queryable/extensions/string_spec.rb +0 -59
  282. data/spec/mongoid/criteria/queryable/extensions/symbol_spec.rb +0 -59
  283. data/spec/mongoid/criteria/queryable/extensions/time_spec.rb +11 -0
  284. data/spec/mongoid/criteria/queryable/extensions/time_with_zone_spec.rb +11 -0
  285. data/spec/mongoid/criteria/queryable/optional_spec.rb +15 -484
  286. data/spec/mongoid/criteria/queryable/selectable_logical_spec.rb +50 -0
  287. data/spec/mongoid/criteria/queryable/selectable_spec.rb +289 -124
  288. data/spec/mongoid/criteria/queryable/selector_spec.rb +89 -4
  289. data/spec/mongoid/criteria/queryable/storable_spec.rb +72 -0
  290. data/spec/mongoid/criteria/translator_spec.rb +132 -0
  291. data/spec/mongoid/criteria_projection_spec.rb +0 -1
  292. data/spec/mongoid/criteria_spec.rb +475 -1199
  293. data/spec/mongoid/document_fields_spec.rb +173 -24
  294. data/spec/mongoid/document_spec.rb +32 -41
  295. data/spec/mongoid/errors/document_not_found_spec.rb +76 -0
  296. data/spec/mongoid/errors/invalid_field_spec.rb +1 -1
  297. data/spec/mongoid/errors/invalid_field_type_spec.rb +55 -0
  298. data/spec/mongoid/errors/mongoid_error_spec.rb +3 -1
  299. data/spec/mongoid/errors/no_environment_spec.rb +3 -3
  300. data/spec/mongoid/errors/too_many_nested_attribute_records_spec.rb +1 -1
  301. data/spec/mongoid/extensions/array_spec.rb +16 -2
  302. data/spec/mongoid/extensions/big_decimal_spec.rb +712 -212
  303. data/spec/mongoid/extensions/binary_spec.rb +44 -9
  304. data/spec/mongoid/extensions/boolean_spec.rb +68 -82
  305. data/spec/mongoid/extensions/date_class_mongoize_spec.rb +7 -3
  306. data/spec/mongoid/extensions/date_spec.rb +71 -1
  307. data/spec/mongoid/extensions/date_time_spec.rb +15 -9
  308. data/spec/mongoid/extensions/float_spec.rb +53 -74
  309. data/spec/mongoid/extensions/hash_spec.rb +33 -3
  310. data/spec/mongoid/extensions/integer_spec.rb +50 -64
  311. data/spec/mongoid/extensions/range_spec.rb +255 -54
  312. data/spec/mongoid/extensions/regexp_spec.rb +58 -33
  313. data/spec/mongoid/extensions/set_spec.rb +106 -0
  314. data/spec/mongoid/extensions/string_spec.rb +53 -25
  315. data/spec/mongoid/extensions/symbol_spec.rb +18 -25
  316. data/spec/mongoid/extensions/time_spec.rb +634 -66
  317. data/spec/mongoid/extensions/time_with_zone_spec.rb +17 -31
  318. data/spec/mongoid/factory_spec.rb +61 -1
  319. data/spec/mongoid/fields/localized_spec.rb +37 -12
  320. data/spec/mongoid/fields_spec.rb +364 -50
  321. data/spec/mongoid/findable_spec.rb +80 -15
  322. data/spec/mongoid/indexable/specification_spec.rb +2 -2
  323. data/spec/mongoid/indexable_spec.rb +39 -20
  324. data/spec/mongoid/interceptable_spec.rb +807 -27
  325. data/spec/mongoid/interceptable_spec_models.rb +235 -4
  326. data/spec/mongoid/matcher/extract_attribute_spec.rb +1 -5
  327. data/spec/mongoid/mongoizable_spec.rb +285 -0
  328. data/spec/mongoid/persistable/creatable_spec.rb +2 -2
  329. data/spec/mongoid/persistable/deletable_spec.rb +2 -2
  330. data/spec/mongoid/persistable/destroyable_spec.rb +2 -2
  331. data/spec/mongoid/persistable/upsertable_spec.rb +14 -0
  332. data/spec/mongoid/persistence_context_spec.rb +50 -1
  333. data/spec/mongoid/query_cache_middleware_spec.rb +0 -18
  334. data/spec/mongoid/query_cache_spec.rb +0 -154
  335. data/spec/mongoid/reloadable_spec.rb +59 -2
  336. data/spec/mongoid/scopable_spec.rb +54 -16
  337. data/spec/mongoid/shardable_models.rb +14 -0
  338. data/spec/mongoid/shardable_spec.rb +157 -51
  339. data/spec/mongoid/stateful_spec.rb +28 -0
  340. data/spec/mongoid/timestamps_spec.rb +390 -0
  341. data/spec/mongoid/timestamps_spec_models.rb +67 -0
  342. data/spec/mongoid/touchable_spec.rb +116 -0
  343. data/spec/mongoid/touchable_spec_models.rb +12 -8
  344. data/spec/mongoid/traversable_spec.rb +4 -11
  345. data/spec/mongoid/validatable/presence_spec.rb +1 -1
  346. data/spec/mongoid/validatable/uniqueness_spec.rb +59 -31
  347. data/spec/mongoid/warnings_spec.rb +35 -0
  348. data/spec/mongoid_spec.rb +1 -1
  349. data/spec/rails/controller_extension/controller_runtime_spec.rb +2 -2
  350. data/spec/rails/mongoid_spec.rb +4 -16
  351. data/spec/shared/lib/mrss/docker_runner.rb +7 -0
  352. data/spec/shared/lib/mrss/lite_constraints.rb +10 -2
  353. data/spec/shared/lib/mrss/server_version_registry.rb +16 -23
  354. data/spec/shared/lib/mrss/utils.rb +28 -6
  355. data/spec/shared/share/Dockerfile.erb +36 -40
  356. data/spec/shared/shlib/server.sh +32 -8
  357. data/spec/shared/shlib/set_env.sh +4 -4
  358. data/spec/support/constraints.rb +24 -0
  359. data/spec/support/macros.rb +46 -0
  360. data/spec/support/models/augmentation.rb +12 -0
  361. data/spec/support/models/band.rb +3 -0
  362. data/spec/support/models/catalog.rb +24 -0
  363. data/spec/support/models/circus.rb +3 -0
  364. data/spec/support/models/code.rb +2 -0
  365. data/spec/support/models/fanatic.rb +8 -0
  366. data/spec/support/models/implant.rb +9 -0
  367. data/spec/support/models/label.rb +2 -0
  368. data/spec/support/models/passport.rb +9 -0
  369. data/spec/support/models/person.rb +2 -0
  370. data/spec/support/models/player.rb +2 -0
  371. data/spec/support/models/powerup.rb +12 -0
  372. data/spec/support/models/purse.rb +9 -0
  373. data/spec/support/models/registry.rb +1 -0
  374. data/spec/support/models/school.rb +14 -0
  375. data/spec/support/models/shield.rb +18 -0
  376. data/spec/support/models/student.rb +14 -0
  377. data/spec/support/models/weapon.rb +12 -0
  378. data.tar.gz.sig +4 -1
  379. metadata +682 -635
  380. metadata.gz.sig +0 -0
  381. data/lib/mongoid/errors/eager_load.rb +0 -23
  382. data/lib/mongoid/errors/invalid_value.rb +0 -17
  383. 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
 
@@ -189,6 +158,16 @@ describe Mongoid::Contextual::Mongo do
189
158
  end
190
159
  end
191
160
  end
161
+
162
+ context 'when for_js is present' do
163
+ let(:context) do
164
+ Band.for_js('this.name == "Depeche Mode"')
165
+ end
166
+
167
+ it 'counts the expected records' do
168
+ expect(context.count).to eq(1)
169
+ end
170
+ end
192
171
  end
193
172
 
194
173
  describe "#estimated_count" do
@@ -217,16 +196,18 @@ describe Mongoid::Contextual::Mongo do
217
196
  end
218
197
  end
219
198
 
220
- context "when context is cached" do
199
+ context "when the query cache is enabled" do
200
+ query_cache_enabled
221
201
 
222
202
  let(:context) do
223
- described_class.new(criteria.cache)
203
+ described_class.new(criteria)
224
204
  end
225
205
 
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
206
+ it "the results are not cached" do
207
+ expect_query(2) do
208
+ 2.times do
209
+ context.estimated_count
210
+ end
230
211
  end
231
212
  end
232
213
  end
@@ -561,8 +542,22 @@ describe Mongoid::Contextual::Mongo do
561
542
  context "when legacy_pluck_distinct is set" do
562
543
  config_override :legacy_pluck_distinct, true
563
544
 
564
- it "returns the non-demongoized distinct field values" do
565
- expect(context.distinct(:sales).sort).to eq([ "1E2", "2E3" ])
545
+ context 'when storing BigDecimal as string' do
546
+ config_override :map_big_decimal_to_decimal128, false
547
+
548
+ it "returns the non-demongoized distinct field values" do
549
+ expect(context.distinct(:sales).sort).to eq([ "1E2", "2E3" ])
550
+ end
551
+ end
552
+
553
+ context 'when storing BigDecimal as decimal128' do
554
+ config_override :map_big_decimal_to_decimal128, true
555
+ min_bson_version '4.15.0'
556
+ max_bson_version '4.99.99'
557
+
558
+ it "returns the non-demongoized distinct field values" do
559
+ expect(context.distinct(:sales).sort).to eq([ BSON::Decimal128.new("1E2"), BSON::Decimal128.new("2E3") ])
560
+ end
566
561
  end
567
562
  end
568
563
 
@@ -675,7 +670,7 @@ describe Mongoid::Contextual::Mongo do
675
670
  end
676
671
 
677
672
  context 'when fallbacks are enabled with a locale list' do
678
- require_fallbacks
673
+ with_i18n_fallbacks
679
674
 
680
675
  around(:all) do |example|
681
676
  prev_fallbacks = I18n.fallbacks.dup
@@ -701,7 +696,7 @@ describe Mongoid::Contextual::Mongo do
701
696
 
702
697
  it "correctly uses the fallback" do
703
698
  I18n.locale = :en
704
- d = Dictionary.create!(description: 'english-text')
699
+ Dictionary.create!(description: 'english-text')
705
700
  I18n.locale = :he
706
701
  distinct.should == "english-text"
707
702
  end
@@ -782,9 +777,11 @@ describe Mongoid::Contextual::Mongo do
782
777
 
783
778
  context "when legacy_pluck_distinct is set" do
784
779
  config_override :legacy_pluck_distinct, true
780
+ config_override :map_big_decimal_to_decimal128, true
781
+ max_bson_version '4.99.99'
785
782
 
786
783
  it "returns the distinct matching fields" do
787
- expect(context.distinct("label.sales")).to eq([ "1E2" ])
784
+ expect(context.distinct("label.sales")).to eq([ BSON::Decimal128.new('1E+2') ])
788
785
  end
789
786
  end
790
787
 
@@ -797,6 +794,449 @@ describe Mongoid::Contextual::Mongo do
797
794
  end
798
795
  end
799
796
 
797
+ describe "#tally" do
798
+ let(:fans1) { [ Fanatic.new(age:1), Fanatic.new(age:2) ] }
799
+ let(:fans2) { [ Fanatic.new(age:1), Fanatic.new(age:2) ] }
800
+ let(:fans3) { [ Fanatic.new(age:1), Fanatic.new(age:3) ] }
801
+
802
+ let(:genres1) { [ { x: 1, y: { z: 1 } }, { x: 2, y: { z: 2 } }, { y: 3 } ]}
803
+ let(:genres2) { [ { x: 1, y: { z: 1 } }, { x: 2, y: { z: 2 } }, { y: 4 } ]}
804
+ let(:genres3) { [ { x: 1, y: { z: 1 } }, { x: 3, y: { z: 3 } }, { y: 5 } ]}
805
+
806
+ let(:label1) { Label.new(name: "Atlantic") }
807
+ let(:label2) { Label.new(name: "Atlantic") }
808
+ let(:label3) { Label.new(name: "Columbia") }
809
+
810
+ before do
811
+ Band.create!(origin: "tally", name: "Depeche Mode", years: 30, sales: "1E2", label: label1, genres: genres1)
812
+ Band.create!(origin: "tally", name: "New Order", years: 30, sales: "2E3", label: label2, genres: genres2)
813
+ Band.create!(origin: "tally", name: "10,000 Maniacs", years: 30, sales: "1E2", label: label3, genres: genres3)
814
+ Band.create!(origin: "tally2", fanatics: fans1, genres: [1, 2])
815
+ Band.create!(origin: "tally2", fanatics: fans2, genres: [1, 2])
816
+ Band.create!(origin: "tally2", fanatics: fans3, genres: [1, 3])
817
+ end
818
+
819
+ let(:criteria) { Band.where(origin: "tally") }
820
+
821
+ context "when tallying a string" do
822
+ let(:tally) do
823
+ criteria.tally(:name)
824
+ end
825
+
826
+ it "returns the correct hash" do
827
+ expect(tally).to eq("Depeche Mode" => 1, "New Order" => 1, "10,000 Maniacs" => 1)
828
+ end
829
+ end
830
+
831
+ context "using an aliased field" do
832
+ let(:tally) do
833
+ criteria.tally(:years)
834
+ end
835
+
836
+ it "returns the correct hash" do
837
+ expect(tally).to eq(30 => 3)
838
+ end
839
+ end
840
+
841
+ context "when tallying a demongoizable field" do
842
+ let(:tally) do
843
+ criteria.tally(:sales)
844
+ end
845
+
846
+ it "returns the correct hash" do
847
+ expect(tally).to eq(BigDecimal("1E2") => 2, BigDecimal("2E3") => 1)
848
+ end
849
+ end
850
+
851
+ context "when tallying a localized field" do
852
+ before do
853
+ I18n.locale = :en
854
+ d1 = Dictionary.create!(description: 'en1')
855
+ d2 = Dictionary.create!(description: 'en1')
856
+ d3 = Dictionary.create!(description: 'en1')
857
+ d4 = Dictionary.create!(description: 'en2')
858
+ I18n.locale = :de
859
+ d1.description = 'de1'
860
+ d2.description = 'de1'
861
+ d3.description = 'de2'
862
+ d4.description = 'de3'
863
+ d1.save!
864
+ d2.save!
865
+ d3.save!
866
+ d4.save!
867
+ I18n.locale = :en
868
+ end
869
+
870
+ context "when getting the demongoized field" do
871
+ let(:tallied) do
872
+ Dictionary.tally(:description)
873
+ end
874
+
875
+ it "returns the translation for the current locale" do
876
+ expect(tallied).to eq("en1" => 3, "en2" => 1)
877
+ end
878
+ end
879
+
880
+ context "when getting a specific locale" do
881
+ let(:tallied) do
882
+ Dictionary.tally("description.de")
883
+ end
884
+
885
+ it "returns the translation for the the specific locale" do
886
+ expect(tallied).to eq("de1" => 2, "de2" => 1, "de3" => 1)
887
+ end
888
+ end
889
+
890
+ context "when getting the full hash" do
891
+ let(:tallied) do
892
+ Dictionary.tally("description_translations")
893
+ end
894
+
895
+ it "returns the correct hash" do
896
+ expect(tallied).to eq(
897
+ {"de" => "de1", "en" => "en1" } => 2,
898
+ {"de" => "de2", "en" => "en1" } => 1,
899
+ {"de" => "de3", "en" => "en2" } => 1
900
+ )
901
+ end
902
+ end
903
+ end
904
+
905
+ context "when tallying an embedded localized field" do
906
+
907
+ before do
908
+ I18n.locale = :en
909
+ address1a = Address.new(name: "en1")
910
+ address1b = Address.new(name: "en2")
911
+ address2a = Address.new(name: "en1")
912
+ address2b = Address.new(name: "en3")
913
+ I18n.locale = :de
914
+ address1a.name = "de1"
915
+ address1b.name = "de2"
916
+ address2a.name = "de1"
917
+ address2b.name = "de3"
918
+ Person.create!(addresses: [ address1a, address1b ])
919
+ Person.create!(addresses: [ address2a, address2b ])
920
+ I18n.locale = :en
921
+ end
922
+
923
+ context "when getting the demongoized field" do
924
+ let(:tallied) do
925
+ Person.tally("addresses.name")
926
+ end
927
+
928
+ it "returns the translation for the current locale" do
929
+ expect(tallied).to eq(
930
+ [ "en1", "en2" ] => 1,
931
+ [ "en1", "en3" ] => 1,
932
+ )
933
+ end
934
+ end
935
+
936
+ context "when getting a specific locale" do
937
+ let(:tallied) do
938
+ Person.tally("addresses.name.de")
939
+ end
940
+
941
+ it "returns the translation for the the specific locale" do
942
+ expect(tallied).to eq(
943
+ [ "de1", "de2" ] => 1,
944
+ [ "de1", "de3" ] => 1,
945
+ )
946
+ end
947
+ end
948
+
949
+ context "when getting the full hash" do
950
+ let(:tallied) do
951
+ Person.tally("addresses.name_translations")
952
+ end
953
+
954
+ it "returns the correct hash" do
955
+ expect(tallied).to eq(
956
+ [{ "de" => "de1", "en" => "en1" }, { "de" => "de2", "en" => "en2" }] => 1,
957
+ [{ "de" => "de1", "en" => "en1" }, { "de" => "de3", "en" => "en3" }] => 1,
958
+ )
959
+ end
960
+ end
961
+
962
+ end
963
+
964
+ context "when tallying an embedded field" do
965
+ let(:tally) do
966
+ criteria.tally("label.name")
967
+ end
968
+
969
+ it "returns the correct hash" do
970
+ expect(tally).to eq("Atlantic" => 2, "Columbia" => 1)
971
+ end
972
+ end
973
+
974
+ context "when tallying an element in an embeds_many field" do
975
+ let(:criteria) { Band.where(origin: "tally2") }
976
+
977
+ let(:tally) do
978
+ criteria.tally("fanatics.age")
979
+ end
980
+
981
+ it "returns the correct hash" do
982
+ expect(tally).to eq(
983
+ [1, 2] => 2,
984
+ [1, 3] => 1
985
+ )
986
+ end
987
+ end
988
+
989
+ context "when tallying an embeds_many field" do
990
+ let(:criteria) { Band.where(origin: "tally2") }
991
+
992
+ let(:tally) do
993
+ criteria.tally("fanatics")
994
+ end
995
+
996
+ it "returns the correct hash" do
997
+ expect(tally).to eq(
998
+ fans1.map(&:attributes) => 1,
999
+ fans2.map(&:attributes) => 1,
1000
+ fans3.map(&:attributes) => 1,
1001
+ )
1002
+ end
1003
+ end
1004
+
1005
+ context "when tallying a field of type array" do
1006
+ let(:criteria) { Band.where(origin: "tally2") }
1007
+
1008
+ let(:tally) do
1009
+ criteria.tally("genres")
1010
+ end
1011
+
1012
+ it "returns the correct hash" do
1013
+ expect(tally).to eq(
1014
+ [1, 2] => 2,
1015
+ [1, 3] => 1
1016
+ )
1017
+ end
1018
+ end
1019
+
1020
+ context "when tallying an element from an array of hashes" do
1021
+ let(:criteria) { Band.where(origin: "tally") }
1022
+
1023
+ let(:tally) do
1024
+ criteria.tally("genres.x")
1025
+ end
1026
+
1027
+ it "returns the correct hash without the nil keys" do
1028
+ expect(tally).to eq(
1029
+ [1, 2] => 2,
1030
+ [1, 3] => 1
1031
+ )
1032
+ end
1033
+ end
1034
+
1035
+ context "when tallying an element from an array of hashes; with duplicate" do
1036
+
1037
+ before do
1038
+ Band.create!(origin: "tally", genres: [ { x: 1 }, {x: 1} ] )
1039
+ end
1040
+
1041
+ let(:criteria) { Band.where(origin: "tally") }
1042
+
1043
+ let(:tally) do
1044
+ criteria.tally("genres.x")
1045
+ end
1046
+
1047
+ it "returns the correct hash without the nil keys" do
1048
+ expect(tally).to eq(
1049
+ [1, 2] => 2,
1050
+ [1, 3] => 1,
1051
+ [1, 1] => 1,
1052
+ )
1053
+ end
1054
+ end
1055
+
1056
+ context "when tallying an aliased field of type array" do
1057
+
1058
+ before do
1059
+ Person.create!(array: [ 1, 2 ])
1060
+ Person.create!(array: [ 1, 3 ])
1061
+ end
1062
+
1063
+ let(:tally) do
1064
+ Person.tally("array")
1065
+ end
1066
+
1067
+ it "returns the correct hash" do
1068
+ expect(tally).to eq(
1069
+ [1, 2] => 1,
1070
+ [1, 3] => 1
1071
+ )
1072
+ end
1073
+ end
1074
+
1075
+ context "when going multiple levels deep in arrays" do
1076
+ let(:criteria) { Band.where(origin: "tally") }
1077
+
1078
+ let(:tally) do
1079
+ criteria.tally("genres.y.z")
1080
+ end
1081
+
1082
+ it "returns the correct hash" do
1083
+ expect(tally).to eq(
1084
+ [1, 2] => 2,
1085
+ [1, 3] => 1
1086
+ )
1087
+ end
1088
+ end
1089
+
1090
+ context "when going multiple levels deep in an array" do
1091
+ let(:criteria) { Band.where(origin: "tally") }
1092
+
1093
+ let(:tally) do
1094
+ criteria.tally("genres.y.z")
1095
+ end
1096
+
1097
+ it "returns the correct hash" do
1098
+ expect(tally).to eq(
1099
+ [1, 2] => 2,
1100
+ [1, 3] => 1
1101
+ )
1102
+ end
1103
+ end
1104
+
1105
+ context "when tallying deeply nested arrays/embedded associations" do
1106
+
1107
+ before do
1108
+ Person.create!(addresses: [ Address.new(code: Code.new(deepest: Deepest.new(array: [ { y: { z: 1 } }, { y: { z: 2 } } ]))) ])
1109
+ Person.create!(addresses: [ Address.new(code: Code.new(deepest: Deepest.new(array: [ { y: { z: 1 } }, { y: { z: 2 } } ]))) ])
1110
+ Person.create!(addresses: [ Address.new(code: Code.new(deepest: Deepest.new(array: [ { y: { z: 1 } }, { y: { z: 3 } } ]))) ])
1111
+ end
1112
+
1113
+ let(:tally) do
1114
+ Person.tally("addresses.code.deepest.array.y.z")
1115
+ end
1116
+
1117
+ it "returns the correct hash" do
1118
+ expect(tally).to eq(
1119
+ [ [ 1, 2 ] ] => 2,
1120
+ [ [ 1, 3 ] ] => 1
1121
+ )
1122
+ end
1123
+ end
1124
+
1125
+ context "when tallying deeply nested arrays/embedded associations" do
1126
+
1127
+ before do
1128
+ Person.create!(addresses: [ Address.new(code: Code.new(deepest: Deepest.new(array: [ { y: { z: 1 } }, { y: { z: 2 } } ]))),
1129
+ Address.new(code: Code.new(deepest: Deepest.new(array: [ { y: { z: 1 } }, { y: { z: 2 } } ]))) ])
1130
+ Person.create!(addresses: [ Address.new(code: Code.new(deepest: Deepest.new(array: [ { y: { z: 1 } }, { y: { z: 2 } } ]))),
1131
+ Address.new(code: Code.new(deepest: Deepest.new(array: [ { y: { z: 1 } }, { y: { z: 2 } } ]))) ])
1132
+ Person.create!(addresses: [ Address.new(code: Code.new(deepest: Deepest.new(array: [ { y: { z: 1 } }, { y: { z: 3 } } ]))),
1133
+ Address.new(code: Code.new(deepest: Deepest.new(array: [ { y: { z: 1 } }, { y: { z: 3 } } ]))) ])
1134
+ end
1135
+
1136
+ let(:tally) do
1137
+ Person.tally("addresses.code.deepest.array.y.z")
1138
+ end
1139
+
1140
+ it "returns the correct hash" do
1141
+ expect(tally).to eq(
1142
+ [ [ 1, 2 ], [ 1, 2 ] ] => 2,
1143
+ [ [ 1, 3 ], [ 1, 3 ] ] => 1
1144
+ )
1145
+ end
1146
+ end
1147
+
1148
+ context "when some keys are missing" do
1149
+ before do
1150
+ 3.times { Band.create!(origin: "tally") }
1151
+ end
1152
+
1153
+ let(:tally) do
1154
+ criteria.tally(:name)
1155
+ end
1156
+
1157
+ it "returns the correct hash" do
1158
+ expect(tally).to eq(
1159
+ "Depeche Mode" => 1,
1160
+ "New Order" => 1,
1161
+ "10,000 Maniacs" => 1,
1162
+ nil => 3
1163
+ )
1164
+ end
1165
+ end
1166
+
1167
+ context "when the first element is an embeds_one" do
1168
+ before do
1169
+ Person.create!(name: Name.new(translations: [ Translation.new(language: 1), Translation.new(language: 2) ]))
1170
+ Person.create!(name: Name.new(translations: [ Translation.new(language: 1), Translation.new(language: 2) ]))
1171
+ Person.create!(name: Name.new(translations: [ Translation.new(language: 1), Translation.new(language: 3) ]))
1172
+ end
1173
+
1174
+ let(:tally) do
1175
+ Person.tally("name.translations.language")
1176
+ end
1177
+
1178
+ it "returns the correct hash" do
1179
+ expect(tally).to eq(
1180
+ [1, 2] => 2,
1181
+ [1, 3] => 1
1182
+ )
1183
+ end
1184
+ end
1185
+
1186
+ context "when tallying demongoizable values from typeless fields" do
1187
+
1188
+ let!(:person1) { Person.create!(ssn: /hello/) }
1189
+ let!(:person2) { Person.create!(ssn: BSON::Decimal128.new("1")) }
1190
+ let(:tally) { Person.tally("ssn") }
1191
+
1192
+ let(:tallied_classes) do
1193
+ tally.keys.map(&:class).sort do |a, b|
1194
+ a.to_s.casecmp(b.to_s)
1195
+ end
1196
+ end
1197
+
1198
+ context "< BSON 5" do
1199
+ max_bson_version '4.99.99'
1200
+
1201
+ it "stores the correct types in the database" do
1202
+ expect(Person.find(person1.id).attributes["ssn"]).to be_a BSON::Regexp::Raw
1203
+ expect(Person.find(person2.id).attributes["ssn"]).to be_a BSON::Decimal128
1204
+ end
1205
+
1206
+ it "tallies the correct type" do
1207
+ expect(tallied_classes).to be == [ BSON::Decimal128, BSON::Regexp::Raw ]
1208
+ end
1209
+ end
1210
+
1211
+ context '>= BSON 5' do
1212
+ min_bson_version "5.0"
1213
+
1214
+ it "stores the correct types in the database" do
1215
+ expect(Person.find(person1.id).ssn).to be_a BSON::Regexp::Raw
1216
+ expect(Person.find(person2.id).ssn).to be_a BigDecimal
1217
+ end
1218
+
1219
+ it "tallies the correct type" do
1220
+ expect(tallied_classes).to be == [ BigDecimal, BSON::Regexp::Raw ]
1221
+ end
1222
+ end
1223
+
1224
+ context '>= BSON 5 with decimal128 allowed' do
1225
+ min_bson_version "5.0"
1226
+ config_override :allow_bson5_decimal128, true
1227
+
1228
+ it "stores the correct types in the database" do
1229
+ expect(Person.find(person1.id).ssn).to be_a BSON::Regexp::Raw
1230
+ expect(Person.find(person2.id).ssn).to be_a BSON::Decimal128
1231
+ end
1232
+
1233
+ it "tallies the correct type" do
1234
+ expect(tallied_classes).to be == [ BSON::Decimal128, BSON::Regexp::Raw ]
1235
+ end
1236
+ end
1237
+ end
1238
+ end
1239
+
800
1240
  describe "#each" do
801
1241
 
802
1242
  before do
@@ -1005,63 +1445,27 @@ describe Mongoid::Contextual::Mongo do
1005
1445
  described_class.new(criteria)
1006
1446
  end
1007
1447
 
1008
- context "when exists? already called" do
1448
+ context "when exists? already called and query cache is enabled" do
1449
+ query_cache_enabled
1009
1450
 
1010
1451
  before do
1011
1452
  context.exists?
1012
1453
  end
1013
1454
 
1014
- it "hits the database again" do
1015
- expect(context).to receive(:view).once.and_call_original
1016
- expect(context).to be_exists
1455
+ it "does not hit the database again" do
1456
+ expect_no_queries do
1457
+ expect(context).to be_exists
1458
+ end
1017
1459
  end
1018
1460
  end
1019
1461
  end
1462
+ end
1020
1463
 
1021
- context "when caching is enabled" do
1464
+ describe "#explain" do
1022
1465
 
1023
- let(:criteria) do
1024
- Band.where(name: "Depeche Mode").cache
1025
- end
1026
-
1027
- let(:context) do
1028
- described_class.new(criteria)
1029
- end
1030
-
1031
- context "when the cache is loaded" do
1032
-
1033
- before do
1034
- context.to_a
1035
- end
1036
-
1037
- it "does not hit the database" do
1038
- expect(context).to receive(:view).never
1039
- expect(context).to be_exists
1040
- end
1041
- end
1042
-
1043
- context "when the cache is not loaded" do
1044
-
1045
- context "when a count has been executed" do
1046
-
1047
- before do
1048
- context.count
1049
- end
1050
-
1051
- it "does not hit the database" do
1052
- expect(context).to receive(:view).never
1053
- expect(context).to be_exists
1054
- end
1055
- end
1056
- end
1057
- end
1058
- end
1059
-
1060
- describe "#explain" do
1061
-
1062
- let(:criteria) do
1063
- Band.where(name: "Depeche Mode")
1064
- end
1466
+ let(:criteria) do
1467
+ Band.where(name: "Depeche Mode")
1468
+ end
1065
1469
 
1066
1470
  let(:context) do
1067
1471
  described_class.new(criteria)
@@ -1408,7 +1812,7 @@ describe Mongoid::Contextual::Mongo do
1408
1812
  it "deletes the document from the database" do
1409
1813
  expect {
1410
1814
  depeche.reload
1411
- }.to raise_error(Mongoid::Errors::DocumentNotFound)
1815
+ }.to raise_error(Mongoid::Errors::DocumentNotFound, /Document\(s\) not found for class Band with id\(s\)/)
1412
1816
  end
1413
1817
 
1414
1818
  context 'when a collation is specified on the criteria' do
@@ -1433,7 +1837,7 @@ describe Mongoid::Contextual::Mongo do
1433
1837
  it "deletes the document from the database" do
1434
1838
  expect {
1435
1839
  depeche.reload
1436
- }.to raise_error(Mongoid::Errors::DocumentNotFound)
1840
+ }.to raise_error(Mongoid::Errors::DocumentNotFound, /Document\(s\) not found for class Band with id\(s\)/)
1437
1841
  end
1438
1842
  end
1439
1843
  end
@@ -1470,203 +1874,687 @@ describe Mongoid::Contextual::Mongo do
1470
1874
  Band.create!(name: "New Order")
1471
1875
  end
1472
1876
 
1473
- context "when the context is not cached" do
1877
+ let!(:rolling_stones) do
1878
+ Band.create!(name: "The Rolling Stones")
1879
+ end
1880
+
1881
+ context "when the context is not cached" do
1882
+
1883
+ let(:criteria) do
1884
+ Band.where(name: "Depeche Mode")
1885
+ end
1886
+
1887
+ let(:context) do
1888
+ described_class.new(criteria)
1889
+ end
1890
+
1891
+ it "returns the first matching document" do
1892
+ expect(context.send(method)).to eq(depeche_mode)
1893
+ end
1894
+
1895
+ context 'when the criteria has a collation' do
1896
+ min_server_version '3.4'
1897
+
1898
+ let(:criteria) do
1899
+ Band.where(name: "DEPECHE MODE").collation(locale: 'en_US', strength: 2)
1900
+ end
1901
+
1902
+ it "returns the first matching document" do
1903
+ expect(context.send(method)).to eq(depeche_mode)
1904
+ end
1905
+ end
1906
+ end
1907
+
1908
+ context "when using .desc" do
1909
+
1910
+ let(:criteria) do
1911
+ Band.desc(:name)
1912
+ end
1913
+
1914
+ let(:context) do
1915
+ described_class.new(criteria)
1916
+ end
1917
+
1918
+ context "when there is sort on the context" do
1919
+
1920
+ it "follows the main sort" do
1921
+ expect(context.send(method)).to eq(rolling_stones)
1922
+ end
1923
+ end
1924
+
1925
+ context "when subsequently calling #last" do
1926
+
1927
+ it "returns the correct document" do
1928
+ expect(context.send(method)).to eq(rolling_stones)
1929
+ expect(context.last).to eq(depeche_mode)
1930
+ end
1931
+ end
1932
+ end
1933
+
1934
+ context 'when the criteria has no sort' do
1935
+
1936
+ let(:criteria) do
1937
+ Band.all
1938
+ end
1939
+
1940
+ let(:context) do
1941
+ described_class.new(criteria)
1942
+ end
1943
+
1944
+
1945
+ it 'applies a sort on _id' do
1946
+ expect(context.send(method)).to eq(depeche_mode)
1947
+ end
1948
+
1949
+ context 'when calling #last' do
1950
+
1951
+ it 'returns the last document, sorted by _id' do
1952
+ expect(context.send(method)).to eq(depeche_mode)
1953
+ expect(context.last).to eq(rolling_stones)
1954
+ end
1955
+ end
1956
+ end
1957
+
1958
+ context 'when the criteria has a sort' do
1959
+
1960
+ let(:criteria) do
1961
+ Band.desc(:name)
1962
+ end
1963
+
1964
+ let(:context) do
1965
+ described_class.new(criteria)
1966
+ end
1967
+
1968
+ it 'applies the criteria sort' do
1969
+ expect(context.send(method)).to eq(rolling_stones)
1970
+ end
1971
+
1972
+ context 'when calling #last' do
1973
+
1974
+ it 'applies the criteria sort' do
1975
+ expect(context.send(method)).to eq(rolling_stones)
1976
+ expect(context.last).to eq(depeche_mode)
1977
+ end
1978
+ end
1979
+ end
1980
+
1981
+ context "when using .sort" do
1982
+
1983
+ let(:criteria) do
1984
+ Band.all.sort(:name => -1).criteria
1985
+ end
1986
+
1987
+ let(:context) do
1988
+ described_class.new(criteria)
1989
+ end
1990
+
1991
+ context "when there is sort on the context" do
1992
+
1993
+ it "follows the main sort" do
1994
+ expect(context.send(method)).to eq(rolling_stones)
1995
+ end
1996
+ end
1997
+
1998
+ context "when subsequently calling #last" do
1999
+
2000
+ it "returns the correct document" do
2001
+ expect(context.send(method)).to eq(rolling_stones)
2002
+ expect(context.last).to eq(depeche_mode)
2003
+ end
2004
+ end
2005
+ end
2006
+
2007
+ context "when the query cache is enabled" do
2008
+ query_cache_enabled
2009
+
2010
+ let(:criteria) do
2011
+ Band.where(name: "Depeche Mode")
2012
+ end
2013
+
2014
+ let(:context) do
2015
+ described_class.new(criteria)
2016
+ end
2017
+
2018
+ context "when first method was called before" do
2019
+
2020
+ before do
2021
+ context.first
2022
+ end
2023
+
2024
+ it "returns the first document without touching the database" do
2025
+ expect_no_queries do
2026
+ expect(context.send(method)).to eq(depeche_mode)
2027
+ end
2028
+ end
2029
+ end
2030
+ end
2031
+
2032
+ context "when including a limit" do
2033
+
2034
+ context "when the context is not cached" do
2035
+
2036
+ let(:context) do
2037
+ described_class.new(criteria)
2038
+ end
2039
+
2040
+ context "when the limit is 1" do
2041
+ let(:criteria) do
2042
+ Band.criteria
2043
+ end
2044
+
2045
+ let(:docs) do
2046
+ context.send(method, 1)
2047
+ end
2048
+
2049
+ it "returns an array of documents" do
2050
+ expect(docs).to eq([ depeche_mode ])
2051
+ end
2052
+ end
2053
+
2054
+ context "when the limit is >1" do
2055
+ let(:criteria) do
2056
+ Band.criteria
2057
+ end
2058
+
2059
+ let(:docs) do
2060
+ context.send(method, 2)
2061
+ end
2062
+
2063
+ it "returns the number of documents in order" do
2064
+ expect(docs).to eq([ depeche_mode, new_order ])
2065
+ end
2066
+ end
2067
+
2068
+ context 'when the criteria has a collation' do
2069
+ min_server_version '3.4'
2070
+
2071
+ let(:criteria) do
2072
+ Band.where(name: "DEPECHE MODE").collation(locale: 'en_US', strength: 2)
2073
+ end
2074
+
2075
+ it "returns the first matching document" do
2076
+ expect(context.send(method, 1)).to eq([ depeche_mode ])
2077
+ end
2078
+ end
2079
+ end
2080
+
2081
+ context "when the query cache is enabled" do
2082
+
2083
+ let(:context) do
2084
+ described_class.new(criteria)
2085
+ end
2086
+
2087
+ context "when calling first beforehand" do
2088
+ query_cache_enabled
2089
+
2090
+ let(:context) do
2091
+ described_class.new(criteria)
2092
+ end
2093
+
2094
+ let(:criteria) do
2095
+ Band.all
2096
+ end
2097
+
2098
+ before do
2099
+ context.first(before_limit)
2100
+ end
2101
+
2102
+ let(:docs) do
2103
+ context.send(method, limit)
2104
+ end
2105
+
2106
+ context "when getting all of the documents before" do
2107
+ let(:before_limit) { 3 }
2108
+
2109
+ context "when getting all of the documents" do
2110
+ let(:limit) { 3 }
2111
+
2112
+ it "returns all documents without touching the database" do
2113
+ expect_no_queries do
2114
+ expect(docs).to eq([ depeche_mode, new_order, rolling_stones ])
2115
+ end
2116
+ end
2117
+ end
2118
+
2119
+ context "when getting fewer documents" do
2120
+ let(:limit) { 2 }
2121
+
2122
+ it "returns the correct documents without touching the database" do
2123
+ expect_no_queries do
2124
+ expect(docs).to eq([ depeche_mode, new_order ])
2125
+ end
2126
+ end
2127
+ end
2128
+ end
2129
+
2130
+ context "when getting fewer documents before" do
2131
+ let(:before_limit) { 2 }
2132
+
2133
+ context "when getting the same number of documents" do
2134
+ let(:limit) { 2 }
2135
+
2136
+ it "returns the correct documents without touching the database" do
2137
+ expect_no_queries do
2138
+ expect(docs).to eq([ depeche_mode, new_order ])
2139
+ end
2140
+ end
2141
+ end
2142
+
2143
+ context "when getting more documents" do
2144
+ let(:limit) { 3 }
2145
+
2146
+ it "returns the correct documents and touches the database" do
2147
+ expect_query(1) do
2148
+ expect(docs).to eq([ depeche_mode, new_order, rolling_stones ])
2149
+ end
2150
+ end
2151
+ end
2152
+ end
2153
+
2154
+ context "when getting one document before" do
2155
+ let(:before_limit) { 1 }
2156
+
2157
+ context "when getting one document" do
2158
+ let(:limit) { 1 }
2159
+
2160
+ it "returns the correct documents without touching the database" do
2161
+ expect_no_queries do
2162
+ expect(docs).to eq([ depeche_mode ])
2163
+ end
2164
+ end
2165
+ end
2166
+
2167
+ context "when getting more than one document" do
2168
+ let(:limit) { 3 }
2169
+
2170
+ it "returns the correct documents and touches the database" do
2171
+ expect_query(1) do
2172
+ expect(docs).to eq([ depeche_mode, new_order, rolling_stones ])
2173
+ end
2174
+ end
2175
+ end
2176
+ end
2177
+ end
2178
+ end
2179
+ end
2180
+
2181
+ context "when calling #first then #last and the query cache is enabled" do
2182
+ query_cache_enabled
2183
+
2184
+ let(:context) do
2185
+ described_class.new(criteria)
2186
+ end
2187
+
2188
+ let(:criteria) do
2189
+ Band.all
2190
+ end
2191
+
2192
+ before do
2193
+ context.first(before_limit)
2194
+ end
2195
+
2196
+ let(:docs) do
2197
+ context.last(limit)
2198
+ end
2199
+
2200
+ context "when getting one from the beginning and one from the end" do
2201
+ let(:before_limit) { 2 }
2202
+ let(:limit) { 1 }
2203
+
2204
+ it "gets the correct document and hits the database" do
2205
+ expect_query(1) do
2206
+ expect(docs).to eq([rolling_stones])
2207
+ end
2208
+ end
2209
+ end
2210
+ end
2211
+ end
2212
+ end
2213
+
2214
+ describe "#last" do
2215
+ let!(:depeche_mode) do
2216
+ Band.create!(name: "Depeche Mode")
2217
+ end
2218
+
2219
+ let!(:new_order) do
2220
+ Band.create!(name: "New Order")
2221
+ end
2222
+
2223
+ let!(:rolling_stones) do
2224
+ Band.create!(name: "The Rolling Stones")
2225
+ end
2226
+
2227
+ context "when the context is not cached" do
2228
+
2229
+ let(:criteria) do
2230
+ Band.where(name: "Depeche Mode")
2231
+ end
2232
+
2233
+ let(:context) do
2234
+ described_class.new(criteria)
2235
+ end
2236
+
2237
+ it "returns the last matching document" do
2238
+ expect(context.last).to eq(depeche_mode)
2239
+ end
2240
+
2241
+ context 'when the criteria has a collation' do
2242
+ min_server_version '3.4'
2243
+
2244
+ let(:criteria) do
2245
+ Band.where(name: "DEPECHE MODE").collation(locale: 'en_US', strength: 2)
2246
+ end
2247
+
2248
+ it "returns the last matching document" do
2249
+ expect(context.last).to eq(depeche_mode)
2250
+ end
2251
+ end
2252
+ end
2253
+
2254
+ context "when using .desc" do
2255
+
2256
+ let(:criteria) do
2257
+ Band.desc(:name)
2258
+ end
2259
+
2260
+ let(:context) do
2261
+ described_class.new(criteria)
2262
+ end
2263
+
2264
+ context "when there is sort on the context" do
2265
+
2266
+ it "follows the main sort" do
2267
+ expect(context.last).to eq(depeche_mode)
2268
+ end
2269
+ end
2270
+
2271
+ context "when subsequently calling #first" do
2272
+
2273
+ it "returns the correct document" do
2274
+ expect(context.last).to eq(depeche_mode)
2275
+ expect(context.first).to eq(rolling_stones)
2276
+ end
2277
+ end
2278
+ end
2279
+
2280
+ context 'when the criteria has no sort' do
2281
+
2282
+ let(:criteria) do
2283
+ Band.all
2284
+ end
2285
+
2286
+ let(:context) do
2287
+ described_class.new(criteria)
2288
+ end
2289
+
2290
+ it 'applies a sort on _id' do
2291
+ expect(context.last).to eq(rolling_stones)
2292
+ end
2293
+
2294
+ context 'when calling #first' do
2295
+
2296
+ it 'returns the first document, sorted by _id' do
2297
+ expect(context.last).to eq(rolling_stones)
2298
+ expect(context.first).to eq(depeche_mode)
2299
+ end
2300
+ end
2301
+ end
2302
+
2303
+ context 'when the criteria has a sort' do
2304
+
2305
+ let(:criteria) do
2306
+ Band.desc(:name)
2307
+ end
2308
+
2309
+ let(:context) do
2310
+ described_class.new(criteria)
2311
+ end
2312
+
2313
+
2314
+ it 'applies the criteria sort' do
2315
+ expect(context.last).to eq(depeche_mode)
2316
+ end
2317
+
2318
+ context 'when calling #first' do
1474
2319
 
1475
- let(:criteria) do
1476
- Band.where(name: "Depeche Mode")
2320
+ it 'applies the criteria sort' do
2321
+ expect(context.last).to eq(depeche_mode)
2322
+ expect(context.first).to eq(rolling_stones)
1477
2323
  end
2324
+ end
2325
+ end
1478
2326
 
1479
- let(:context) do
1480
- described_class.new(criteria)
1481
- end
2327
+ context "when using .sort" do
1482
2328
 
1483
- it "returns the first matching document" do
1484
- expect(context.send(method)).to eq(depeche_mode)
1485
- end
2329
+ let(:criteria) do
2330
+ Band.all.sort(:name => -1).criteria
2331
+ end
1486
2332
 
1487
- context 'when the criteria has a collation' do
1488
- min_server_version '3.4'
2333
+ let(:context) do
2334
+ described_class.new(criteria)
2335
+ end
1489
2336
 
1490
- let(:criteria) do
1491
- Band.where(name: "DEPECHE MODE").collation(locale: 'en_US', strength: 2)
1492
- end
2337
+ context "when there is sort on the context" do
1493
2338
 
1494
- it "returns the first matching document" do
1495
- expect(context.send(method)).to eq(depeche_mode)
1496
- end
2339
+ it "follows the main sort" do
2340
+ expect(context.last).to eq(depeche_mode)
1497
2341
  end
1498
2342
  end
1499
2343
 
1500
- context "when using .desc" do
2344
+ context "when subsequently calling #first" do
1501
2345
 
1502
- let(:criteria) do
1503
- Band.desc(:name)
2346
+ it "returns the correct document" do
2347
+ expect(context.last).to eq(depeche_mode)
2348
+ expect(context.first).to eq(rolling_stones)
1504
2349
  end
2350
+ end
2351
+ end
1505
2352
 
1506
- let(:context) do
1507
- described_class.new(criteria)
1508
- end
2353
+ context "when the query cache is enabled" do
2354
+ query_cache_enabled
1509
2355
 
1510
- context "when there is sort on the context" do
2356
+ let(:criteria) do
2357
+ Band.where(name: "Depeche Mode")
2358
+ end
1511
2359
 
1512
- it "follows the main sort" do
1513
- expect(context.send(method)).to eq(new_order)
1514
- end
1515
- end
2360
+ let(:context) do
2361
+ described_class.new(criteria)
2362
+ end
1516
2363
 
1517
- context "when subsequently calling #last" do
2364
+ context "when last method was called before" do
1518
2365
 
1519
- it "returns the correct document" do
1520
- expect(context.send(method)).to eq(new_order)
2366
+ before do
2367
+ context.last
2368
+ end
2369
+
2370
+ it "returns the last document without touching the database" do
2371
+ expect_no_queries do
1521
2372
  expect(context.last).to eq(depeche_mode)
1522
2373
  end
1523
2374
  end
1524
2375
  end
2376
+ end
1525
2377
 
1526
- context 'when the criteria has no sort' do
2378
+ context "when including a limit" do
1527
2379
 
1528
- let(:criteria) do
1529
- Band.all
1530
- end
2380
+ context "when the context is not cached" do
1531
2381
 
1532
2382
  let(:context) do
1533
2383
  described_class.new(criteria)
1534
2384
  end
1535
2385
 
2386
+ context "when the limit is 1" do
2387
+ let(:criteria) do
2388
+ Band.criteria
2389
+ end
1536
2390
 
1537
- it 'applies a sort on _id' do
1538
- expect(context.send(method)).to eq(depeche_mode)
1539
- end
1540
-
1541
- context 'when calling #last' do
2391
+ let(:docs) do
2392
+ context.last(1)
2393
+ end
1542
2394
 
1543
- it 'returns the last document, sorted by _id' do
1544
- expect(context.send(method)).to eq(depeche_mode)
1545
- expect(context.last).to eq(new_order)
2395
+ it "returns an array of documents" do
2396
+ expect(docs).to eq([ rolling_stones ])
1546
2397
  end
1547
2398
  end
1548
2399
 
1549
- context 'with option { sort: :none }' do
2400
+ context "when the limit is >1" do
2401
+ let(:criteria) do
2402
+ Band.criteria
2403
+ end
1550
2404
 
1551
- let(:opts) do
1552
- { id_sort: :none }
2405
+ let(:docs) do
2406
+ context.last(2)
1553
2407
  end
1554
2408
 
1555
- it 'does not apply the sort on _id' do
1556
- expect(context.send(method, opts)).to eq(depeche_mode)
2409
+ it "returns the number of documents in order" do
2410
+ expect(docs).to eq([ new_order, rolling_stones ])
1557
2411
  end
2412
+ end
1558
2413
 
1559
- context 'when calling #last' do
2414
+ context 'when the criteria has a collation' do
2415
+ min_server_version '3.4'
1560
2416
 
1561
- it 'does not apply a sort on _id' do
1562
- expect(context.send(method, opts)).to eq(depeche_mode)
1563
- expect(context.last(opts)).to eq(depeche_mode)
1564
- end
2417
+ let(:criteria) do
2418
+ Band.where(name: "DEPECHE MODE").collation(locale: 'en_US', strength: 2)
2419
+ end
2420
+
2421
+ it "returns the first matching document" do
2422
+ expect(context.last(1)).to eq([ depeche_mode ])
1565
2423
  end
1566
2424
  end
1567
2425
  end
1568
2426
 
1569
- context 'when the criteria has a sort' do
1570
-
1571
- let(:criteria) do
1572
- Band.desc(:name)
1573
- end
2427
+ context "when the context is cached" do
1574
2428
 
1575
2429
  let(:context) do
1576
2430
  described_class.new(criteria)
1577
2431
  end
1578
2432
 
2433
+ context "when query cache is enabled" do
2434
+ query_cache_enabled
1579
2435
 
1580
- it 'applies the criteria sort' do
1581
- expect(context.send(method)).to eq(new_order)
1582
- end
1583
-
1584
- context 'when calling #last' do
1585
-
1586
- it 'applies the criteria sort' do
1587
- expect(context.send(method)).to eq(new_order)
1588
- expect(context.last).to eq(depeche_mode)
2436
+ let(:context) do
2437
+ described_class.new(criteria)
1589
2438
  end
1590
- end
1591
2439
 
1592
- context 'with option { sort: :none }' do
2440
+ let(:criteria) do
2441
+ Band.all
2442
+ end
1593
2443
 
1594
- let(:opts) do
1595
- { id_sort: :none }
2444
+ before do
2445
+ context.last(before_limit)
1596
2446
  end
1597
2447
 
1598
- it 'applies the criteria sort' do
1599
- expect(context.send(method, opts)).to eq(new_order)
2448
+ let(:docs) do
2449
+ context.last(limit)
1600
2450
  end
1601
2451
 
1602
- context 'when calling #last' do
2452
+ context "when getting all of the documents before" do
2453
+ let(:before_limit) { 3 }
1603
2454
 
1604
- it 'applies the criteria sort' do
1605
- expect(context.send(method, opts)).to eq(new_order)
1606
- expect(context.last(opts)).to eq(depeche_mode)
2455
+ context "when getting all of the documents" do
2456
+ let(:limit) { 3 }
2457
+
2458
+ it "returns all documents without touching the db" do
2459
+ expect_no_queries do
2460
+ expect(docs).to eq([ depeche_mode, new_order, rolling_stones ])
2461
+ end
2462
+ end
2463
+ end
2464
+
2465
+ context "when getting fewer documents" do
2466
+ let(:limit) { 2 }
2467
+
2468
+ it "returns the correct documents without touching the db" do
2469
+ expect_no_queries do
2470
+ expect(docs).to eq([ new_order, rolling_stones ])
2471
+ end
2472
+ end
1607
2473
  end
1608
2474
  end
1609
- end
1610
- end
1611
2475
 
1612
- context "when using .sort" do
2476
+ context "when getting fewer documents before" do
2477
+ let(:before_limit) { 2 }
1613
2478
 
1614
- let(:criteria) do
1615
- Band.all.sort(:name => -1).criteria
1616
- end
2479
+ context "when getting the same number of documents" do
2480
+ let(:limit) { 2 }
1617
2481
 
1618
- let(:context) do
1619
- described_class.new(criteria)
1620
- end
2482
+ it "returns the correct documents without touching the db" do
2483
+ expect_no_queries do
2484
+ expect(docs).to eq([ new_order, rolling_stones ])
2485
+ end
2486
+ end
2487
+ end
1621
2488
 
1622
- context "when there is sort on the context" do
2489
+ context "when getting more documents" do
2490
+ let(:limit) { 3 }
1623
2491
 
1624
- it "follows the main sort" do
1625
- expect(context.send(method)).to eq(new_order)
2492
+ it "returns the correct documents and touches the database" do
2493
+ expect_query(1) do
2494
+ expect(docs).to eq([ depeche_mode, new_order, rolling_stones ])
2495
+ end
2496
+ end
2497
+ end
1626
2498
  end
1627
- end
1628
2499
 
1629
- context "when subsequently calling #last" do
2500
+ context "when getting one document before" do
2501
+ let(:before_limit) { 1 }
1630
2502
 
1631
- it "returns the correct document" do
1632
- expect(context.send(method)).to eq(new_order)
1633
- expect(context.last).to eq(depeche_mode)
2503
+ context "when getting one document" do
2504
+ let(:limit) { 1 }
2505
+
2506
+ it "returns the correct documents without touching the database" do
2507
+ expect_no_queries do
2508
+ expect(docs).to eq([ rolling_stones ])
2509
+ end
2510
+ end
2511
+ end
2512
+
2513
+ context "when getting more than one document" do
2514
+ let(:limit) { 3 }
2515
+
2516
+ it "returns the correct documents and touches the database" do
2517
+ expect_query(1) do
2518
+ expect(docs).to eq([ depeche_mode, new_order, rolling_stones ])
2519
+ end
2520
+ end
2521
+ end
1634
2522
  end
1635
2523
  end
1636
2524
  end
2525
+ end
1637
2526
 
1638
- context "when the context is cached" do
1639
-
1640
- let(:criteria) do
1641
- Band.where(name: "Depeche Mode").cache
1642
- end
2527
+ context "when calling #last then #first and the query cache is enabled" do
2528
+ query_cache_enabled
1643
2529
 
1644
- let(:context) do
1645
- described_class.new(criteria)
1646
- end
2530
+ let(:context) do
2531
+ described_class.new(criteria)
2532
+ end
1647
2533
 
1648
- context "when the cache is loaded" do
2534
+ let(:criteria) do
2535
+ Band.all
2536
+ end
1649
2537
 
1650
- before do
1651
- context.to_a
1652
- end
2538
+ before do
2539
+ context.last(before_limit)
2540
+ end
1653
2541
 
1654
- it "returns the first document without touching the database" do
1655
- expect(context).to receive(:view).never
1656
- expect(context.send(method)).to eq(depeche_mode)
1657
- end
1658
- end
2542
+ let(:docs) do
2543
+ context.first(limit)
2544
+ end
1659
2545
 
1660
- context "when first method was called before" do
2546
+ context "when getting one from the beginning and one from the end" do
2547
+ let(:before_limit) { 2 }
2548
+ let(:limit) { 1 }
1661
2549
 
1662
- before do
1663
- context.first
2550
+ it "hits the database" do
2551
+ expect_query(1) do
2552
+ docs
1664
2553
  end
2554
+ end
1665
2555
 
1666
- it "returns the first document without touching the database" do
1667
- expect(context).to receive(:view).never
1668
- expect(context.send(method)).to eq(depeche_mode)
1669
- end
2556
+ it "gets the correct document" do
2557
+ expect(docs).to eq([ depeche_mode ])
1670
2558
  end
1671
2559
  end
1672
2560
  end
@@ -1718,37 +2606,28 @@ describe Mongoid::Contextual::Mongo do
1718
2606
  described_class.new(criteria)
1719
2607
  end
1720
2608
 
1721
- it "returns the number of documents that match" do
1722
- expect(context.send(method)).to eq(2)
1723
- end
2609
+ context "when broken_view_options is false" do
2610
+ driver_config_override :broken_view_options, false
1724
2611
 
1725
- context "when calling more than once" do
1726
- it "returns the cached value for subsequent calls" do
1727
- expect(context.view).to receive(:count_documents).once.and_return(2)
1728
- 2.times { expect(context.send(method)).to eq(2) }
2612
+ it "returns the number of documents that match" do
2613
+ expect(context.send(method)).to eq(1)
1729
2614
  end
1730
2615
  end
1731
2616
 
1732
- context "when the results have been iterated over" do
1733
-
1734
- before do
1735
- context.entries
1736
- end
2617
+ context "when broken_view_options is true" do
2618
+ driver_config_override :broken_view_options, true
1737
2619
 
1738
- it "returns the cached value for all calls" do
1739
- expect(context.view).to receive(:count_documents).once.and_return(2)
2620
+ it "returns the number of documents that match" do
1740
2621
  expect(context.send(method)).to eq(2)
1741
2622
  end
2623
+ end
1742
2624
 
1743
- context "when the results have been iterated over multiple times" do
1744
-
1745
- before do
1746
- context.entries
1747
- end
2625
+ context "when calling more than once with different limits" do
2626
+ driver_config_override :broken_view_options, false
1748
2627
 
1749
- it "resets the length on each full iteration" do
1750
- expect(context.size).to eq(2)
1751
- end
2628
+ it "does not cache the value" do
2629
+ expect(context.limit(1).send(method)).to eq(1)
2630
+ expect(context.limit(2).send(method)).to eq(2)
1752
2631
  end
1753
2632
  end
1754
2633
  end
@@ -1767,10 +2646,12 @@ describe Mongoid::Contextual::Mongo do
1767
2646
  expect(context.send(method)).to eq(1)
1768
2647
  end
1769
2648
 
1770
- context "when calling more than once" do
1771
- it "returns the cached value for subsequent calls" do
1772
- expect(context.view).to receive(:count_documents).once.and_return(1)
1773
- 2.times { expect(context.send(method)).to eq(1) }
2649
+ context "when calling more than once with different skips" do
2650
+ driver_config_override :broken_view_options, false
2651
+
2652
+ it "does not cache the value" do
2653
+ expect(context.skip(0).send(method)).to eq(1)
2654
+ expect(context.skip(1).send(method)).to eq(0)
1774
2655
  end
1775
2656
  end
1776
2657
 
@@ -1823,6 +2704,80 @@ describe Mongoid::Contextual::Mongo do
1823
2704
  end
1824
2705
  end
1825
2706
 
2707
+ describe "#take" do
2708
+
2709
+ let!(:depeche_mode) do
2710
+ Band.create!(name: "Depeche Mode")
2711
+ end
2712
+
2713
+ let!(:new_order) do
2714
+ Band.create!(name: "New Order")
2715
+ end
2716
+
2717
+ let!(:rolling_stones) do
2718
+ Band.create!(name: "The Rolling Stones")
2719
+ end
2720
+
2721
+ let(:criteria) do
2722
+ Band.all
2723
+ end
2724
+
2725
+ let(:context) do
2726
+ described_class.new(criteria)
2727
+ end
2728
+
2729
+ it "takes the correct number results" do
2730
+ expect(context.take(2)).to eq([ depeche_mode, new_order ])
2731
+ end
2732
+
2733
+ it "returns an array when passing 1" do
2734
+ expect(context.take(1)).to eq([ depeche_mode ])
2735
+ end
2736
+
2737
+ it "does not return an array when not passing an argument" do
2738
+ expect(context.take).to eq(depeche_mode)
2739
+ end
2740
+
2741
+ it "returns all the documents taking more than whats in the db" do
2742
+ expect(context.take(5)).to eq([ depeche_mode, new_order, rolling_stones ])
2743
+ end
2744
+ end
2745
+
2746
+ describe "#take!" do
2747
+
2748
+ let!(:depeche_mode) do
2749
+ Band.create!(name: "Depeche Mode")
2750
+ end
2751
+
2752
+ let!(:new_order) do
2753
+ Band.create!(name: "New Order")
2754
+ end
2755
+
2756
+ let!(:rolling_stones) do
2757
+ Band.create!(name: "The Rolling Stones")
2758
+ end
2759
+
2760
+ let(:criteria) do
2761
+ Band.all
2762
+ end
2763
+
2764
+ let(:context) do
2765
+ described_class.new(criteria)
2766
+ end
2767
+
2768
+ it "takes the first document" do
2769
+ expect(context.take!).to eq(depeche_mode)
2770
+ end
2771
+
2772
+ context "when there are no documents" do
2773
+ it "raises an error" do
2774
+ expect do
2775
+ Person.take!
2776
+ end.to raise_error(Mongoid::Errors::DocumentNotFound, /Could not find a document of class Person./)
2777
+ end
2778
+ end
2779
+ end
2780
+
1826
2781
  describe "#map" do
1827
2782
 
1828
2783
  before do
@@ -1840,8 +2795,10 @@ describe Mongoid::Contextual::Mongo do
1840
2795
 
1841
2796
  context "when passed the symbol field name" do
1842
2797
 
1843
- it "performs mapping" do
1844
- expect(context.map(:name)).to eq ["Depeche Mode", "New Order"]
2798
+ it "raises an error" do
2799
+ expect do
2800
+ context.map(:name)
2801
+ end.to raise_error(ArgumentError)
1845
2802
  end
1846
2803
  end
1847
2804
 
@@ -2616,16 +3573,65 @@ describe Mongoid::Contextual::Mongo do
2616
3573
 
2617
3574
  context "when the attributes are in the correct type" do
2618
3575
 
3576
+ context "when operation is $set" do
3577
+
3578
+ before do
3579
+ context.update_all("$set" => { name: "Smiths" })
3580
+ end
3581
+
3582
+ it "updates the first matching document" do
3583
+ expect(depeche_mode.reload.name).to eq("Smiths")
3584
+ end
3585
+
3586
+ it "updates the last matching document" do
3587
+ expect(new_order.reload.name).to eq("Smiths")
3588
+ end
3589
+ end
3590
+
3591
+ context "when operation is $push" do
3592
+
3593
+ before do
3594
+ depeche_mode.update_attribute(:genres, ["electronic"])
3595
+ new_order.update_attribute(:genres, ["electronic"])
3596
+ context.update_all("$push" => { genres: "pop" })
3597
+ end
3598
+
3599
+ it "updates the first matching document" do
3600
+ expect(depeche_mode.reload.genres).to eq(["electronic", "pop"])
3601
+ end
3602
+
3603
+ it "updates the last matching document" do
3604
+ expect(new_order.reload.genres).to eq(["electronic", "pop"])
3605
+ end
3606
+ end
3607
+
3608
+ context "when operation is $addToSet" do
3609
+
3610
+ before do
3611
+ context.update_all("$addToSet" => { genres: "electronic" })
3612
+ end
3613
+
3614
+ it "updates the first matching document" do
3615
+ expect(depeche_mode.reload.genres).to eq(["electronic"])
3616
+ end
3617
+
3618
+ it "updates the last matching document" do
3619
+ expect(new_order.reload.genres).to eq(["electronic"])
3620
+ end
3621
+ end
3622
+ end
3623
+
3624
+ context 'when using aliased field names' do
2619
3625
  before do
2620
- context.update_all("$set" => { name: "Smiths" })
3626
+ context.update_all('$set' => { years: 100 })
2621
3627
  end
2622
3628
 
2623
3629
  it "updates the first matching document" do
2624
- expect(depeche_mode.reload.name).to eq("Smiths")
3630
+ expect(depeche_mode.reload.years).to eq(100)
2625
3631
  end
2626
3632
 
2627
3633
  it "updates the last matching document" do
2628
- expect(new_order.reload.name).to eq("Smiths")
3634
+ expect(new_order.reload.years).to eq(100)
2629
3635
  end
2630
3636
  end
2631
3637