mongoid 7.5.4 → 8.1.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 (442) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +3 -3
  3. data/README.md +6 -6
  4. data/Rakefile +44 -46
  5. data/lib/config/locales/en.yml +92 -43
  6. data/lib/mongoid/association/accessors.rb +44 -11
  7. data/lib/mongoid/association/bindable.rb +50 -2
  8. data/lib/mongoid/association/builders.rb +5 -3
  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 +34 -11
  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/buildable.rb +2 -2
  15. data/lib/mongoid/association/embedded/embedded_in/proxy.rb +4 -3
  16. data/lib/mongoid/association/embedded/embedded_in.rb +3 -2
  17. data/lib/mongoid/association/embedded/embeds_many/binding.rb +1 -0
  18. data/lib/mongoid/association/embedded/embeds_many/buildable.rb +4 -3
  19. data/lib/mongoid/association/embedded/embeds_many/proxy.rb +85 -46
  20. data/lib/mongoid/association/embedded/embeds_many.rb +2 -2
  21. data/lib/mongoid/association/embedded/embeds_one/buildable.rb +19 -5
  22. data/lib/mongoid/association/embedded/embeds_one/proxy.rb +24 -5
  23. data/lib/mongoid/association/embedded/embeds_one.rb +3 -3
  24. data/lib/mongoid/association/macros.rb +8 -1
  25. data/lib/mongoid/association/many.rb +11 -7
  26. data/lib/mongoid/association/nested/many.rb +5 -4
  27. data/lib/mongoid/association/nested/nested_buildable.rb +4 -4
  28. data/lib/mongoid/association/nested/one.rb +45 -7
  29. data/lib/mongoid/association/one.rb +2 -2
  30. data/lib/mongoid/association/options.rb +9 -9
  31. data/lib/mongoid/association/proxy.rb +15 -4
  32. data/lib/mongoid/association/referenced/auto_save.rb +4 -3
  33. data/lib/mongoid/association/referenced/belongs_to/binding.rb +1 -0
  34. data/lib/mongoid/association/referenced/belongs_to/buildable.rb +1 -1
  35. data/lib/mongoid/association/referenced/belongs_to/proxy.rb +5 -6
  36. data/lib/mongoid/association/referenced/belongs_to.rb +2 -2
  37. data/lib/mongoid/association/referenced/counter_cache.rb +10 -10
  38. data/lib/mongoid/association/referenced/eager.rb +2 -2
  39. data/lib/mongoid/association/referenced/has_and_belongs_to_many/proxy.rb +70 -13
  40. data/lib/mongoid/association/referenced/has_and_belongs_to_many.rb +6 -3
  41. data/lib/mongoid/association/referenced/has_many/enumerable.rb +22 -30
  42. data/lib/mongoid/association/referenced/has_many/proxy.rb +40 -21
  43. data/lib/mongoid/association/referenced/has_many.rb +3 -3
  44. data/lib/mongoid/association/referenced/has_one/buildable.rb +1 -1
  45. data/lib/mongoid/association/referenced/has_one/nested_builder.rb +5 -5
  46. data/lib/mongoid/association/referenced/has_one/proxy.rb +9 -12
  47. data/lib/mongoid/association/referenced/has_one.rb +3 -3
  48. data/lib/mongoid/association/referenced/syncable.rb +4 -4
  49. data/lib/mongoid/association/reflections.rb +4 -4
  50. data/lib/mongoid/association/relatable.rb +44 -10
  51. data/lib/mongoid/association.rb +5 -5
  52. data/lib/mongoid/atomic/modifiers.rb +2 -2
  53. data/lib/mongoid/atomic.rb +16 -7
  54. data/lib/mongoid/attributes/dynamic.rb +4 -4
  55. data/lib/mongoid/attributes/nested.rb +6 -6
  56. data/lib/mongoid/attributes/processing.rb +37 -6
  57. data/lib/mongoid/attributes/projector.rb +2 -2
  58. data/lib/mongoid/attributes/readonly.rb +3 -3
  59. data/lib/mongoid/attributes.rb +51 -42
  60. data/lib/mongoid/changeable.rb +147 -14
  61. data/lib/mongoid/clients/options.rb +5 -1
  62. data/lib/mongoid/clients/sessions.rb +2 -14
  63. data/lib/mongoid/clients/storage_options.rb +2 -5
  64. data/lib/mongoid/clients/validators/storage.rb +3 -15
  65. data/lib/mongoid/collection_configurable.rb +58 -0
  66. data/lib/mongoid/composable.rb +2 -0
  67. data/lib/mongoid/config/defaults.rb +60 -0
  68. data/lib/mongoid/config/options.rb +3 -0
  69. data/lib/mongoid/config/validators/async_query_executor.rb +24 -0
  70. data/lib/mongoid/config/validators/client.rb +6 -6
  71. data/lib/mongoid/config/validators.rb +1 -0
  72. data/lib/mongoid/config.rb +153 -18
  73. data/lib/mongoid/contextual/aggregable/memory.rb +24 -16
  74. data/lib/mongoid/contextual/aggregable/mongo.rb +5 -5
  75. data/lib/mongoid/contextual/aggregable/none.rb +1 -1
  76. data/lib/mongoid/contextual/atomic.rb +1 -1
  77. data/lib/mongoid/contextual/geo_near.rb +7 -7
  78. data/lib/mongoid/contextual/map_reduce.rb +2 -2
  79. data/lib/mongoid/contextual/memory.rb +285 -58
  80. data/lib/mongoid/contextual/mongo/documents_loader.rb +177 -0
  81. data/lib/mongoid/contextual/mongo.rb +540 -346
  82. data/lib/mongoid/contextual/none.rb +193 -20
  83. data/lib/mongoid/contextual/queryable.rb +1 -1
  84. data/lib/mongoid/contextual.rb +14 -2
  85. data/lib/mongoid/copyable.rb +32 -8
  86. data/lib/mongoid/criteria/findable.rb +8 -5
  87. data/lib/mongoid/criteria/includable.rb +27 -22
  88. data/lib/mongoid/criteria/marshalable.rb +10 -2
  89. data/lib/mongoid/criteria/permission.rb +1 -1
  90. data/lib/mongoid/criteria/queryable/aggregable.rb +2 -2
  91. data/lib/mongoid/criteria/queryable/extensions/array.rb +3 -16
  92. data/lib/mongoid/criteria/queryable/extensions/big_decimal.rb +25 -4
  93. data/lib/mongoid/criteria/queryable/extensions/boolean.rb +2 -2
  94. data/lib/mongoid/criteria/queryable/extensions/date.rb +6 -1
  95. data/lib/mongoid/criteria/queryable/extensions/date_time.rb +6 -1
  96. data/lib/mongoid/criteria/queryable/extensions/hash.rb +1 -17
  97. data/lib/mongoid/criteria/queryable/extensions/numeric.rb +15 -9
  98. data/lib/mongoid/criteria/queryable/extensions/object.rb +2 -1
  99. data/lib/mongoid/criteria/queryable/extensions/range.rb +13 -5
  100. data/lib/mongoid/criteria/queryable/extensions/regexp.rb +3 -3
  101. data/lib/mongoid/criteria/queryable/extensions/set.rb +1 -1
  102. data/lib/mongoid/criteria/queryable/extensions/string.rb +4 -14
  103. data/lib/mongoid/criteria/queryable/extensions/symbol.rb +4 -12
  104. data/lib/mongoid/criteria/queryable/extensions/time.rb +6 -1
  105. data/lib/mongoid/criteria/queryable/extensions/time_with_zone.rb +6 -1
  106. data/lib/mongoid/criteria/queryable/key.rb +4 -4
  107. data/lib/mongoid/criteria/queryable/mergeable.rb +1 -1
  108. data/lib/mongoid/criteria/queryable/optional.rb +11 -17
  109. data/lib/mongoid/criteria/queryable/options.rb +2 -2
  110. data/lib/mongoid/criteria/queryable/pipeline.rb +1 -1
  111. data/lib/mongoid/criteria/queryable/selectable.rb +47 -38
  112. data/lib/mongoid/criteria/queryable/selector.rb +92 -7
  113. data/lib/mongoid/criteria/queryable/smash.rb +40 -7
  114. data/lib/mongoid/criteria/queryable.rb +12 -7
  115. data/lib/mongoid/criteria/scopable.rb +2 -2
  116. data/lib/mongoid/criteria/translator.rb +45 -0
  117. data/lib/mongoid/criteria.rb +20 -40
  118. data/lib/mongoid/deprecable.rb +37 -0
  119. data/lib/mongoid/deprecation.rb +25 -0
  120. data/lib/mongoid/document.rb +127 -35
  121. data/lib/mongoid/equality.rb +8 -8
  122. data/lib/mongoid/errors/create_collection_failure.rb +33 -0
  123. data/lib/mongoid/errors/document_not_found.rb +10 -6
  124. data/lib/mongoid/errors/drop_collection_failure.rb +27 -0
  125. data/lib/mongoid/errors/immutable_attribute.rb +26 -0
  126. data/lib/mongoid/errors/invalid_async_query_executor.rb +25 -0
  127. data/lib/mongoid/errors/invalid_config_option.rb +1 -1
  128. data/lib/mongoid/errors/invalid_dependent_strategy.rb +1 -1
  129. data/lib/mongoid/errors/invalid_dot_dollar_assignment.rb +23 -0
  130. data/lib/mongoid/errors/invalid_field.rb +6 -2
  131. data/lib/mongoid/errors/invalid_field_type.rb +26 -0
  132. data/lib/mongoid/errors/invalid_global_executor_concurrency.rb +22 -0
  133. data/lib/mongoid/errors/invalid_relation.rb +1 -1
  134. data/lib/mongoid/errors/invalid_relation_option.rb +1 -1
  135. data/lib/mongoid/errors/invalid_session_use.rb +1 -1
  136. data/lib/mongoid/errors/invalid_storage_options.rb +1 -1
  137. data/lib/mongoid/errors/invalid_storage_parent.rb +2 -0
  138. data/lib/mongoid/errors/mongoid_error.rb +3 -3
  139. data/lib/mongoid/errors/nested_attributes_metadata_not_found.rb +1 -1
  140. data/lib/mongoid/errors/no_client_database.rb +1 -1
  141. data/lib/mongoid/errors/no_client_hosts.rb +1 -1
  142. data/lib/mongoid/errors/readonly_attribute.rb +1 -1
  143. data/lib/mongoid/errors/too_many_nested_attribute_records.rb +1 -1
  144. data/lib/mongoid/errors/unknown_attribute.rb +1 -1
  145. data/lib/mongoid/errors.rb +6 -3
  146. data/lib/mongoid/extensions/array.rb +9 -7
  147. data/lib/mongoid/extensions/big_decimal.rb +33 -10
  148. data/lib/mongoid/extensions/binary.rb +42 -0
  149. data/lib/mongoid/extensions/boolean.rb +8 -2
  150. data/lib/mongoid/extensions/date.rb +26 -20
  151. data/lib/mongoid/extensions/date_time.rb +1 -1
  152. data/lib/mongoid/extensions/false_class.rb +1 -1
  153. data/lib/mongoid/extensions/float.rb +7 -4
  154. data/lib/mongoid/extensions/hash.rb +38 -9
  155. data/lib/mongoid/extensions/integer.rb +7 -4
  156. data/lib/mongoid/extensions/module.rb +1 -1
  157. data/lib/mongoid/extensions/object.rb +10 -8
  158. data/lib/mongoid/extensions/range.rb +41 -10
  159. data/lib/mongoid/extensions/regexp.rb +11 -4
  160. data/lib/mongoid/extensions/set.rb +11 -4
  161. data/lib/mongoid/extensions/string.rb +11 -22
  162. data/lib/mongoid/extensions/symbol.rb +4 -15
  163. data/lib/mongoid/extensions/time.rb +29 -16
  164. data/lib/mongoid/extensions/time_with_zone.rb +1 -2
  165. data/lib/mongoid/extensions/true_class.rb +1 -1
  166. data/lib/mongoid/extensions.rb +1 -0
  167. data/lib/mongoid/factory.rb +55 -7
  168. data/lib/mongoid/fields/foreign_key.rb +11 -4
  169. data/lib/mongoid/fields/localized.rb +19 -4
  170. data/lib/mongoid/fields/standard.rb +17 -7
  171. data/lib/mongoid/fields/validators/macro.rb +3 -9
  172. data/lib/mongoid/fields.rb +142 -28
  173. data/lib/mongoid/findable.rb +54 -24
  174. data/lib/mongoid/indexable/specification.rb +2 -2
  175. data/lib/mongoid/indexable/validators/options.rb +6 -2
  176. data/lib/mongoid/interceptable.rb +186 -16
  177. data/lib/mongoid/matchable.rb +1 -1
  178. data/lib/mongoid/matcher/eq_impl.rb +1 -1
  179. data/lib/mongoid/matcher/type.rb +1 -1
  180. data/lib/mongoid/matcher.rb +48 -14
  181. data/lib/mongoid/persistable/creatable.rb +19 -9
  182. data/lib/mongoid/persistable/deletable.rb +2 -2
  183. data/lib/mongoid/persistable/destroyable.rb +1 -1
  184. data/lib/mongoid/persistable/savable.rb +14 -2
  185. data/lib/mongoid/persistable/unsettable.rb +2 -2
  186. data/lib/mongoid/persistable/updatable.rb +69 -12
  187. data/lib/mongoid/persistable/upsertable.rb +21 -2
  188. data/lib/mongoid/persistable.rb +6 -3
  189. data/lib/mongoid/persistence_context.rb +6 -4
  190. data/lib/mongoid/query_cache.rb +13 -261
  191. data/lib/mongoid/railties/controller_runtime.rb +1 -1
  192. data/lib/mongoid/railties/database.rake +7 -2
  193. data/lib/mongoid/reloadable.rb +10 -8
  194. data/lib/mongoid/scopable.rb +15 -13
  195. data/lib/mongoid/selectable.rb +1 -2
  196. data/lib/mongoid/serializable.rb +17 -13
  197. data/lib/mongoid/stateful.rb +57 -10
  198. data/lib/mongoid/tasks/database.rake +12 -0
  199. data/lib/mongoid/tasks/database.rb +20 -2
  200. data/lib/mongoid/threaded/lifecycle.rb +5 -5
  201. data/lib/mongoid/threaded.rb +42 -12
  202. data/lib/mongoid/timestamps/created.rb +1 -1
  203. data/lib/mongoid/timestamps/updated.rb +2 -2
  204. data/lib/mongoid/touchable.rb +3 -4
  205. data/lib/mongoid/traversable.rb +10 -5
  206. data/lib/mongoid/utils.rb +22 -0
  207. data/lib/mongoid/validatable/associated.rb +98 -17
  208. data/lib/mongoid/validatable/localizable.rb +1 -1
  209. data/lib/mongoid/validatable/macros.rb +5 -7
  210. data/lib/mongoid/validatable/presence.rb +2 -2
  211. data/lib/mongoid/validatable/uniqueness.rb +9 -8
  212. data/lib/mongoid/validatable.rb +17 -6
  213. data/lib/mongoid/version.rb +1 -1
  214. data/lib/mongoid/warnings.rb +19 -4
  215. data/lib/mongoid.rb +17 -3
  216. data/spec/config/mongoid.yml +16 -0
  217. data/spec/integration/app_spec.rb +24 -19
  218. data/spec/integration/associations/belongs_to_spec.rb +18 -0
  219. data/spec/integration/associations/embedded_spec.rb +15 -0
  220. data/spec/integration/associations/embeds_many_spec.rb +15 -2
  221. data/spec/integration/associations/embeds_one_spec.rb +18 -0
  222. data/spec/integration/associations/foreign_key_spec.rb +9 -0
  223. data/spec/integration/associations/has_and_belongs_to_many_spec.rb +61 -0
  224. data/spec/integration/associations/has_one_spec.rb +97 -1
  225. data/spec/integration/associations/scope_option_spec.rb +1 -1
  226. data/spec/integration/callbacks_models.rb +132 -1
  227. data/spec/integration/callbacks_spec.rb +381 -4
  228. data/spec/integration/criteria/range_spec.rb +95 -1
  229. data/spec/integration/discriminator_key_spec.rb +118 -80
  230. data/spec/integration/dots_and_dollars_spec.rb +277 -0
  231. data/spec/integration/i18n_fallbacks_spec.rb +3 -32
  232. data/spec/integration/matcher_examples_spec.rb +20 -13
  233. data/spec/integration/matcher_operator_data/type_decimal.yml +3 -2
  234. data/spec/integration/matcher_operator_spec.rb +3 -5
  235. data/spec/integration/persistence/range_field_spec.rb +350 -0
  236. data/spec/mongoid/association/counter_cache_spec.rb +1 -1
  237. data/spec/mongoid/association/depending_spec.rb +9 -9
  238. data/spec/mongoid/association/eager_spec.rb +2 -1
  239. data/spec/mongoid/association/embedded/embedded_in/binding_spec.rb +2 -1
  240. data/spec/mongoid/association/embedded/embedded_in/buildable_spec.rb +54 -0
  241. data/spec/mongoid/association/embedded/embedded_in/proxy_spec.rb +96 -9
  242. data/spec/mongoid/association/embedded/embeds_many/buildable_spec.rb +112 -0
  243. data/spec/mongoid/association/embedded/embeds_many/proxy_spec.rb +290 -65
  244. data/spec/mongoid/association/embedded/embeds_many_models.rb +37 -0
  245. data/spec/mongoid/association/embedded/embeds_many_query_spec.rb +16 -0
  246. data/spec/mongoid/association/embedded/embeds_many_spec.rb +68 -0
  247. data/spec/mongoid/association/embedded/embeds_one/buildable_spec.rb +25 -0
  248. data/spec/mongoid/association/embedded/embeds_one/proxy_spec.rb +15 -2
  249. data/spec/mongoid/association/embedded/embeds_one_models.rb +19 -0
  250. data/spec/mongoid/association/embedded/embeds_one_spec.rb +28 -0
  251. data/spec/mongoid/association/referenced/belongs_to/binding_spec.rb +2 -1
  252. data/spec/mongoid/association/referenced/belongs_to/buildable_spec.rb +54 -0
  253. data/spec/mongoid/association/referenced/belongs_to/proxy_spec.rb +19 -0
  254. data/spec/mongoid/association/referenced/belongs_to_models.rb +11 -0
  255. data/spec/mongoid/association/referenced/belongs_to_spec.rb +4 -20
  256. data/spec/mongoid/association/referenced/has_and_belongs_to_many/proxy_spec.rb +186 -229
  257. data/spec/mongoid/association/referenced/has_and_belongs_to_many_models.rb +25 -0
  258. data/spec/mongoid/association/referenced/has_and_belongs_to_many_spec.rb +35 -2
  259. data/spec/mongoid/association/referenced/has_many/buildable_spec.rb +109 -0
  260. data/spec/mongoid/association/referenced/has_many/enumerable_spec.rb +2 -56
  261. data/spec/mongoid/association/referenced/has_many/proxy_spec.rb +215 -177
  262. data/spec/mongoid/association/referenced/has_many_models.rb +3 -1
  263. data/spec/mongoid/association/referenced/has_many_spec.rb +25 -0
  264. data/spec/mongoid/association/referenced/has_one/buildable_spec.rb +2 -2
  265. data/spec/mongoid/association/referenced/has_one/proxy_spec.rb +107 -1
  266. data/spec/mongoid/association/referenced/has_one_models.rb +16 -0
  267. data/spec/mongoid/association/syncable_spec.rb +15 -1
  268. data/spec/mongoid/atomic/paths_spec.rb +0 -14
  269. data/spec/mongoid/attributes/nested_spec.rb +80 -11
  270. data/spec/mongoid/attributes/nested_spec_models.rb +48 -0
  271. data/spec/mongoid/attributes/projector_spec.rb +1 -5
  272. data/spec/mongoid/attributes_spec.rb +526 -33
  273. data/spec/mongoid/changeable_spec.rb +429 -37
  274. data/spec/mongoid/clients/factory_spec.rb +23 -30
  275. data/spec/mongoid/clients/sessions_spec.rb +0 -38
  276. data/spec/mongoid/clients_spec.rb +149 -15
  277. data/spec/mongoid/collection_configurable_spec.rb +158 -0
  278. data/spec/mongoid/config/defaults_spec.rb +160 -0
  279. data/spec/mongoid/config_spec.rb +214 -31
  280. data/spec/mongoid/contextual/aggregable/memory_spec.rb +396 -158
  281. data/spec/mongoid/contextual/aggregable/memory_table.yml +88 -0
  282. data/spec/mongoid/contextual/aggregable/memory_table_spec.rb +62 -0
  283. data/spec/mongoid/contextual/map_reduce_spec.rb +2 -16
  284. data/spec/mongoid/contextual/memory_spec.rb +850 -88
  285. data/spec/mongoid/contextual/mongo/documents_loader_spec.rb +187 -0
  286. data/spec/mongoid/contextual/mongo_spec.rb +2256 -1005
  287. data/spec/mongoid/contextual/none_spec.rb +60 -21
  288. data/spec/mongoid/copyable_spec.rb +453 -11
  289. data/spec/mongoid/criteria/findable_spec.rb +86 -210
  290. data/spec/mongoid/criteria/includable_spec.rb +1492 -0
  291. data/spec/mongoid/criteria/includable_spec_models.rb +54 -0
  292. data/spec/mongoid/criteria/marshalable_spec.rb +18 -1
  293. data/spec/mongoid/criteria/queryable/extensions/array_spec.rb +7 -19
  294. data/spec/mongoid/criteria/queryable/extensions/big_decimal_spec.rb +134 -26
  295. data/spec/mongoid/criteria/queryable/extensions/date_spec.rb +11 -0
  296. data/spec/mongoid/criteria/queryable/extensions/date_time_spec.rb +11 -0
  297. data/spec/mongoid/criteria/queryable/extensions/hash_spec.rb +0 -15
  298. data/spec/mongoid/criteria/queryable/extensions/numeric_spec.rb +73 -7
  299. data/spec/mongoid/criteria/queryable/extensions/string_spec.rb +4 -69
  300. data/spec/mongoid/criteria/queryable/extensions/symbol_spec.rb +0 -59
  301. data/spec/mongoid/criteria/queryable/extensions/time_spec.rb +11 -0
  302. data/spec/mongoid/criteria/queryable/extensions/time_with_zone_spec.rb +11 -0
  303. data/spec/mongoid/criteria/queryable/optional_spec.rb +15 -484
  304. data/spec/mongoid/criteria/queryable/options_spec.rb +1 -1
  305. data/spec/mongoid/criteria/queryable/selectable_logical_spec.rb +469 -0
  306. data/spec/mongoid/criteria/queryable/selectable_spec.rb +78 -86
  307. data/spec/mongoid/criteria/queryable/selector_spec.rb +15 -3
  308. data/spec/mongoid/criteria/translator_spec.rb +132 -0
  309. data/spec/mongoid/criteria_projection_spec.rb +1 -5
  310. data/spec/mongoid/criteria_spec.rb +469 -1205
  311. data/spec/mongoid/document_fields_spec.rb +173 -24
  312. data/spec/mongoid/document_spec.rb +32 -41
  313. data/spec/mongoid/errors/document_not_found_spec.rb +29 -2
  314. data/spec/mongoid/errors/invalid_field_spec.rb +1 -1
  315. data/spec/mongoid/errors/invalid_field_type_spec.rb +55 -0
  316. data/spec/mongoid/errors/mongoid_error_spec.rb +3 -1
  317. data/spec/mongoid/errors/no_environment_spec.rb +3 -3
  318. data/spec/mongoid/errors/readonly_document_spec.rb +2 -2
  319. data/spec/mongoid/errors/too_many_nested_attribute_records_spec.rb +1 -1
  320. data/spec/mongoid/extensions/array_spec.rb +16 -2
  321. data/spec/mongoid/extensions/big_decimal_spec.rb +712 -212
  322. data/spec/mongoid/extensions/binary_spec.rb +44 -9
  323. data/spec/mongoid/extensions/boolean_spec.rb +68 -82
  324. data/spec/mongoid/extensions/date_class_mongoize_spec.rb +7 -3
  325. data/spec/mongoid/extensions/date_spec.rb +71 -1
  326. data/spec/mongoid/extensions/date_time_spec.rb +15 -9
  327. data/spec/mongoid/extensions/float_spec.rb +53 -74
  328. data/spec/mongoid/extensions/hash_spec.rb +33 -3
  329. data/spec/mongoid/extensions/integer_spec.rb +50 -64
  330. data/spec/mongoid/extensions/range_spec.rb +255 -54
  331. data/spec/mongoid/extensions/regexp_spec.rb +58 -33
  332. data/spec/mongoid/extensions/set_spec.rb +106 -0
  333. data/spec/mongoid/extensions/string_spec.rb +53 -25
  334. data/spec/mongoid/extensions/symbol_spec.rb +18 -25
  335. data/spec/mongoid/extensions/time_spec.rb +639 -106
  336. data/spec/mongoid/extensions/time_with_zone_spec.rb +24 -83
  337. data/spec/mongoid/factory_spec.rb +61 -1
  338. data/spec/mongoid/fields/localized_spec.rb +80 -37
  339. data/spec/mongoid/fields_spec.rb +503 -87
  340. data/spec/mongoid/findable_spec.rb +450 -58
  341. data/spec/mongoid/indexable/specification_spec.rb +2 -2
  342. data/spec/mongoid/indexable_spec.rb +55 -30
  343. data/spec/mongoid/interceptable_spec.rb +824 -22
  344. data/spec/mongoid/interceptable_spec_models.rb +235 -4
  345. data/spec/mongoid/matcher/extract_attribute_spec.rb +1 -5
  346. data/spec/mongoid/mongoizable_spec.rb +285 -0
  347. data/spec/mongoid/persistable/creatable_spec.rb +2 -2
  348. data/spec/mongoid/persistable/deletable_spec.rb +28 -8
  349. data/spec/mongoid/persistable/destroyable_spec.rb +28 -8
  350. data/spec/mongoid/persistable/incrementable_spec.rb +37 -0
  351. data/spec/mongoid/persistable/logical_spec.rb +37 -0
  352. data/spec/mongoid/persistable/poppable_spec.rb +36 -0
  353. data/spec/mongoid/persistable/pullable_spec.rb +72 -0
  354. data/spec/mongoid/persistable/pushable_spec.rb +72 -0
  355. data/spec/mongoid/persistable/renamable_spec.rb +36 -0
  356. data/spec/mongoid/persistable/savable_spec.rb +96 -0
  357. data/spec/mongoid/persistable/settable_spec.rb +37 -0
  358. data/spec/mongoid/persistable/unsettable_spec.rb +36 -0
  359. data/spec/mongoid/persistable/updatable_spec.rb +20 -28
  360. data/spec/mongoid/persistable/upsertable_spec.rb +89 -1
  361. data/spec/mongoid/persistence_context_spec.rb +31 -57
  362. data/spec/mongoid/query_cache_middleware_spec.rb +0 -18
  363. data/spec/mongoid/query_cache_spec.rb +56 -215
  364. data/spec/mongoid/reloadable_spec.rb +83 -6
  365. data/spec/mongoid/scopable_spec.rb +91 -1
  366. data/spec/mongoid/serializable_spec.rb +25 -39
  367. data/spec/mongoid/shardable_spec.rb +4 -4
  368. data/spec/mongoid/stateful_spec.rb +150 -8
  369. data/spec/mongoid/tasks/database_rake_spec.rb +74 -0
  370. data/spec/mongoid/tasks/database_spec.rb +127 -0
  371. data/spec/mongoid/timestamps_spec.rb +392 -4
  372. data/spec/mongoid/timestamps_spec_models.rb +67 -0
  373. data/spec/mongoid/touchable_spec.rb +390 -2
  374. data/spec/mongoid/touchable_spec_models.rb +14 -8
  375. data/spec/mongoid/traversable_spec.rb +13 -35
  376. data/spec/mongoid/validatable/associated_spec.rb +27 -34
  377. data/spec/mongoid/validatable/presence_spec.rb +1 -1
  378. data/spec/mongoid/validatable/uniqueness_spec.rb +58 -31
  379. data/spec/mongoid/warnings_spec.rb +35 -0
  380. data/spec/mongoid_spec.rb +34 -16
  381. data/spec/rails/controller_extension/controller_runtime_spec.rb +2 -2
  382. data/spec/rails/mongoid_spec.rb +4 -16
  383. data/spec/spec_helper.rb +5 -0
  384. data/spec/support/constraints.rb +24 -0
  385. data/spec/support/immutable_ids.rb +118 -0
  386. data/spec/support/macros.rb +78 -0
  387. data/spec/support/models/artist.rb +0 -1
  388. data/spec/support/models/augmentation.rb +12 -0
  389. data/spec/support/models/band.rb +5 -0
  390. data/spec/support/models/book.rb +1 -0
  391. data/spec/support/models/building.rb +2 -0
  392. data/spec/support/models/catalog.rb +24 -0
  393. data/spec/support/models/circus.rb +3 -0
  394. data/spec/support/models/cover.rb +10 -0
  395. data/spec/support/models/fanatic.rb +8 -0
  396. data/spec/support/models/implant.rb +9 -0
  397. data/spec/support/models/label.rb +2 -0
  398. data/spec/support/models/lat_lng.rb +6 -0
  399. data/spec/support/models/name.rb +10 -0
  400. data/spec/support/models/passport.rb +9 -0
  401. data/spec/support/models/person.rb +2 -0
  402. data/spec/support/models/player.rb +2 -0
  403. data/spec/support/models/powerup.rb +12 -0
  404. data/spec/support/models/product.rb +1 -0
  405. data/spec/support/models/purse.rb +9 -0
  406. data/spec/support/models/registry.rb +1 -0
  407. data/spec/support/models/school.rb +14 -0
  408. data/spec/support/models/shield.rb +18 -0
  409. data/spec/support/models/student.rb +14 -0
  410. data/spec/support/models/weapon.rb +12 -0
  411. metadata +101 -96
  412. checksums.yaml.gz.sig +0 -0
  413. data/lib/mongoid/errors/eager_load.rb +0 -23
  414. data/lib/mongoid/errors/invalid_value.rb +0 -17
  415. data/spec/mongoid/criteria/queryable/extensions/bignum_spec.rb +0 -60
  416. data/spec/mongoid/criteria/queryable/extensions/fixnum_spec.rb +0 -60
  417. data/spec/mongoid/errors/eager_load_spec.rb +0 -31
  418. data/spec/shared/LICENSE +0 -20
  419. data/spec/shared/bin/get-mongodb-download-url +0 -17
  420. data/spec/shared/bin/s3-copy +0 -45
  421. data/spec/shared/bin/s3-upload +0 -69
  422. data/spec/shared/lib/mrss/child_process_helper.rb +0 -80
  423. data/spec/shared/lib/mrss/cluster_config.rb +0 -231
  424. data/spec/shared/lib/mrss/constraints.rb +0 -378
  425. data/spec/shared/lib/mrss/docker_runner.rb +0 -291
  426. data/spec/shared/lib/mrss/eg_config_utils.rb +0 -51
  427. data/spec/shared/lib/mrss/event_subscriber.rb +0 -210
  428. data/spec/shared/lib/mrss/lite_constraints.rb +0 -238
  429. data/spec/shared/lib/mrss/server_version_registry.rb +0 -120
  430. data/spec/shared/lib/mrss/session_registry.rb +0 -69
  431. data/spec/shared/lib/mrss/session_registry_legacy.rb +0 -60
  432. data/spec/shared/lib/mrss/spec_organizer.rb +0 -179
  433. data/spec/shared/lib/mrss/utils.rb +0 -15
  434. data/spec/shared/share/Dockerfile.erb +0 -325
  435. data/spec/shared/share/haproxy-1.conf +0 -16
  436. data/spec/shared/share/haproxy-2.conf +0 -17
  437. data/spec/shared/shlib/config.sh +0 -27
  438. data/spec/shared/shlib/distro.sh +0 -74
  439. data/spec/shared/shlib/server.sh +0 -392
  440. data/spec/shared/shlib/set_env.sh +0 -169
  441. data.tar.gz.sig +0 -0
  442. metadata.gz.sig +0 -3
@@ -4,6 +4,36 @@ require "spec_helper"
4
4
 
5
5
  describe Mongoid::Contextual::Memory do
6
6
 
7
+ shared_examples "raises an error when no documents" do
8
+ context "when there are no matching documents" do
9
+ let(:criteria) do
10
+ Address.all.tap do |crit|
11
+ crit.documents = []
12
+ end
13
+ end
14
+
15
+ it "returns nil" do
16
+ expect do
17
+ context.send(method)
18
+ end.to raise_error(Mongoid::Errors::DocumentNotFound, /Could not find a document of class Address./)
19
+ end
20
+ end
21
+ end
22
+
23
+ shared_examples "returns nil when no documents" do
24
+ context "when there are no matching documents" do
25
+ let(:criteria) do
26
+ Address.all.tap do |crit|
27
+ crit.documents = []
28
+ end
29
+ end
30
+
31
+ it "returns nil" do
32
+ expect(context.send(method)).to be_nil
33
+ end
34
+ end
35
+ end
36
+
7
37
  [ :blank?, :empty? ].each do |method|
8
38
 
9
39
  describe "##{method}" do
@@ -492,6 +522,8 @@ describe Mongoid::Contextual::Memory do
492
522
  end
493
523
 
494
524
  context "when getting a localized field" do
525
+ with_default_i18n_configs
526
+
495
527
  before do
496
528
  I18n.locale = :en
497
529
  d = Dictionary.create!(description: 'english-text')
@@ -500,10 +532,6 @@ describe Mongoid::Contextual::Memory do
500
532
  d.save!
501
533
  end
502
534
 
503
- after do
504
- I18n.locale = :en
505
- end
506
-
507
535
  let(:criteria) do
508
536
  Dictionary.all.tap do |crit|
509
537
  crit.documents = [ Dictionary.first ]
@@ -547,16 +575,10 @@ describe Mongoid::Contextual::Memory do
547
575
 
548
576
  context 'when fallbacks are enabled with a locale list' do
549
577
  require_fallbacks
578
+ with_default_i18n_configs
550
579
 
551
- around(:all) do |example|
552
- prev_fallbacks = I18n.fallbacks.dup
580
+ before do
553
581
  I18n.fallbacks[:he] = [ :en ]
554
- example.run
555
- I18n.fallbacks = prev_fallbacks
556
- end
557
-
558
- after do
559
- I18n.locale = :en
560
582
  end
561
583
 
562
584
  let(:distinct) do
@@ -565,13 +587,15 @@ describe Mongoid::Contextual::Memory do
565
587
 
566
588
  it "correctly uses the fallback" do
567
589
  I18n.locale = :en
568
- d = Dictionary.create!(description: 'english-text')
590
+ Dictionary.create!(description: 'english-text')
569
591
  I18n.locale = :he
570
592
  distinct.should == "english-text"
571
593
  end
572
594
  end
573
595
 
574
596
  context "when the localized field is embedded" do
597
+ with_default_i18n_configs
598
+
575
599
  let(:person) do
576
600
  p = Passport.new
577
601
  I18n.locale = :en
@@ -582,10 +606,6 @@ describe Mongoid::Contextual::Memory do
582
606
  Person.create!(passport: p, employer_id: 12345)
583
607
  end
584
608
 
585
- after do
586
- I18n.locale = :en
587
- end
588
-
589
609
  let(:criteria) do
590
610
  Person.where(employer_id: 12345).tap do |crit|
591
611
  crit.documents = [ person ]
@@ -746,52 +766,158 @@ describe Mongoid::Contextual::Memory do
746
766
  Address.new(street: "friedel")
747
767
  end
748
768
 
749
- context "when there are matching documents" do
769
+ let(:criteria) do
770
+ Address.where(street: "hobrecht").tap do |crit|
771
+ crit.documents = [ hobrecht, friedel ]
772
+ end
773
+ end
774
+
775
+ context "when not passing options" do
750
776
 
751
- let(:criteria) do
752
- Address.where(street: "hobrecht").tap do |crit|
753
- crit.documents = [ hobrecht, friedel ]
777
+ context "when there are matching documents" do
778
+
779
+ let(:context) do
780
+ described_class.new(criteria)
781
+ end
782
+
783
+ it "returns true" do
784
+ expect(context).to be_exists
754
785
  end
755
786
  end
756
787
 
757
- let(:context) do
758
- described_class.new(criteria)
788
+ context "when there are no matching documents" do
789
+
790
+ let(:criteria) do
791
+ Address.where(street: "pfluger").tap do |crit|
792
+ crit.documents = [ hobrecht, friedel ]
793
+ end
794
+ end
795
+
796
+ let(:context) do
797
+ described_class.new(criteria)
798
+ end
799
+
800
+ it "returns false" do
801
+ expect(context).to_not be_exists
802
+ end
759
803
  end
760
804
 
761
- it "returns true" do
762
- expect(context).to be_exists
805
+ context 'when there is a collation on the criteria' do
806
+
807
+ let(:criteria) do
808
+ Address.where(street: "pfluger").tap do |crit|
809
+ crit.documents = [ hobrecht, friedel ]
810
+ end.collation(locale: 'en_US', strength: 2)
811
+ end
812
+
813
+ it "raises an exception" do
814
+ expect {
815
+ context
816
+ }.to raise_exception(Mongoid::Errors::InMemoryCollationNotSupported)
817
+ end
763
818
  end
764
819
  end
765
820
 
766
- context "when there are no matching documents" do
821
+ context "when passing an _id" do
767
822
 
768
- let(:criteria) do
769
- Address.where(street: "pfluger").tap do |crit|
770
- crit.documents = [ hobrecht, friedel ]
823
+ context "when its of type BSON::ObjectId" do
824
+
825
+ context "when calling it on an empty criteria" do
826
+
827
+ it "returns true" do
828
+ expect(criteria.exists?(hobrecht._id)).to be true
829
+ end
830
+ end
831
+
832
+ context "when calling it on a criteria that includes the object" do
833
+
834
+ it "returns true" do
835
+ expect(criteria.where(street: hobrecht.street).exists?(hobrecht._id)).to be true
836
+ end
837
+ end
838
+
839
+ context "when calling it on a criteria that does not include the object" do
840
+
841
+ it "returns false" do
842
+ expect(criteria.where(street: "bogus").exists?(hobrecht._id)).to be false
843
+ end
844
+ end
845
+
846
+ context "when the id does not exist" do
847
+
848
+ it "returns false" do
849
+ expect(criteria.exists?(BSON::ObjectId.new)).to be false
850
+ end
771
851
  end
772
852
  end
773
853
 
774
- let(:context) do
775
- described_class.new(criteria)
854
+ context "when its of type String" do
855
+
856
+ context "when the id exists" do
857
+
858
+ it "returns true" do
859
+ expect(criteria.exists?(hobrecht._id.to_s)).to be true
860
+ end
861
+ end
862
+
863
+ context "when the id does not exist" do
864
+
865
+ it "returns false" do
866
+ expect(criteria.exists?(BSON::ObjectId.new.to_s)).to be false
867
+ end
868
+ end
869
+ end
870
+ end
871
+
872
+ context "when passing a hash" do
873
+
874
+ context "when calling it on an empty criteria" do
875
+
876
+ it "returns true" do
877
+ expect(criteria.exists?(street: hobrecht.street)).to be true
878
+ end
879
+ end
880
+
881
+ context "when calling it on a criteria that includes the object" do
882
+
883
+ it "returns true" do
884
+ expect(criteria.where(_id: hobrecht._id).exists?(street: hobrecht.street)).to be true
885
+ end
886
+ end
887
+
888
+ context "when calling it on a criteria that does not include the object" do
889
+
890
+ it "returns false" do
891
+ expect(criteria.where(_id: BSON::ObjectId.new).exists?(street: hobrecht.street)).to be false
892
+ end
776
893
  end
777
894
 
895
+ context "when the conditions don't match" do
896
+
897
+ it "returns false" do
898
+ expect(criteria.exists?(street: "bogus")).to be false
899
+ end
900
+ end
901
+ end
902
+
903
+ context "when passing false" do
904
+
778
905
  it "returns false" do
779
- expect(context).to_not be_exists
906
+ expect(criteria.exists?(false)).to be false
780
907
  end
781
908
  end
782
909
 
783
- context 'when there is a collation on the criteria' do
910
+ context "when passing nil" do
784
911
 
785
- let(:criteria) do
786
- Address.where(street: "pfluger").tap do |crit|
787
- crit.documents = [ hobrecht, friedel ]
788
- end.collation(locale: 'en_US', strength: 2)
912
+ it "returns false" do
913
+ expect(criteria.exists?(nil)).to be false
789
914
  end
915
+ end
790
916
 
791
- it "raises an exception" do
792
- expect {
793
- context
794
- }.to raise_exception(Mongoid::Errors::InMemoryCollationNotSupported)
917
+ context "when the limit is 0" do
918
+
919
+ it "returns false" do
920
+ expect(criteria.limit(0).exists?).to be false
795
921
  end
796
922
  end
797
923
  end
@@ -800,6 +926,8 @@ describe Mongoid::Contextual::Memory do
800
926
 
801
927
  describe "##{method}" do
802
928
 
929
+ let(:method) { method }
930
+
803
931
  let(:hobrecht) do
804
932
  Address.new(street: "hobrecht")
805
933
  end
@@ -830,9 +958,7 @@ describe Mongoid::Contextual::Memory do
830
958
  expect(context.send(method, 1)).to eq([ hobrecht ])
831
959
  end
832
960
 
833
- it "returns the matching document when passing deprecated options" do
834
- expect(context.send(method, id_sort: :none)).to eq(hobrecht)
835
- end
961
+ include_examples "returns nil when no documents"
836
962
 
837
963
  context 'when there is a collation on the criteria' do
838
964
 
@@ -851,8 +977,39 @@ describe Mongoid::Contextual::Memory do
851
977
  end
852
978
  end
853
979
 
980
+ describe "#first!" do
981
+
982
+ let(:method) { :first! }
983
+
984
+ let(:hobrecht) do
985
+ Address.new(street: "hobrecht")
986
+ end
987
+
988
+ let(:friedel) do
989
+ Address.new(street: "friedel")
990
+ end
991
+
992
+ let(:criteria) do
993
+ Address.where(:street.in => [ "hobrecht", "friedel" ]).tap do |crit|
994
+ crit.documents = [ hobrecht, friedel ]
995
+ end
996
+ end
997
+
998
+ let(:context) do
999
+ described_class.new(criteria)
1000
+ end
1001
+
1002
+ it "returns the first matching document" do
1003
+ expect(context.first!).to eq(hobrecht)
1004
+ end
1005
+
1006
+ include_examples "raises an error when no documents"
1007
+ end
1008
+
854
1009
  describe "#take" do
855
1010
 
1011
+ let(:method) { :take }
1012
+
856
1013
  let(:hobrecht) do
857
1014
  Address.new(street: "hobrecht")
858
1015
  end
@@ -883,6 +1040,8 @@ describe Mongoid::Contextual::Memory do
883
1040
  expect(context.take(1)).to eq([ hobrecht ])
884
1041
  end
885
1042
 
1043
+ include_examples "returns nil when no documents"
1044
+
886
1045
  context 'when there is a collation on the criteria' do
887
1046
 
888
1047
  let(:criteria) do
@@ -901,6 +1060,8 @@ describe Mongoid::Contextual::Memory do
901
1060
 
902
1061
  describe "#take!" do
903
1062
 
1063
+ let(:method) { :take! }
1064
+
904
1065
  let(:hobrecht) do
905
1066
  Address.new(street: "hobrecht")
906
1067
  end
@@ -923,19 +1084,7 @@ describe Mongoid::Contextual::Memory do
923
1084
  expect(context.take!).to eq(hobrecht)
924
1085
  end
925
1086
 
926
- context "when the criteria is empty" do
927
- let(:criteria) do
928
- Address.where(street: "bogus").tap do |crit|
929
- crit.documents = []
930
- end
931
- end
932
-
933
- it "raise an error" do
934
- expect do
935
- context.take!
936
- end.to raise_error(Mongoid::Errors::DocumentNotFound, /Could not find a document of class Address./)
937
- end
938
- end
1087
+ include_examples "raises an error when no documents"
939
1088
 
940
1089
  context 'when there is a collation on the criteria' do
941
1090
 
@@ -1056,6 +1205,8 @@ describe Mongoid::Contextual::Memory do
1056
1205
 
1057
1206
  describe "#last" do
1058
1207
 
1208
+ let(:method) { :last }
1209
+
1059
1210
  let(:hobrecht) do
1060
1211
  Address.new(street: "hobrecht")
1061
1212
  end
@@ -1086,9 +1237,7 @@ describe Mongoid::Contextual::Memory do
1086
1237
  expect(context.last(1)).to eq([ friedel ])
1087
1238
  end
1088
1239
 
1089
- it "returns the matching document when passing deprecated options" do
1090
- expect(context.last(id_sort: :none)).to eq(friedel)
1091
- end
1240
+ include_examples "returns nil when no documents"
1092
1241
 
1093
1242
  context 'when there is a collation on the criteria' do
1094
1243
 
@@ -1106,6 +1255,102 @@ describe Mongoid::Contextual::Memory do
1106
1255
  end
1107
1256
  end
1108
1257
 
1258
+ describe "#last!" do
1259
+ let(:method) { :last! }
1260
+
1261
+ let(:hobrecht) do
1262
+ Address.new(street: "hobrecht")
1263
+ end
1264
+
1265
+ let(:friedel) do
1266
+ Address.new(street: "friedel")
1267
+ end
1268
+
1269
+ let(:criteria) do
1270
+ Address.where(:street.in => [ "hobrecht", "friedel" ]).tap do |crit|
1271
+ crit.documents = [ hobrecht, friedel ]
1272
+ end
1273
+ end
1274
+
1275
+ let(:context) do
1276
+ described_class.new(criteria)
1277
+ end
1278
+
1279
+ it "returns the last matching document" do
1280
+ expect(context.last!).to eq(friedel)
1281
+ end
1282
+
1283
+ include_examples "raises an error when no documents"
1284
+ end
1285
+
1286
+ [ :second,
1287
+ :third,
1288
+ :fourth,
1289
+ :fifth,
1290
+ :second_to_last,
1291
+ :third_to_last
1292
+ ].each do |meth|
1293
+ describe "##{meth}" do
1294
+ let(:method) { meth }
1295
+
1296
+ let(:addresses) do
1297
+ [
1298
+ Address.new,
1299
+ Address.new,
1300
+ Address.new,
1301
+ Address.new,
1302
+ Address.new,
1303
+ ]
1304
+ end
1305
+
1306
+ let(:criteria) do
1307
+ Address.all.tap do |crit|
1308
+ crit.documents = addresses
1309
+ end
1310
+ end
1311
+
1312
+ let(:context) do
1313
+ described_class.new(criteria)
1314
+ end
1315
+
1316
+ it "returns the matching document" do
1317
+ expect(context.send(method)).to eq(addresses.send(method))
1318
+ end
1319
+
1320
+ include_examples "returns nil when no documents"
1321
+ end
1322
+
1323
+ describe "##{meth}!" do
1324
+ let(:method) { "#{meth}!" }
1325
+
1326
+ let(:addresses) do
1327
+ [
1328
+ Address.new,
1329
+ Address.new,
1330
+ Address.new,
1331
+ Address.new,
1332
+ Address.new,
1333
+ ]
1334
+ end
1335
+
1336
+ let(:criteria) do
1337
+ Address.all.tap do |crit|
1338
+ crit.documents = addresses
1339
+ end
1340
+ end
1341
+
1342
+ let(:context) do
1343
+ described_class.new(criteria)
1344
+ end
1345
+
1346
+ it "returns the matching document" do
1347
+ expect(context.send(method)).to eq(addresses.send(meth))
1348
+ end
1349
+
1350
+ include_examples "raises an error when no documents"
1351
+ end
1352
+ end
1353
+
1109
1354
  [ :length, :size ].each do |method|
1110
1355
 
1111
1356
  describe "##{method}" do
@@ -1251,11 +1496,11 @@ describe Mongoid::Contextual::Memory do
1251
1496
  config_override :legacy_pluck_distinct, true
1252
1497
 
1253
1498
  let(:hobrecht) do
1254
- Address.new(street: "hobrecht")
1499
+ Address.new(street: "hobrecht", number: 213)
1255
1500
  end
1256
1501
 
1257
1502
  let(:friedel) do
1258
- Address.new(street: "friedel")
1503
+ Address.new(street: "friedel", number: 11)
1259
1504
  end
1260
1505
 
1261
1506
  let(:criteria) do
@@ -1275,6 +1520,17 @@ describe Mongoid::Contextual::Memory do
1275
1520
  end
1276
1521
  end
1277
1522
 
1523
+ context "when plucking multiple fields" do
1524
+
1525
+ let!(:plucked) do
1526
+ context.pluck(:street, :number)
1527
+ end
1528
+
1529
+ it "returns the values as an array" do
1530
+ expect(plucked).to eq([ ["hobrecht", 213], ["friedel", 11] ])
1531
+ end
1532
+ end
1533
+
1278
1534
  context "when plucking a mix of empty and non-empty values" do
1279
1535
 
1280
1536
  let(:empty_doc) do
@@ -1304,7 +1560,7 @@ describe Mongoid::Contextual::Memory do
1304
1560
  context.pluck(:foo)
1305
1561
  end
1306
1562
 
1307
- it "returns a empty array" do
1563
+ it "returns an empty array" do
1308
1564
  expect(plucked).to eq([nil, nil])
1309
1565
  end
1310
1566
  end
@@ -1315,7 +1571,7 @@ describe Mongoid::Contextual::Memory do
1315
1571
  context.pluck(:foo, :bar)
1316
1572
  end
1317
1573
 
1318
- it "returns a empty array" do
1574
+ it "returns an empty array" do
1319
1575
  expect(plucked).to eq([[nil, nil], [nil, nil]])
1320
1576
  end
1321
1577
  end
@@ -1352,7 +1608,7 @@ describe Mongoid::Contextual::Memory do
1352
1608
  Band.create!(name: "Photek", likes: 1)
1353
1609
  end
1354
1610
 
1355
- let(:maniacs) do
1611
+ let!(:maniacs) do
1356
1612
  Band.create!(name: "10,000 Maniacs", likes: 1, sales: "1E2")
1357
1613
  end
1358
1614
 
@@ -1537,6 +1793,7 @@ describe Mongoid::Contextual::Memory do
1537
1793
  end
1538
1794
 
1539
1795
  context 'when plucking a localized field' do
1796
+ with_default_i18n_configs
1540
1797
 
1541
1798
  before do
1542
1799
  I18n.locale = :en
@@ -1546,10 +1803,6 @@ describe Mongoid::Contextual::Memory do
1546
1803
  d.save!
1547
1804
  end
1548
1805
 
1549
- after do
1550
- I18n.locale = :en
1551
- end
1552
-
1553
1806
  let(:criteria) do
1554
1807
  Dictionary.all.tap do |crit|
1555
1808
  crit.documents = [ Dictionary.first ]
@@ -1607,16 +1860,10 @@ describe Mongoid::Contextual::Memory do
1607
1860
 
1608
1861
  context 'when fallbacks are enabled with a locale list' do
1609
1862
  require_fallbacks
1863
+ with_default_i18n_configs
1610
1864
 
1611
- around(:all) do |example|
1612
- prev_fallbacks = I18n.fallbacks.dup
1865
+ before do
1613
1866
  I18n.fallbacks[:he] = [ :en ]
1614
- example.run
1615
- I18n.fallbacks = prev_fallbacks
1616
- end
1617
-
1618
- after do
1619
- I18n.locale = :en
1620
1867
  end
1621
1868
 
1622
1869
  let(:plucked) do
@@ -1625,13 +1872,15 @@ describe Mongoid::Contextual::Memory do
1625
1872
 
1626
1873
  it "correctly uses the fallback" do
1627
1874
  I18n.locale = :en
1628
- d = Dictionary.create!(description: 'english-text')
1875
+ Dictionary.create!(description: 'english-text')
1629
1876
  I18n.locale = :he
1630
1877
  plucked.should == "english-text"
1631
1878
  end
1632
1879
  end
1633
1880
 
1634
1881
  context "when the localized field is embedded" do
1882
+ with_default_i18n_configs
1883
+
1635
1884
  before do
1636
1885
  p = Passport.new
1637
1886
  I18n.locale = :en
@@ -1642,10 +1891,6 @@ describe Mongoid::Contextual::Memory do
1642
1891
  Person.create!(passport: p, employer_id: 12345)
1643
1892
  end
1644
1893
 
1645
- after do
1646
- I18n.locale = :en
1647
- end
1648
-
1649
1894
  let(:plucked) do
1650
1895
  Person.where(employer_id: 12345).pluck("pass.name").first
1651
1896
  end
@@ -1678,9 +1923,12 @@ describe Mongoid::Contextual::Memory do
1678
1923
  Band.where(name: maniacs.name).pluck(:sales)
1679
1924
  end
1680
1925
 
1681
- it "demongoizes the field" do
1682
- expect(plucked.first).to be_a(BigDecimal)
1683
- expect(plucked.first).to eq(BigDecimal("1E2"))
1926
+ with_config_values :map_big_decimal_to_decimal128, true, false do
1927
+
1928
+ it "demongoizes the field" do
1929
+ expect(plucked.first).to be_a(BigDecimal)
1930
+ expect(plucked.first).to eq(BigDecimal("1E2"))
1931
+ end
1684
1932
  end
1685
1933
  end
1686
1934
 
@@ -1690,7 +1938,7 @@ describe Mongoid::Contextual::Memory do
1690
1938
 
1691
1939
  let(:plucked) do
1692
1940
  Band.where(_id: band.id).tap do |crit|
1693
- crit.documents = [band]
1941
+ crit.documents = [ band ]
1694
1942
  end.pluck("label.sales")
1695
1943
  end
1696
1944
 
@@ -1716,7 +1964,7 @@ describe Mongoid::Contextual::Memory do
1716
1964
 
1717
1965
  let(:plucked) do
1718
1966
  Band.where(_id: band.id).tap do |crit|
1719
- crit.documents = band
1967
+ crit.documents = [ band ]
1720
1968
  end.pluck("label.qwerty")
1721
1969
  end
1722
1970
 
@@ -1725,7 +1973,7 @@ describe Mongoid::Contextual::Memory do
1725
1973
  end
1726
1974
  end
1727
1975
 
1728
- context "when tallying deeply nested arrays/embedded associations" do
1976
+ context "when plucking deeply nested arrays/embedded associations" do
1729
1977
 
1730
1978
  let(:criteria) do
1731
1979
  Person.all.tap do |crit|
@@ -1750,6 +1998,520 @@ describe Mongoid::Contextual::Memory do
1750
1998
  end
1751
1999
  end
1752
2000
 
2001
+ describe "#pick" do
2002
+
2003
+ let(:depeche) do
2004
+ Band.create!(name: "Depeche Mode", likes: 3)
2005
+ end
2006
+
2007
+ let(:tool) do
2008
+ Band.create!(name: "Tool", likes: 3)
2009
+ end
2010
+
2011
+ let(:criteria) do
2012
+ Band.all.tap do |crit|
2013
+ crit.documents = [ depeche, tool ]
2014
+ end
2015
+ end
2016
+
2017
+ let(:context) do
2018
+ described_class.new(criteria)
2019
+ end
2020
+
2021
+ context "when picking a field" do
2022
+
2023
+ let(:picked) do
2024
+ context.pick(:name)
2025
+ end
2026
+
2027
+ it "returns one element" do
2028
+ expect(picked).to eq("Depeche Mode")
2029
+ end
2030
+ end
2031
+
2032
+ context "when picking multiple fields" do
2033
+
2034
+ let(:picked) do
2035
+ context.pick(:name, :likes)
2036
+ end
2037
+
2038
+ it "returns an array" do
2039
+ expect(picked).to eq([ "Depeche Mode", 3 ])
2040
+ end
2041
+ end
2042
+
2043
+ context "when no documents to pick" do
2044
+
2045
+ let(:criteria) do
2046
+ Band.all.tap do |crit|
2047
+ crit.documents = []
2048
+ end
2049
+ end
2050
+
2051
+ let(:picked) do
2052
+ context.pick(:name)
2053
+ end
2054
+
2055
+ it "returns nil" do
2056
+ expect(picked).to be_nil
2057
+ end
2058
+ end
2059
+ end
2060
+
2061
+ describe "#tally" do
2062
+ let(:fans1) { [ Fanatic.new(age:1), Fanatic.new(age:2) ] }
2063
+ let(:fans2) { [ Fanatic.new(age:1), Fanatic.new(age:2) ] }
2064
+ let(:fans3) { [ Fanatic.new(age:1), Fanatic.new(age:3) ] }
2065
+
2066
+ let(:genres1) { [ { x: 1, y: { z: 1 } }, { x: 2, y: { z: 2 } }, { y: 3 } ]}
2067
+ let(:genres2) { [ { x: 1, y: { z: 1 } }, { x: 2, y: { z: 2 } }, { y: 4 } ]}
2068
+ let(:genres3) { [ { x: 1, y: { z: 1 } }, { x: 3, y: { z: 3 } }, { y: 5 } ]}
2069
+
2070
+ let(:label1) { Label.new(name: "Atlantic") }
2071
+ let(:label2) { Label.new(name: "Atlantic") }
2072
+ let(:label3) { Label.new(name: "Columbia") }
2073
+
2074
+
2075
+ let(:band1) { Band.new(origin: "tally", name: "Depeche Mode", years: 30, sales: "1E2", label: label1, genres: genres1) }
2076
+ let(:band2) { Band.new(origin: "tally", name: "New Order", years: 30, sales: "2E3", label: label2, genres: genres2) }
2077
+ let(:band3) { Band.new(origin: "tally", name: "10,000 Maniacs", years: 30, sales: "1E2", label: label3, genres: genres3) }
2078
+ let(:band4) { Band.new(origin: "tally2", fanatics: fans1, genres: [1, 2]) }
2079
+ let(:band5) { Band.new(origin: "tally2", fanatics: fans2, genres: [1, 2]) }
2080
+ let(:band6) { Band.new(origin: "tally2", fanatics: fans3, genres: [1, 3]) }
2081
+
2082
+ let(:criteria) do
2083
+ Band.where(origin: "tally").all.tap do |crit|
2084
+ crit.documents = [ band1, band2, band3 ]
2085
+ end
2086
+ end
2087
+
2088
+ let(:criteria2) do
2089
+ Band.where(origin: "tally2").tap do |crit|
2090
+ crit.documents = [ band4, band5, band6 ]
2091
+ end
2092
+ end
2093
+
2094
+ let(:context) do
2095
+ described_class.new(criteria)
2096
+ end
2097
+
2098
+ let(:context2) do
2099
+ described_class.new(criteria2)
2100
+ end
2101
+
2102
+ context "when tallying a string" do
2103
+ let(:tally) do
2104
+ context.tally(:name)
2105
+ end
2106
+
2107
+ it "returns the correct hash" do
2108
+ expect(tally).to eq("Depeche Mode" => 1, "New Order" => 1, "10,000 Maniacs" => 1)
2109
+ end
2110
+ end
2111
+
2112
+ context "using an aliased field" do
2113
+ let(:tally) do
2114
+ context.tally(:years)
2115
+ end
2116
+
2117
+ it "returns the correct hash" do
2118
+ expect(tally).to eq(30 => 3)
2119
+ end
2120
+ end
2121
+
2122
+ context "when tallying a demongoizable field" do
2123
+ let(:tally) do
2124
+ context.tally(:sales)
2125
+ end
2126
+
2127
+ it "returns the correct hash" do
2128
+ expect(tally).to eq(BigDecimal("1E2") => 2, BigDecimal("2E3") => 1)
2129
+ end
2130
+ end
2131
+
2132
+ context "when tallying a localized field" do
2133
+ with_default_i18n_configs
2134
+
2135
+ let(:d1) { Dictionary.new(description: 'en1') }
2136
+ let(:d2) { Dictionary.new(description: 'en1') }
2137
+ let(:d3) { Dictionary.new(description: 'en1') }
2138
+ let(:d4) { Dictionary.new(description: 'en2') }
2139
+
2140
+ before do
2141
+ I18n.locale = :en
2142
+ d1
2143
+ d2
2144
+ d3
2145
+ d4
2146
+ I18n.locale = :de
2147
+ d1.description = 'de1'
2148
+ d2.description = 'de1'
2149
+ d3.description = 'de2'
2150
+ d4.description = 'de3'
2151
+ I18n.locale = :en
2152
+ end
2153
+
2154
+ let(:criteria) do
2155
+ Dictionary.all.tap do |crit|
2156
+ crit.documents = [ d1, d2, d3, d4 ]
2157
+ end
2158
+ end
2159
+
2160
+ context "when getting the demongoized field" do
2161
+ let(:tallied) do
2162
+ context.tally(:description)
2163
+ end
2164
+
2165
+ it "returns the translation for the current locale" do
2166
+ expect(tallied).to eq("en1" => 3, "en2" => 1)
2167
+ end
2168
+ end
2169
+
2170
+ context "when getting a specific locale" do
2171
+ let(:tallied) do
2172
+ context.tally("description.de")
2173
+ end
2174
+
2175
+ it "returns the translation for the the specific locale" do
2176
+ expect(tallied).to eq("de1" => 2, "de2" => 1, "de3" => 1)
2177
+ end
2178
+ end
2179
+
2180
+ context "when getting the full hash" do
2181
+ let(:tallied) do
2182
+ context.tally("description_translations")
2183
+ end
2184
+
2185
+ it "returns the correct hash" do
2186
+ expect(tallied).to eq(
2187
+ {"de" => "de1", "en" => "en1" } => 2,
2188
+ {"de" => "de2", "en" => "en1" } => 1,
2189
+ {"de" => "de3", "en" => "en2" } => 1
2190
+ )
2191
+ end
2192
+ end
2193
+ end
2194
+
2195
+ context "when tallying an embedded localized field" do
2196
+ with_default_i18n_configs
2197
+
2198
+ let(:person1) { Person.create!(addresses: [ address1a, address1b ]) }
2199
+ let(:person2) { Person.create!(addresses: [ address2a, address2b ]) }
2200
+
2201
+ let(:address1a) { Address.new(name: "en1") }
2202
+ let(:address1b) { Address.new(name: "en2") }
2203
+ let(:address2a) { Address.new(name: "en1") }
2204
+ let(:address2b) { Address.new(name: "en3") }
2205
+
2206
+ before do
2207
+ I18n.locale = :en
2208
+ address1a
2209
+ address1b
2210
+ address2a
2211
+ address2b
2212
+ I18n.locale = :de
2213
+ address1a.name = "de1"
2214
+ address1b.name = "de2"
2215
+ address2a.name = "de1"
2216
+ address2b.name = "de3"
2217
+ person1
2218
+ person2
2219
+ I18n.locale = :en
2220
+ end
2221
+
2222
+ let(:criteria) do
2223
+ Person.all.tap do |crit|
2224
+ crit.documents = [ person1, person2 ]
2225
+ end
2226
+ end
2227
+
2228
+ context "when getting the demongoized field" do
2229
+ let(:tallied) do
2230
+ context.tally("addresses.name")
2231
+ end
2232
+
2233
+ it "returns the translation for the current locale" do
2234
+ expect(tallied).to eq(
2235
+ [ "en1", "en2" ] => 1,
2236
+ [ "en1", "en3" ] => 1,
2237
+ )
2238
+ end
2239
+ end
2240
+
2241
+ context "when getting a specific locale" do
2242
+ let(:tallied) do
2243
+ context.tally("addresses.name.de")
2244
+ end
2245
+
2246
+ it "returns the translation for the the specific locale" do
2247
+ expect(tallied).to eq(
2248
+ [ "de1", "de2" ] => 1,
2249
+ [ "de1", "de3" ] => 1,
2250
+ )
2251
+ end
2252
+ end
2253
+
2254
+ context "when getting the full hash" do
2255
+ let(:tallied) do
2256
+ context.tally("addresses.name_translations")
2257
+ end
2258
+
2259
+ it "returns the correct hash" do
2260
+ expect(tallied).to eq(
2261
+ [{ "de" => "de1", "en" => "en1" }, { "de" => "de2", "en" => "en2" }] => 1,
2262
+ [{ "de" => "de1", "en" => "en1" }, { "de" => "de3", "en" => "en3" }] => 1,
2263
+ )
2264
+ end
2265
+ end
2266
+ end
2267
+
2268
+ context "when tallying an embedded field" do
2269
+ let(:tally) do
2270
+ context.tally("label.name")
2271
+ end
2272
+
2273
+ it "returns the correct hash" do
2274
+ expect(tally).to eq("Atlantic" => 2, "Columbia" => 1)
2275
+ end
2276
+ end
2277
+
2278
+ context "when tallying an element in an embeds_many field" do
2279
+
2280
+ let(:tally) do
2281
+ context2.tally("fanatics.age")
2282
+ end
2283
+
2284
+ it "returns the correct hash" do
2285
+ expect(tally).to eq(
2286
+ [1, 2] => 2,
2287
+ [1, 3] => 1
2288
+ )
2289
+ end
2290
+ end
2291
+
2292
+ context "when tallying an embeds_many field" do
2293
+
2294
+ let(:tally) do
2295
+ context2.tally("fanatics")
2296
+ end
2297
+
2298
+ it "returns the correct hash" do
2299
+ expect(tally).to eq(
2300
+ fans1 => 1,
2301
+ fans2 => 1,
2302
+ fans3 => 1,
2303
+ )
2304
+ end
2305
+ end
2306
+
2307
+ context "when tallying a field of type array" do
2308
+
2309
+ let(:tally) do
2310
+ context2.tally("genres")
2311
+ end
2312
+
2313
+ it "returns the correct hash" do
2314
+ expect(tally).to eq(
2315
+ [1, 2] => 2,
2316
+ [1, 3] => 1
2317
+ )
2318
+ end
2319
+ end
2320
+
2321
+ context "when tallying an element from an array of hashes" do
2322
+
2323
+ let(:tally) do
2324
+ context.tally("genres.x")
2325
+ end
2326
+
2327
+ it "returns the correct hash without the nil keys" do
2328
+ expect(tally).to eq(
2329
+ [1, 2] => 2,
2330
+ [1, 3] => 1
2331
+ )
2332
+ end
2333
+ end
2334
+
2335
+ context "when tallying an element from an array of hashes; with duplicate" do
2336
+
2337
+ let(:band4) { Band.new(origin: "tally", genres: [ { x: 1 }, {x: 1} ] ) }
2338
+
2339
+ let(:criteria) do
2340
+ Band.where(origin: "tally").all.tap do |crit|
2341
+ crit.documents = [ band1, band2, band3, band4 ]
2342
+ end
2343
+ end
2344
+
2345
+ let(:tally) do
2346
+ context.tally("genres.x")
2347
+ end
2348
+
2349
+ it "returns the correct hash without the nil keys" do
2350
+ expect(tally).to eq(
2351
+ [1, 2] => 2,
2352
+ [1, 3] => 1,
2353
+ [1, 1] => 1,
2354
+ )
2355
+ end
2356
+ end
2357
+
2358
+ context "when tallying an aliased field of type array" do
2359
+
2360
+ let(:person1) { Person.new(array: [ 1, 2 ]) }
2361
+ let(:person2) { Person.new(array: [ 1, 3 ]) }
2362
+
2363
+ let(:criteria) do
2364
+ Person.all.tap do |crit|
2365
+ crit.documents = [ person1, person2 ]
2366
+ end
2367
+ end
2368
+
2369
+ let(:tally) do
2370
+ context.tally("array")
2371
+ end
2372
+
2373
+ it "returns the correct hash" do
2374
+ expect(tally).to eq(
2375
+ [1, 2] => 1,
2376
+ [1, 3] => 1
2377
+ )
2378
+ end
2379
+ end
2380
+
2381
+ context "when going multiple levels deep in arrays" do
2382
+
2383
+ let(:tally) do
2384
+ context.tally("genres.y.z")
2385
+ end
2386
+
2387
+ it "returns the correct hash" do
2388
+ expect(tally).to eq(
2389
+ [1, 2] => 2,
2390
+ [1, 3] => 1
2391
+ )
2392
+ end
2393
+ end
2394
+
2395
+ context "when going multiple levels deep in an array" do
2396
+
2397
+ let(:tally) do
2398
+ context.tally("genres.y.z")
2399
+ end
2400
+
2401
+ it "returns the correct hash" do
2402
+ expect(tally).to eq(
2403
+ [1, 2] => 2,
2404
+ [1, 3] => 1
2405
+ )
2406
+ end
2407
+ end
2408
+
2409
+ context "when tallying deeply nested arrays/embedded associations" do
2410
+
2411
+ let(:person1) { Person.new(addresses: [ Address.new(code: Code.new(deepest: Deepest.new(array: [ { y: { z: 1 } }, { y: { z: 2 } } ]))) ]) }
2412
+ let(:person2) { Person.new(addresses: [ Address.new(code: Code.new(deepest: Deepest.new(array: [ { y: { z: 1 } }, { y: { z: 2 } } ]))) ]) }
2413
+ let(:person3) { Person.new(addresses: [ Address.new(code: Code.new(deepest: Deepest.new(array: [ { y: { z: 1 } }, { y: { z: 3 } } ]))) ]) }
2414
+
2415
+ let(:criteria) do
2416
+ Person.all.tap do |crit|
2417
+ crit.documents = [ person1, person2, person3 ]
2418
+ end
2419
+ end
2420
+
2421
+ let(:tally) do
2422
+ context.tally("addresses.code.deepest.array.y.z")
2423
+ end
2424
+
2425
+ it "returns the correct hash" do
2426
+ expect(tally).to eq(
2427
+ [ [ 1, 2 ] ] => 2,
2428
+ [ [ 1, 3 ] ] => 1
2429
+ )
2430
+ end
2431
+ end
2432
+
2433
+ context "when tallying deeply nested arrays/embedded associations" do
2434
+
2435
+ let(:person1) do
2436
+ Person.new(addresses: [ Address.new(code: Code.new(deepest: Deepest.new(array: [ { y: { z: 1 } }, { y: { z: 2 } } ]))),
2437
+ Address.new(code: Code.new(deepest: Deepest.new(array: [ { y: { z: 1 } }, { y: { z: 2 } } ]))) ])
2438
+ end
2439
+
2440
+ let(:person2) do
2441
+ Person.new(addresses: [ Address.new(code: Code.new(deepest: Deepest.new(array: [ { y: { z: 1 } }, { y: { z: 2 } } ]))),
2442
+ Address.new(code: Code.new(deepest: Deepest.new(array: [ { y: { z: 1 } }, { y: { z: 2 } } ]))) ])
2443
+ end
2444
+
2445
+ let(:person3) do
2446
+ Person.new(addresses: [ Address.new(code: Code.new(deepest: Deepest.new(array: [ { y: { z: 1 } }, { y: { z: 3 } } ]))),
2447
+ Address.new(code: Code.new(deepest: Deepest.new(array: [ { y: { z: 1 } }, { y: { z: 3 } } ]))) ])
2448
+ end
2449
+
2450
+ let(:criteria) do
2451
+ Person.all.tap do |crit|
2452
+ crit.documents = [ person1, person2, person3 ]
2453
+ end
2454
+ end
2455
+
2456
+ let(:tally) do
2457
+ context.tally("addresses.code.deepest.array.y.z")
2458
+ end
2459
+
2460
+ it "returns the correct hash" do
2461
+ expect(tally).to eq(
2462
+ [ [ 1, 2 ], [ 1, 2 ] ] => 2,
2463
+ [ [ 1, 3 ], [ 1, 3 ] ] => 1
2464
+ )
2465
+ end
2466
+ end
2467
+
2468
+ context "when some keys are missing" do
2469
+
2470
+ let(:criteria) do
2471
+ Band.where(origin: "tally").all.tap do |crit|
2472
+ crit.documents = [ band1, band2, band3 ]
2473
+ 3.times{ crit.documents << Band.new(origin: "tally") }
2474
+ end
2475
+ end
2476
+
2477
+ let(:tally) do
2478
+ context.tally(:name)
2479
+ end
2480
+
2481
+ it "returns the correct hash" do
2482
+ expect(tally).to eq(
2483
+ "Depeche Mode" => 1,
2484
+ "New Order" => 1,
2485
+ "10,000 Maniacs" => 1,
2486
+ nil => 3
2487
+ )
2488
+ end
2489
+ end
2490
+
2491
+ context "when the first element is an embeds_one" do
2492
+ let(:person1) { Person.create!(name: Name.new(translations: [ Translation.new(language: 1), Translation.new(language: 2) ])) }
2493
+ let(:person2) { Person.create!(name: Name.new(translations: [ Translation.new(language: 1), Translation.new(language: 2) ])) }
2494
+ let(:person3) { Person.create!(name: Name.new(translations: [ Translation.new(language: 1), Translation.new(language: 3) ])) }
2495
+
2496
+ let(:criteria) do
2497
+ Person.all.tap do |crit|
2498
+ crit.documents = [ person1, person2, person3 ]
2499
+ end
2500
+ end
2501
+
2502
+ let(:tally) do
2503
+ context.tally("name.translations.language")
2504
+ end
2505
+
2506
+ it "returns the correct hash" do
2507
+ expect(tally).to eq(
2508
+ [1, 2] => 2,
2509
+ [1, 3] => 1
2510
+ )
2511
+ end
2512
+ end
2513
+ end
2514
+
1753
2515
  describe '#inc' do
1754
2516
 
1755
2517
  let(:criteria) do