mongoid 7.2.1 → 9.0.0

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 (1082) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/CHANGELOG.md +20 -20
  4. data/LICENSE +1 -1
  5. data/README.md +7 -12
  6. data/Rakefile +58 -1
  7. data/lib/config/locales/en.yml +191 -60
  8. data/lib/mongoid/association/accessors.rb +67 -53
  9. data/lib/mongoid/association/bindable.rb +77 -31
  10. data/lib/mongoid/association/builders.rb +8 -14
  11. data/lib/mongoid/association/constrainable.rb +2 -5
  12. data/lib/mongoid/association/depending.rb +20 -12
  13. data/lib/mongoid/association/eager.rb +160 -0
  14. data/lib/mongoid/association/eager_loadable.rb +41 -11
  15. data/lib/mongoid/association/embedded/batchable.rb +63 -52
  16. data/lib/mongoid/association/embedded/cyclic.rb +4 -12
  17. data/lib/mongoid/association/embedded/eager.rb +23 -0
  18. data/lib/mongoid/association/embedded/embedded_in/binding.rb +29 -13
  19. data/lib/mongoid/association/embedded/embedded_in/buildable.rb +3 -5
  20. data/lib/mongoid/association/embedded/embedded_in/proxy.rb +25 -23
  21. data/lib/mongoid/association/embedded/embedded_in.rb +11 -26
  22. data/lib/mongoid/association/embedded/embeds_many/binding.rb +4 -9
  23. data/lib/mongoid/association/embedded/embeds_many/buildable.rb +5 -6
  24. data/lib/mongoid/association/embedded/embeds_many/proxy.rb +226 -203
  25. data/lib/mongoid/association/embedded/embeds_many.rb +3 -33
  26. data/lib/mongoid/association/embedded/embeds_one/binding.rb +3 -9
  27. data/lib/mongoid/association/embedded/embeds_one/buildable.rb +20 -8
  28. data/lib/mongoid/association/embedded/embeds_one/proxy.rb +131 -42
  29. data/lib/mongoid/association/embedded/embeds_one.rb +4 -30
  30. data/lib/mongoid/association/embedded.rb +2 -1
  31. data/lib/mongoid/association/macros.rb +47 -16
  32. data/lib/mongoid/association/many.rb +12 -24
  33. data/lib/mongoid/association/marshalable.rb +4 -5
  34. data/lib/mongoid/association/nested/many.rb +14 -19
  35. data/lib/mongoid/association/nested/nested_buildable.rb +36 -13
  36. data/lib/mongoid/association/nested/one.rb +54 -26
  37. data/lib/mongoid/association/nested.rb +1 -3
  38. data/lib/mongoid/association/one.rb +3 -11
  39. data/lib/mongoid/association/options.rb +18 -44
  40. data/lib/mongoid/association/proxy.rb +49 -42
  41. data/lib/mongoid/association/referenced/auto_save.rb +11 -15
  42. data/lib/mongoid/association/referenced/belongs_to/binding.rb +2 -7
  43. data/lib/mongoid/association/referenced/belongs_to/buildable.rb +6 -6
  44. data/lib/mongoid/association/referenced/belongs_to/eager.rb +2 -2
  45. data/lib/mongoid/association/referenced/belongs_to/proxy.rb +23 -32
  46. data/lib/mongoid/association/referenced/belongs_to.rb +13 -37
  47. data/lib/mongoid/association/referenced/counter_cache.rb +18 -26
  48. data/lib/mongoid/association/referenced/has_and_belongs_to_many/binding.rb +15 -8
  49. data/lib/mongoid/association/referenced/has_and_belongs_to_many/buildable.rb +1 -3
  50. data/lib/mongoid/association/referenced/has_and_belongs_to_many/eager.rb +2 -2
  51. data/lib/mongoid/association/referenced/has_and_belongs_to_many/proxy.rb +191 -123
  52. data/lib/mongoid/association/referenced/has_and_belongs_to_many.rb +23 -42
  53. data/lib/mongoid/association/referenced/has_many/binding.rb +1 -5
  54. data/lib/mongoid/association/referenced/has_many/buildable.rb +1 -3
  55. data/lib/mongoid/association/referenced/has_many/eager.rb +2 -2
  56. data/lib/mongoid/association/referenced/has_many/enumerable.rb +471 -496
  57. data/lib/mongoid/association/referenced/has_many/proxy.rb +182 -179
  58. data/lib/mongoid/association/referenced/has_many.rb +17 -43
  59. data/lib/mongoid/association/referenced/has_one/binding.rb +1 -7
  60. data/lib/mongoid/association/referenced/has_one/buildable.rb +5 -5
  61. data/lib/mongoid/association/referenced/has_one/eager.rb +3 -4
  62. data/lib/mongoid/association/referenced/has_one/proxy.rb +38 -41
  63. data/lib/mongoid/association/referenced/has_one.rb +17 -36
  64. data/lib/mongoid/association/referenced/syncable.rb +11 -27
  65. data/lib/mongoid/association/referenced.rb +1 -1
  66. data/lib/mongoid/association/reflections.rb +9 -9
  67. data/lib/mongoid/association/relatable.rb +55 -74
  68. data/lib/mongoid/association.rb +10 -22
  69. data/lib/mongoid/atomic/modifiers.rb +7 -53
  70. data/lib/mongoid/atomic/paths/embedded/many.rb +20 -5
  71. data/lib/mongoid/atomic/paths/embedded/one.rb +1 -5
  72. data/lib/mongoid/atomic/paths/embedded.rb +1 -3
  73. data/lib/mongoid/atomic/paths/root.rb +1 -5
  74. data/lib/mongoid/atomic/paths.rb +1 -1
  75. data/lib/mongoid/atomic.rb +39 -86
  76. data/lib/mongoid/atomic_update_preparer.rb +88 -0
  77. data/lib/mongoid/attributes/dynamic.rb +5 -21
  78. data/lib/mongoid/attributes/embedded.rb +34 -0
  79. data/lib/mongoid/attributes/nested.rb +9 -13
  80. data/lib/mongoid/attributes/processing.rb +43 -28
  81. data/lib/mongoid/attributes/projector.rb +120 -0
  82. data/lib/mongoid/attributes/readonly.rb +4 -8
  83. data/lib/mongoid/attributes.rb +85 -89
  84. data/lib/mongoid/cacheable.rb +5 -9
  85. data/lib/mongoid/changeable.rb +183 -97
  86. data/lib/mongoid/clients/factory.rb +58 -15
  87. data/lib/mongoid/clients/options.rb +117 -8
  88. data/lib/mongoid/clients/sessions.rb +246 -84
  89. data/lib/mongoid/clients/storage_options.rb +37 -11
  90. data/lib/mongoid/clients/validators/storage.rb +4 -24
  91. data/lib/mongoid/clients/validators.rb +1 -1
  92. data/lib/mongoid/clients.rb +37 -14
  93. data/lib/mongoid/collection_configurable.rb +59 -0
  94. data/lib/mongoid/composable.rb +7 -7
  95. data/lib/mongoid/config/defaults.rb +40 -0
  96. data/lib/mongoid/config/encryption.rb +213 -0
  97. data/lib/mongoid/config/environment.rb +25 -5
  98. data/lib/mongoid/config/introspection.rb +152 -0
  99. data/lib/mongoid/config/options.rb +11 -14
  100. data/lib/mongoid/config/validators/async_query_executor.rb +34 -0
  101. data/lib/mongoid/config/validators/client.rb +7 -23
  102. data/lib/mongoid/config/validators/option.rb +1 -3
  103. data/lib/mongoid/config/validators.rb +2 -1
  104. data/lib/mongoid/config.rb +183 -46
  105. data/lib/mongoid/contextual/aggregable/memory.rb +38 -26
  106. data/lib/mongoid/contextual/aggregable/mongo.rb +26 -32
  107. data/lib/mongoid/contextual/aggregable/none.rb +66 -0
  108. data/lib/mongoid/contextual/aggregable.rb +18 -0
  109. data/lib/mongoid/contextual/atomic.rb +97 -30
  110. data/lib/mongoid/contextual/command.rb +3 -5
  111. data/lib/mongoid/contextual/map_reduce.rb +8 -33
  112. data/lib/mongoid/contextual/memory.rb +396 -89
  113. data/lib/mongoid/contextual/mongo/documents_loader.rb +178 -0
  114. data/lib/mongoid/contextual/mongo.rb +640 -311
  115. data/lib/mongoid/contextual/none.rb +244 -30
  116. data/lib/mongoid/contextual/queryable.rb +5 -4
  117. data/lib/mongoid/contextual.rb +18 -7
  118. data/lib/mongoid/copyable.rb +34 -14
  119. data/lib/mongoid/criteria/findable.rb +52 -22
  120. data/lib/mongoid/criteria/includable.rb +31 -34
  121. data/lib/mongoid/criteria/inspectable.rb +4 -3
  122. data/lib/mongoid/criteria/marshalable.rb +14 -7
  123. data/lib/mongoid/criteria/modifiable.rb +5 -19
  124. data/lib/mongoid/criteria/options.rb +1 -3
  125. data/lib/mongoid/criteria/permission.rb +6 -2
  126. data/lib/mongoid/criteria/queryable/aggregable.rb +3 -15
  127. data/lib/mongoid/criteria/queryable/expandable.rb +1 -25
  128. data/lib/mongoid/criteria/queryable/extensions/array.rb +6 -41
  129. data/lib/mongoid/criteria/queryable/extensions/big_decimal.rb +25 -9
  130. data/lib/mongoid/criteria/queryable/extensions/boolean.rb +5 -7
  131. data/lib/mongoid/criteria/queryable/extensions/date.rb +10 -11
  132. data/lib/mongoid/criteria/queryable/extensions/date_time.rb +8 -7
  133. data/lib/mongoid/criteria/queryable/extensions/hash.rb +3 -41
  134. data/lib/mongoid/criteria/queryable/extensions/nil_class.rb +2 -14
  135. data/lib/mongoid/criteria/queryable/extensions/numeric.rb +3 -21
  136. data/lib/mongoid/criteria/queryable/extensions/object.rb +7 -30
  137. data/lib/mongoid/criteria/queryable/extensions/range.rb +48 -17
  138. data/lib/mongoid/criteria/queryable/extensions/regexp.rb +10 -13
  139. data/lib/mongoid/criteria/queryable/extensions/set.rb +3 -5
  140. data/lib/mongoid/criteria/queryable/extensions/string.rb +19 -34
  141. data/lib/mongoid/criteria/queryable/extensions/symbol.rb +6 -22
  142. data/lib/mongoid/criteria/queryable/extensions/time.rb +8 -9
  143. data/lib/mongoid/criteria/queryable/extensions/time_with_zone.rb +9 -9
  144. data/lib/mongoid/criteria/queryable/extensions.rb +1 -5
  145. data/lib/mongoid/criteria/queryable/key.rb +15 -18
  146. data/lib/mongoid/criteria/queryable/macroable.rb +1 -3
  147. data/lib/mongoid/criteria/queryable/mergeable.rb +69 -50
  148. data/lib/mongoid/criteria/queryable/optional.rb +12 -62
  149. data/lib/mongoid/criteria/queryable/options.rb +3 -21
  150. data/lib/mongoid/criteria/queryable/pipeline.rb +2 -14
  151. data/lib/mongoid/criteria/queryable/selectable.rb +87 -124
  152. data/lib/mongoid/criteria/queryable/selector.rb +96 -25
  153. data/lib/mongoid/criteria/queryable/smash.rb +41 -18
  154. data/lib/mongoid/criteria/queryable/storable.rb +14 -9
  155. data/lib/mongoid/criteria/queryable.rb +12 -13
  156. data/lib/mongoid/criteria/scopable.rb +32 -21
  157. data/lib/mongoid/criteria/translator.rb +46 -0
  158. data/lib/mongoid/criteria.rb +60 -109
  159. data/lib/mongoid/deprecable.rb +38 -0
  160. data/lib/mongoid/deprecation.rb +29 -0
  161. data/lib/mongoid/document.rb +263 -173
  162. data/lib/mongoid/encryptable.rb +53 -0
  163. data/lib/mongoid/equality.rb +22 -25
  164. data/lib/mongoid/errors/ambiguous_relationship.rb +3 -5
  165. data/lib/mongoid/errors/attribute_not_loaded.rb +34 -0
  166. data/lib/mongoid/errors/callback.rb +1 -3
  167. data/lib/mongoid/errors/create_collection_failure.rb +34 -0
  168. data/lib/mongoid/errors/criteria_argument_required.rb +1 -1
  169. data/lib/mongoid/errors/delete_restriction.rb +9 -12
  170. data/lib/mongoid/errors/document_not_destroyed.rb +3 -7
  171. data/lib/mongoid/errors/document_not_found.rb +34 -21
  172. data/lib/mongoid/errors/drop_collection_failure.rb +28 -0
  173. data/lib/mongoid/errors/empty_config_file.rb +26 -0
  174. data/lib/mongoid/errors/immutable_attribute.rb +27 -0
  175. data/lib/mongoid/errors/in_memory_collation_not_supported.rb +1 -3
  176. data/lib/mongoid/errors/invalid_async_query_executor.rb +26 -0
  177. data/lib/mongoid/errors/invalid_auto_encryption_configuration.rb +33 -0
  178. data/lib/mongoid/errors/invalid_collection.rb +1 -1
  179. data/lib/mongoid/errors/invalid_config_file.rb +26 -0
  180. data/lib/mongoid/errors/invalid_config_option.rb +2 -4
  181. data/lib/mongoid/errors/invalid_dependent_strategy.rb +2 -4
  182. data/lib/mongoid/errors/invalid_discriminator_key_target.rb +1 -1
  183. data/lib/mongoid/errors/invalid_dot_dollar_assignment.rb +24 -0
  184. data/lib/mongoid/errors/invalid_elem_match_operator.rb +1 -1
  185. data/lib/mongoid/errors/invalid_estimated_count_criteria.rb +6 -5
  186. data/lib/mongoid/errors/invalid_estimated_count_scoping.rb +27 -0
  187. data/lib/mongoid/errors/invalid_expression_operator.rb +1 -1
  188. data/lib/mongoid/errors/invalid_field.rb +7 -7
  189. data/lib/mongoid/errors/invalid_field_operator.rb +1 -1
  190. data/lib/mongoid/errors/invalid_field_option.rb +1 -3
  191. data/lib/mongoid/errors/invalid_field_type.rb +27 -0
  192. data/lib/mongoid/errors/invalid_find.rb +1 -3
  193. data/lib/mongoid/errors/invalid_global_executor_concurrency.rb +23 -0
  194. data/lib/mongoid/errors/invalid_includes.rb +1 -3
  195. data/lib/mongoid/errors/invalid_index.rb +1 -3
  196. data/lib/mongoid/errors/invalid_options.rb +1 -3
  197. data/lib/mongoid/errors/invalid_path.rb +1 -3
  198. data/lib/mongoid/errors/invalid_persistence_option.rb +1 -5
  199. data/lib/mongoid/errors/invalid_query.rb +1 -1
  200. data/lib/mongoid/errors/invalid_relation.rb +2 -8
  201. data/lib/mongoid/errors/invalid_relation_option.rb +2 -4
  202. data/lib/mongoid/errors/invalid_scope.rb +1 -3
  203. data/lib/mongoid/errors/invalid_session_nesting.rb +17 -0
  204. data/lib/mongoid/errors/invalid_set_polymorphic_relation.rb +1 -2
  205. data/lib/mongoid/errors/invalid_storage_options.rb +2 -4
  206. data/lib/mongoid/errors/invalid_time.rb +1 -3
  207. data/lib/mongoid/errors/invalid_transaction_nesting.rb +17 -0
  208. data/lib/mongoid/errors/inverse_not_found.rb +1 -3
  209. data/lib/mongoid/errors/mixed_client_configuration.rb +1 -3
  210. data/lib/mongoid/errors/mixed_relations.rb +1 -3
  211. data/lib/mongoid/errors/mongoid_error.rb +8 -16
  212. data/lib/mongoid/errors/nested_attributes_metadata_not_found.rb +2 -4
  213. data/lib/mongoid/errors/no_client_config.rb +1 -3
  214. data/lib/mongoid/errors/no_client_database.rb +2 -4
  215. data/lib/mongoid/errors/no_client_hosts.rb +2 -4
  216. data/lib/mongoid/errors/no_clients_config.rb +1 -3
  217. data/lib/mongoid/errors/no_default_client.rb +1 -3
  218. data/lib/mongoid/errors/no_environment.rb +1 -3
  219. data/lib/mongoid/errors/no_map_reduce_output.rb +1 -3
  220. data/lib/mongoid/errors/no_metadata.rb +1 -3
  221. data/lib/mongoid/errors/no_parent.rb +1 -3
  222. data/lib/mongoid/errors/readonly_attribute.rb +2 -4
  223. data/lib/mongoid/errors/readonly_document.rb +2 -6
  224. data/lib/mongoid/errors/rollback.rb +15 -0
  225. data/lib/mongoid/errors/scope_overwrite.rb +1 -1
  226. data/lib/mongoid/errors/sessions_not_supported.rb +17 -0
  227. data/lib/mongoid/errors/too_many_nested_attribute_records.rb +2 -2
  228. data/lib/mongoid/errors/transaction_error.rb +25 -0
  229. data/lib/mongoid/errors/transactions_not_supported.rb +17 -0
  230. data/lib/mongoid/errors/unknown_attribute.rb +2 -4
  231. data/lib/mongoid/errors/unknown_model.rb +1 -3
  232. data/lib/mongoid/errors/unsaved_document.rb +2 -2
  233. data/lib/mongoid/errors/unsupported_javascript.rb +1 -3
  234. data/lib/mongoid/errors/validations.rb +1 -1
  235. data/lib/mongoid/errors.rb +18 -5
  236. data/lib/mongoid/evolvable.rb +2 -4
  237. data/lib/mongoid/extensions/array.rb +20 -58
  238. data/lib/mongoid/extensions/big_decimal.rb +44 -24
  239. data/lib/mongoid/extensions/binary.rb +45 -0
  240. data/lib/mongoid/extensions/boolean.rb +11 -6
  241. data/lib/mongoid/extensions/date.rb +31 -29
  242. data/lib/mongoid/extensions/date_time.rb +5 -16
  243. data/lib/mongoid/extensions/decimal128.rb +3 -5
  244. data/lib/mongoid/extensions/false_class.rb +8 -10
  245. data/lib/mongoid/extensions/float.rb +11 -12
  246. data/lib/mongoid/extensions/hash.rb +28 -148
  247. data/lib/mongoid/extensions/integer.rb +13 -14
  248. data/lib/mongoid/extensions/module.rb +5 -5
  249. data/lib/mongoid/extensions/nil_class.rb +5 -7
  250. data/lib/mongoid/extensions/object.rb +32 -81
  251. data/lib/mongoid/extensions/object_id.rb +3 -7
  252. data/lib/mongoid/extensions/range.rb +47 -24
  253. data/lib/mongoid/extensions/raw_value.rb +34 -0
  254. data/lib/mongoid/extensions/regexp.rb +14 -7
  255. data/lib/mongoid/extensions/set.rb +24 -13
  256. data/lib/mongoid/extensions/string.rb +30 -62
  257. data/lib/mongoid/extensions/symbol.rb +9 -22
  258. data/lib/mongoid/extensions/time.rb +30 -40
  259. data/lib/mongoid/extensions/time_with_zone.rb +18 -11
  260. data/lib/mongoid/extensions/true_class.rb +8 -10
  261. data/lib/mongoid/extensions.rb +3 -20
  262. data/lib/mongoid/factory.rb +178 -37
  263. data/lib/mongoid/fields/encrypted.rb +48 -0
  264. data/lib/mongoid/fields/foreign_key.rb +39 -27
  265. data/lib/mongoid/fields/localized.rb +25 -15
  266. data/lib/mongoid/fields/standard.rb +22 -40
  267. data/lib/mongoid/fields/validators/macro.rb +6 -19
  268. data/lib/mongoid/fields/validators.rb +1 -1
  269. data/lib/mongoid/fields.rb +354 -76
  270. data/lib/mongoid/findable.rb +62 -22
  271. data/lib/mongoid/indexable/specification.rb +55 -34
  272. data/lib/mongoid/indexable/validators/options.rb +7 -9
  273. data/lib/mongoid/indexable.rb +2 -18
  274. data/lib/mongoid/inspectable.rb +34 -11
  275. data/lib/mongoid/interceptable.rb +197 -41
  276. data/lib/mongoid/loadable.rb +83 -0
  277. data/lib/mongoid/loggable.rb +1 -9
  278. data/lib/mongoid/matchable.rb +2 -6
  279. data/lib/mongoid/matcher/all.rb +15 -0
  280. data/lib/mongoid/matcher/and.rb +14 -0
  281. data/lib/mongoid/matcher/bits.rb +60 -0
  282. data/lib/mongoid/matcher/bits_all_clear.rb +41 -0
  283. data/lib/mongoid/matcher/bits_all_set.rb +41 -0
  284. data/lib/mongoid/matcher/bits_any_clear.rb +41 -0
  285. data/lib/mongoid/matcher/bits_any_set.rb +41 -0
  286. data/lib/mongoid/matcher/elem_match.rb +17 -1
  287. data/lib/mongoid/matcher/elem_match_expression.rb +14 -2
  288. data/lib/mongoid/matcher/eq.rb +15 -0
  289. data/lib/mongoid/matcher/eq_impl.rb +54 -2
  290. data/lib/mongoid/matcher/eq_impl_with_regexp.rb +18 -1
  291. data/lib/mongoid/matcher/exists.rb +15 -0
  292. data/lib/mongoid/matcher/expression.rb +22 -14
  293. data/lib/mongoid/matcher/expression_operator.rb +14 -0
  294. data/lib/mongoid/matcher/field_expression.rb +19 -5
  295. data/lib/mongoid/matcher/field_operator.rb +30 -0
  296. data/lib/mongoid/matcher/gt.rb +15 -0
  297. data/lib/mongoid/matcher/gte.rb +15 -0
  298. data/lib/mongoid/matcher/in.rb +15 -0
  299. data/lib/mongoid/matcher/lt.rb +15 -0
  300. data/lib/mongoid/matcher/lte.rb +15 -0
  301. data/lib/mongoid/matcher/mod.rb +33 -0
  302. data/lib/mongoid/matcher/ne.rb +15 -0
  303. data/lib/mongoid/matcher/nin.rb +15 -0
  304. data/lib/mongoid/matcher/nor.rb +14 -0
  305. data/lib/mongoid/matcher/not.rb +16 -0
  306. data/lib/mongoid/matcher/or.rb +14 -0
  307. data/lib/mongoid/matcher/regex.rb +24 -0
  308. data/lib/mongoid/matcher/size.rb +16 -0
  309. data/lib/mongoid/matcher/type.rb +124 -0
  310. data/lib/mongoid/matcher.rb +59 -52
  311. data/lib/mongoid/persistable/creatable.rb +25 -29
  312. data/lib/mongoid/persistable/deletable.rb +10 -23
  313. data/lib/mongoid/persistable/destroyable.rb +37 -11
  314. data/lib/mongoid/persistable/incrementable.rb +2 -6
  315. data/lib/mongoid/persistable/logical.rb +1 -5
  316. data/lib/mongoid/persistable/maxable.rb +37 -0
  317. data/lib/mongoid/persistable/minable.rb +37 -0
  318. data/lib/mongoid/persistable/multipliable.rb +36 -0
  319. data/lib/mongoid/persistable/poppable.rb +1 -5
  320. data/lib/mongoid/persistable/pullable.rb +1 -7
  321. data/lib/mongoid/persistable/pushable.rb +1 -7
  322. data/lib/mongoid/persistable/renamable.rb +1 -5
  323. data/lib/mongoid/persistable/savable.rb +14 -8
  324. data/lib/mongoid/persistable/settable.rb +1 -5
  325. data/lib/mongoid/persistable/unsettable.rb +3 -7
  326. data/lib/mongoid/persistable/updatable.rb +114 -28
  327. data/lib/mongoid/persistable/upsertable.rb +33 -8
  328. data/lib/mongoid/persistable.rb +17 -27
  329. data/lib/mongoid/persistence_context.rb +111 -43
  330. data/lib/mongoid/positional.rb +1 -5
  331. data/lib/mongoid/railtie.rb +23 -15
  332. data/lib/mongoid/railties/bson_object_id_serializer.rb +39 -0
  333. data/lib/mongoid/railties/console_sandbox.rb +42 -0
  334. data/lib/mongoid/railties/controller_runtime.rb +21 -6
  335. data/lib/mongoid/railties/database.rake +19 -2
  336. data/lib/mongoid/reloadable.rb +45 -42
  337. data/lib/mongoid/scopable.rb +25 -53
  338. data/lib/mongoid/search_indexable.rb +167 -0
  339. data/lib/mongoid/selectable.rb +6 -17
  340. data/lib/mongoid/serializable.rb +11 -21
  341. data/lib/mongoid/shardable.rb +50 -16
  342. data/lib/mongoid/stateful.rb +66 -22
  343. data/lib/mongoid/stringified_symbol.rb +19 -7
  344. data/lib/mongoid/tasks/database.rake +25 -0
  345. data/lib/mongoid/tasks/database.rb +84 -8
  346. data/lib/mongoid/tasks/encryption.rake +59 -0
  347. data/lib/mongoid/tasks/encryption.rb +108 -0
  348. data/lib/mongoid/threaded/lifecycle.rb +6 -26
  349. data/lib/mongoid/threaded.rb +131 -92
  350. data/lib/mongoid/timestamps/created/short.rb +1 -1
  351. data/lib/mongoid/timestamps/created.rb +4 -4
  352. data/lib/mongoid/timestamps/short.rb +1 -1
  353. data/lib/mongoid/timestamps/timeless.rb +29 -7
  354. data/lib/mongoid/timestamps/updated/short.rb +1 -1
  355. data/lib/mongoid/timestamps/updated.rb +3 -5
  356. data/lib/mongoid/timestamps.rb +1 -1
  357. data/lib/mongoid/touchable.rb +155 -29
  358. data/lib/mongoid/traversable.rb +180 -125
  359. data/lib/mongoid/utils.rb +52 -0
  360. data/lib/mongoid/validatable/associated.rb +97 -21
  361. data/lib/mongoid/validatable/format.rb +1 -1
  362. data/lib/mongoid/validatable/length.rb +1 -1
  363. data/lib/mongoid/validatable/localizable.rb +2 -4
  364. data/lib/mongoid/validatable/macros.rb +10 -14
  365. data/lib/mongoid/validatable/presence.rb +7 -13
  366. data/lib/mongoid/validatable/queryable.rb +9 -3
  367. data/lib/mongoid/validatable/uniqueness.rb +26 -39
  368. data/lib/mongoid/validatable.rb +20 -29
  369. data/lib/mongoid/version.rb +2 -2
  370. data/lib/mongoid/warnings.rb +37 -0
  371. data/lib/mongoid.rb +56 -22
  372. data/lib/rails/generators/mongoid/config/config_generator.rb +25 -5
  373. data/lib/rails/generators/mongoid/config/templates/mongoid.rb +25 -0
  374. data/lib/rails/generators/mongoid/config/templates/mongoid.yml +44 -64
  375. data/lib/rails/generators/mongoid/model/model_generator.rb +4 -1
  376. data/lib/rails/generators/mongoid_generator.rb +13 -1
  377. data/lib/rails/mongoid.rb +4 -32
  378. data/spec/config/mongoid.yml +16 -1
  379. data/spec/config/mongoid_with_schema_map_uuid.yml +27 -0
  380. data/spec/integration/active_job_spec.rb +32 -0
  381. data/spec/integration/app_spec.rb +180 -89
  382. data/spec/integration/associations/belongs_to_spec.rb +19 -1
  383. data/spec/integration/associations/embedded_dirty_spec.rb +58 -0
  384. data/spec/integration/associations/embedded_spec.rb +90 -7
  385. data/spec/integration/associations/embeds_many_spec.rb +197 -1
  386. data/spec/integration/associations/embeds_one_spec.rb +19 -1
  387. data/spec/integration/associations/foreign_key_spec.rb +10 -1
  388. data/spec/integration/associations/foreign_key_spec_models.rb +1 -1
  389. data/spec/integration/associations/has_and_belongs_to_many_spec.rb +62 -0
  390. data/spec/integration/associations/has_many_spec.rb +1 -1
  391. data/spec/integration/associations/has_one_spec.rb +145 -1
  392. data/spec/integration/associations/nested_attributes_assignment_spec.rb +1 -1
  393. data/spec/integration/associations/reverse_population_spec.rb +1 -1
  394. data/spec/integration/associations/reverse_population_spec_models.rb +1 -1
  395. data/spec/integration/associations/scope_option_spec.rb +102 -0
  396. data/spec/integration/atomic/modifiers_spec.rb +1 -1
  397. data/spec/integration/bson_regexp_raw_spec.rb +1 -1
  398. data/spec/integration/callbacks_models.rb +147 -3
  399. data/spec/integration/callbacks_spec.rb +398 -8
  400. data/spec/integration/contextual/empty_spec.rb +142 -0
  401. data/spec/integration/criteria/alias_query_spec.rb +98 -0
  402. data/spec/integration/criteria/date_field_spec.rb +2 -2
  403. data/spec/integration/criteria/default_scope_spec.rb +52 -0
  404. data/spec/integration/criteria/logical_spec.rb +12 -0
  405. data/spec/integration/criteria/range_spec.rb +358 -0
  406. data/spec/integration/criteria/raw_value_spec.rb +525 -0
  407. data/spec/integration/criteria/time_with_zone_spec.rb +126 -15
  408. data/spec/integration/discriminator_key_spec.rb +119 -81
  409. data/spec/integration/discriminator_value_spec.rb +1 -1
  410. data/spec/integration/document_spec.rb +31 -1
  411. data/spec/integration/dots_and_dollars_spec.rb +278 -0
  412. data/spec/integration/encryption_spec.rb +100 -0
  413. data/spec/integration/i18n_fallbacks_spec.rb +10 -52
  414. data/spec/integration/matcher_examples_spec.rb +21 -14
  415. data/spec/integration/matcher_operator_data/bits_all_clear.yml +144 -0
  416. data/spec/integration/matcher_operator_data/bits_all_set.yml +144 -0
  417. data/spec/integration/matcher_operator_data/bits_any_clear.yml +144 -0
  418. data/spec/integration/matcher_operator_data/bits_any_set.yml +144 -0
  419. data/spec/integration/matcher_operator_data/comment.yml +22 -0
  420. data/spec/integration/matcher_operator_data/elem_match.yml +46 -0
  421. data/spec/integration/matcher_operator_data/implicit_traversal.yml +96 -0
  422. data/spec/integration/matcher_operator_data/in.yml +16 -0
  423. data/spec/integration/matcher_operator_data/mod.yml +55 -0
  424. data/spec/integration/matcher_operator_data/size.yml +0 -3
  425. data/spec/integration/matcher_operator_data/type.yml +64 -0
  426. data/spec/integration/matcher_operator_data/type_array.yml +15 -0
  427. data/spec/integration/matcher_operator_data/type_binary.yml +18 -0
  428. data/spec/integration/matcher_operator_data/type_boolean.yml +39 -0
  429. data/spec/integration/matcher_operator_data/type_code.yml +26 -0
  430. data/spec/integration/matcher_operator_data/type_code_with_scope.yml +26 -0
  431. data/spec/integration/matcher_operator_data/type_date.yml +39 -0
  432. data/spec/integration/matcher_operator_data/type_db_pointer.yml +19 -0
  433. data/spec/integration/matcher_operator_data/type_decimal.yml +37 -0
  434. data/spec/integration/matcher_operator_data/type_double.yml +15 -0
  435. data/spec/integration/matcher_operator_data/type_int32.yml +33 -0
  436. data/spec/integration/matcher_operator_data/type_int64.yml +33 -0
  437. data/spec/integration/matcher_operator_data/type_max_key.yml +17 -0
  438. data/spec/integration/matcher_operator_data/type_min_key.yml +17 -0
  439. data/spec/integration/matcher_operator_data/type_null.yml +23 -0
  440. data/spec/integration/matcher_operator_data/type_object.yml +23 -0
  441. data/spec/integration/matcher_operator_data/type_object_id.yml +25 -0
  442. data/spec/integration/matcher_operator_data/type_regex.yml +44 -0
  443. data/spec/integration/matcher_operator_data/type_string.yml +15 -0
  444. data/spec/integration/matcher_operator_data/type_symbol.yml +32 -0
  445. data/spec/integration/matcher_operator_data/type_timestamp.yml +25 -0
  446. data/spec/integration/matcher_operator_data/type_undefined.yml +17 -0
  447. data/spec/integration/matcher_operator_spec.rb +26 -3
  448. data/spec/integration/matcher_spec.rb +50 -1
  449. data/spec/integration/persistence/range_field_spec.rb +351 -0
  450. data/spec/integration/server_query_spec.rb +1 -1
  451. data/spec/integration/shardable_spec.rb +1 -1
  452. data/spec/integration/stringified_symbol_field_spec.rb +17 -3
  453. data/spec/lite_spec_helper.rb +47 -14
  454. data/spec/mongoid/association/accessors_spec.rb +31 -19
  455. data/spec/mongoid/association/auto_save_spec.rb +73 -34
  456. data/spec/mongoid/association/builders_spec.rb +2 -2
  457. data/spec/mongoid/association/constrainable_spec.rb +1 -1
  458. data/spec/mongoid/association/counter_cache_spec.rb +34 -34
  459. data/spec/mongoid/association/depending_spec.rb +397 -358
  460. data/spec/mongoid/association/eager_spec.rb +56 -6
  461. data/spec/mongoid/association/embedded/cyclic_spec.rb +3 -3
  462. data/spec/mongoid/association/embedded/dirty_spec.rb +3 -3
  463. data/spec/mongoid/association/embedded/embedded_in/binding_spec.rb +3 -2
  464. data/spec/mongoid/association/embedded/embedded_in/buildable_spec.rb +55 -1
  465. data/spec/mongoid/association/embedded/embedded_in/proxy_spec.rb +110 -23
  466. data/spec/mongoid/association/embedded/embedded_in_spec.rb +19 -8
  467. data/spec/mongoid/association/embedded/embeds_many/binding_spec.rb +1 -1
  468. data/spec/mongoid/association/embedded/embeds_many/buildable_spec.rb +113 -1
  469. data/spec/mongoid/association/embedded/embeds_many/proxy_spec.rb +712 -203
  470. data/spec/mongoid/association/embedded/embeds_many_models.rb +189 -1
  471. data/spec/mongoid/association/embedded/embeds_many_query_spec.rb +14 -2
  472. data/spec/mongoid/association/embedded/embeds_many_spec.rb +69 -1
  473. data/spec/mongoid/association/embedded/embeds_one/binding_spec.rb +1 -1
  474. data/spec/mongoid/association/embedded/embeds_one/buildable_spec.rb +26 -1
  475. data/spec/mongoid/association/embedded/embeds_one/proxy_spec.rb +37 -24
  476. data/spec/mongoid/association/embedded/embeds_one_dnl_models.rb +1 -1
  477. data/spec/mongoid/association/embedded/embeds_one_models.rb +25 -2
  478. data/spec/mongoid/association/embedded/embeds_one_query_spec.rb +2 -2
  479. data/spec/mongoid/association/embedded/embeds_one_spec.rb +29 -1
  480. data/spec/mongoid/association/macros_spec.rb +10 -10
  481. data/spec/mongoid/association/nested/many_spec.rb +1 -1
  482. data/spec/mongoid/association/nested/one_spec.rb +17 -13
  483. data/spec/mongoid/association/options_spec.rb +1 -1
  484. data/spec/mongoid/association/polymorphic_spec.rb +1 -1
  485. data/spec/mongoid/association/referenced/belongs_to/binding_spec.rb +3 -2
  486. data/spec/mongoid/association/referenced/belongs_to/buildable_spec.rb +110 -17
  487. data/spec/mongoid/association/referenced/belongs_to/eager_spec.rb +51 -15
  488. data/spec/mongoid/association/referenced/belongs_to/proxy_spec.rb +113 -59
  489. data/spec/mongoid/association/referenced/belongs_to_models.rb +12 -0
  490. data/spec/mongoid/association/referenced/belongs_to_query_spec.rb +22 -2
  491. data/spec/mongoid/association/referenced/belongs_to_spec.rb +27 -22
  492. data/spec/mongoid/association/referenced/has_and_belongs_to_many/binding_spec.rb +2 -2
  493. data/spec/mongoid/association/referenced/has_and_belongs_to_many/buildable_spec.rb +28 -3
  494. data/spec/mongoid/association/referenced/has_and_belongs_to_many/eager_spec.rb +32 -3
  495. data/spec/mongoid/association/referenced/has_and_belongs_to_many/proxy_persistence_spec.rb +1 -1
  496. data/spec/mongoid/association/referenced/has_and_belongs_to_many/proxy_spec.rb +386 -376
  497. data/spec/mongoid/association/referenced/has_and_belongs_to_many_models.rb +44 -1
  498. data/spec/mongoid/association/referenced/has_and_belongs_to_many_query_spec.rb +2 -2
  499. data/spec/mongoid/association/referenced/has_and_belongs_to_many_spec.rb +57 -3
  500. data/spec/mongoid/association/referenced/has_many/binding_spec.rb +2 -2
  501. data/spec/mongoid/association/referenced/has_many/buildable_spec.rb +131 -1
  502. data/spec/mongoid/association/referenced/has_many/eager_spec.rb +24 -7
  503. data/spec/mongoid/association/referenced/has_many/enumerable_spec.rb +313 -134
  504. data/spec/mongoid/association/referenced/has_many/proxy_query_spec.rb +1 -1
  505. data/spec/mongoid/association/referenced/has_many/proxy_spec.rb +1313 -2109
  506. data/spec/mongoid/association/referenced/has_many_models.rb +39 -2
  507. data/spec/mongoid/association/referenced/has_many_query_spec.rb +2 -2
  508. data/spec/mongoid/association/referenced/has_many_spec.rb +47 -1
  509. data/spec/mongoid/association/referenced/has_one/binding_spec.rb +1 -1
  510. data/spec/mongoid/association/referenced/has_one/buildable_spec.rb +54 -10
  511. data/spec/mongoid/association/referenced/has_one/eager_spec.rb +18 -2
  512. data/spec/mongoid/association/referenced/has_one/proxy_spec.rb +134 -28
  513. data/spec/mongoid/association/referenced/has_one_models.rb +43 -1
  514. data/spec/mongoid/association/referenced/has_one_query_spec.rb +2 -2
  515. data/spec/mongoid/association/referenced/has_one_spec.rb +22 -1
  516. data/spec/mongoid/association/reflections_spec.rb +1 -1
  517. data/spec/mongoid/association/syncable_spec.rb +47 -33
  518. data/spec/mongoid/association_spec.rb +1 -1
  519. data/spec/mongoid/atomic/modifiers_spec.rb +1 -1
  520. data/spec/mongoid/atomic/paths/embedded/many_spec.rb +1 -1
  521. data/spec/mongoid/atomic/paths/embedded/one_spec.rb +1 -1
  522. data/spec/mongoid/atomic/paths/root_spec.rb +1 -1
  523. data/spec/mongoid/atomic/paths_spec.rb +65 -27
  524. data/spec/mongoid/atomic_spec.rb +29 -7
  525. data/spec/mongoid/atomic_update_preparer_spec.rb +83 -0
  526. data/spec/mongoid/attributes/dynamic_spec.rb +1 -1
  527. data/spec/mongoid/attributes/embedded_spec.rb +118 -0
  528. data/spec/mongoid/attributes/nested_spec.rb +147 -78
  529. data/spec/mongoid/attributes/nested_spec_models.rb +49 -0
  530. data/spec/mongoid/attributes/projector_data/embedded.yml +105 -0
  531. data/spec/mongoid/attributes/projector_data/fields.yml +93 -0
  532. data/spec/mongoid/attributes/projector_spec.rb +41 -0
  533. data/spec/mongoid/attributes/readonly_spec.rb +23 -23
  534. data/spec/mongoid/attributes_spec.rb +921 -69
  535. data/spec/mongoid/cacheable_spec.rb +5 -5
  536. data/spec/mongoid/changeable_spec.rb +468 -76
  537. data/spec/mongoid/clients/factory_spec.rb +152 -30
  538. data/spec/mongoid/clients/options_spec.rb +24 -12
  539. data/spec/mongoid/clients/sessions_spec.rb +49 -71
  540. data/spec/mongoid/clients/transactions_spec.rb +971 -176
  541. data/spec/mongoid/clients/transactions_spec_models.rb +159 -0
  542. data/spec/mongoid/clients_spec.rb +230 -22
  543. data/spec/mongoid/collection_configurable_spec.rb +159 -0
  544. data/spec/mongoid/composable_spec.rb +1 -1
  545. data/spec/mongoid/config/defaults_spec.rb +99 -0
  546. data/spec/mongoid/config/encryption_spec.rb +152 -0
  547. data/spec/mongoid/config/environment_spec.rb +126 -39
  548. data/spec/mongoid/config/introspection_spec.rb +114 -0
  549. data/spec/mongoid/config/options_spec.rb +1 -1
  550. data/spec/mongoid/config_spec.rb +375 -43
  551. data/spec/mongoid/contextual/aggregable/memory_spec.rb +432 -154
  552. data/spec/mongoid/contextual/aggregable/memory_table.yml +88 -0
  553. data/spec/mongoid/contextual/aggregable/memory_table_spec.rb +63 -0
  554. data/spec/mongoid/contextual/aggregable/mongo_spec.rb +95 -20
  555. data/spec/mongoid/contextual/aggregable/none_spec.rb +49 -0
  556. data/spec/mongoid/contextual/atomic_spec.rb +329 -87
  557. data/spec/mongoid/contextual/map_reduce_spec.rb +5 -19
  558. data/spec/mongoid/contextual/memory_spec.rb +1479 -127
  559. data/spec/mongoid/contextual/mongo/documents_loader_spec.rb +194 -0
  560. data/spec/mongoid/contextual/mongo_spec.rb +3374 -1254
  561. data/spec/mongoid/contextual/none_spec.rb +79 -68
  562. data/spec/mongoid/copyable_spec.rb +465 -23
  563. data/spec/mongoid/copyable_spec_models.rb +1 -1
  564. data/spec/mongoid/criteria/findable_spec.rb +295 -229
  565. data/spec/mongoid/criteria/includable_spec.rb +1493 -0
  566. data/spec/mongoid/criteria/includable_spec_models.rb +55 -0
  567. data/spec/mongoid/criteria/inspectable_spec.rb +1 -1
  568. data/spec/mongoid/criteria/marshalable_spec.rb +19 -2
  569. data/spec/mongoid/criteria/modifiable_spec.rb +38 -38
  570. data/spec/mongoid/criteria/options_spec.rb +1 -1
  571. data/spec/mongoid/criteria/queryable/aggregable_spec.rb +2 -2
  572. data/spec/mongoid/criteria/queryable/expandable_spec.rb +1 -74
  573. data/spec/mongoid/criteria/queryable/extensions/array_spec.rb +8 -20
  574. data/spec/mongoid/criteria/queryable/extensions/big_decimal_spec.rb +135 -27
  575. data/spec/mongoid/criteria/queryable/extensions/boolean_spec.rb +2 -2
  576. data/spec/mongoid/criteria/queryable/extensions/date_spec.rb +32 -12
  577. data/spec/mongoid/criteria/queryable/extensions/date_time_spec.rb +12 -1
  578. data/spec/mongoid/criteria/queryable/extensions/float_spec.rb +1 -1
  579. data/spec/mongoid/criteria/queryable/extensions/hash_spec.rb +1 -16
  580. data/spec/mongoid/criteria/queryable/extensions/integer_spec.rb +1 -1
  581. data/spec/mongoid/criteria/queryable/extensions/nil_class_spec.rb +1 -1
  582. data/spec/mongoid/criteria/queryable/extensions/numeric_spec.rb +74 -8
  583. data/spec/mongoid/criteria/queryable/extensions/object_spec.rb +1 -1
  584. data/spec/mongoid/criteria/queryable/extensions/range_spec.rb +238 -179
  585. data/spec/mongoid/criteria/queryable/extensions/regexp_raw_spec.rb +1 -12
  586. data/spec/mongoid/criteria/queryable/extensions/regexp_spec.rb +1 -12
  587. data/spec/mongoid/criteria/queryable/extensions/set_spec.rb +1 -1
  588. data/spec/mongoid/criteria/queryable/extensions/string_spec.rb +48 -132
  589. data/spec/mongoid/criteria/queryable/extensions/symbol_spec.rb +5 -60
  590. data/spec/mongoid/criteria/queryable/extensions/time_spec.rb +12 -1
  591. data/spec/mongoid/criteria/queryable/extensions/time_with_zone_spec.rb +12 -1
  592. data/spec/mongoid/criteria/queryable/key_spec.rb +1 -1
  593. data/spec/mongoid/criteria/queryable/mergeable_spec.rb +106 -8
  594. data/spec/mongoid/criteria/queryable/optional_spec.rb +17 -486
  595. data/spec/mongoid/criteria/queryable/options_spec.rb +2 -2
  596. data/spec/mongoid/criteria/queryable/pipeline_spec.rb +1 -1
  597. data/spec/mongoid/criteria/queryable/queryable_spec.rb +2 -2
  598. data/spec/mongoid/criteria/queryable/selectable_logical_spec.rb +700 -26
  599. data/spec/mongoid/criteria/queryable/selectable_shared_examples.rb +39 -0
  600. data/spec/mongoid/criteria/queryable/selectable_spec.rb +149 -683
  601. data/spec/mongoid/criteria/queryable/selectable_where_spec.rb +590 -0
  602. data/spec/mongoid/criteria/queryable/selector_spec.rb +186 -6
  603. data/spec/mongoid/criteria/queryable/smash_spec.rb +1 -1
  604. data/spec/mongoid/criteria/queryable/storable_spec.rb +87 -1
  605. data/spec/mongoid/criteria/scopable_spec.rb +128 -1
  606. data/spec/mongoid/criteria/translator_spec.rb +133 -0
  607. data/spec/mongoid/criteria_projection_spec.rb +407 -0
  608. data/spec/mongoid/criteria_spec.rb +1029 -1806
  609. data/spec/mongoid/document_fields_spec.rb +180 -5
  610. data/spec/mongoid/document_persistence_context_spec.rb +77 -1
  611. data/spec/mongoid/document_query_spec.rb +55 -4
  612. data/spec/mongoid/document_spec.rb +43 -172
  613. data/spec/mongoid/equality_spec.rb +7 -8
  614. data/spec/mongoid/errors/ambiguous_relationship_spec.rb +1 -1
  615. data/spec/mongoid/errors/attribute_not_loaded_spec.rb +32 -0
  616. data/spec/mongoid/errors/callback_spec.rb +1 -1
  617. data/spec/mongoid/errors/delete_restriction_spec.rb +2 -2
  618. data/spec/mongoid/errors/document_not_destroyed_spec.rb +1 -1
  619. data/spec/mongoid/errors/document_not_found_spec.rb +77 -1
  620. data/spec/mongoid/errors/invalid_collection_spec.rb +1 -1
  621. data/spec/mongoid/errors/{eager_load_spec.rb → invalid_config_file_spec.rb} +6 -6
  622. data/spec/mongoid/errors/invalid_config_option_spec.rb +1 -1
  623. data/spec/mongoid/errors/invalid_field_option_spec.rb +1 -1
  624. data/spec/mongoid/errors/invalid_field_spec.rb +2 -2
  625. data/spec/mongoid/errors/invalid_field_type_spec.rb +56 -0
  626. data/spec/mongoid/errors/invalid_find_spec.rb +1 -1
  627. data/spec/mongoid/errors/invalid_includes_spec.rb +1 -1
  628. data/spec/mongoid/errors/invalid_index_spec.rb +1 -1
  629. data/spec/mongoid/errors/invalid_options_spec.rb +1 -1
  630. data/spec/mongoid/errors/invalid_path_spec.rb +1 -1
  631. data/spec/mongoid/errors/invalid_relation_spec.rb +1 -1
  632. data/spec/mongoid/errors/invalid_scope_spec.rb +2 -2
  633. data/spec/mongoid/errors/invalid_set_polymorphic_relation_spec.rb +1 -1
  634. data/spec/mongoid/errors/invalid_storage_options_spec.rb +1 -1
  635. data/spec/mongoid/errors/invalid_time_spec.rb +1 -1
  636. data/spec/mongoid/errors/inverse_not_found_spec.rb +1 -1
  637. data/spec/mongoid/errors/mixed_client_configuration_spec.rb +1 -1
  638. data/spec/mongoid/errors/mixed_relations_spec.rb +1 -1
  639. data/spec/mongoid/errors/mongoid_error_spec.rb +4 -4
  640. data/spec/mongoid/errors/nested_attributes_metadata_not_found_spec.rb +1 -1
  641. data/spec/mongoid/errors/no_client_config_spec.rb +1 -1
  642. data/spec/mongoid/errors/no_client_database_spec.rb +1 -1
  643. data/spec/mongoid/errors/no_client_hosts_spec.rb +1 -1
  644. data/spec/mongoid/errors/no_clients_config_spec.rb +1 -1
  645. data/spec/mongoid/errors/no_environment_spec.rb +4 -4
  646. data/spec/mongoid/errors/no_map_reduce_output_spec.rb +1 -1
  647. data/spec/mongoid/errors/no_metadata_spec.rb +1 -1
  648. data/spec/mongoid/errors/no_parent_spec.rb +1 -1
  649. data/spec/mongoid/errors/readonly_attribute_spec.rb +1 -1
  650. data/spec/mongoid/errors/readonly_document_spec.rb +3 -3
  651. data/spec/mongoid/errors/scope_overwrite_spec.rb +1 -1
  652. data/spec/mongoid/errors/too_many_nested_attribute_records_spec.rb +2 -2
  653. data/spec/mongoid/errors/unknown_attribute_spec.rb +3 -3
  654. data/spec/mongoid/errors/unsaved_document_spec.rb +1 -1
  655. data/spec/mongoid/errors/unsupported_javascript_spec.rb +1 -1
  656. data/spec/mongoid/errors/validations_spec.rb +1 -1
  657. data/spec/mongoid/extensions/array_spec.rb +19 -265
  658. data/spec/mongoid/extensions/big_decimal_spec.rb +713 -213
  659. data/spec/mongoid/extensions/binary_spec.rb +45 -10
  660. data/spec/mongoid/extensions/boolean_spec.rb +69 -83
  661. data/spec/mongoid/extensions/date_class_mongoize_spec.rb +15 -11
  662. data/spec/mongoid/extensions/date_spec.rb +74 -22
  663. data/spec/mongoid/extensions/date_time_spec.rb +18 -19
  664. data/spec/mongoid/extensions/decimal128_spec.rb +1 -1
  665. data/spec/mongoid/extensions/false_class_spec.rb +2 -9
  666. data/spec/mongoid/extensions/float_spec.rb +56 -84
  667. data/spec/mongoid/extensions/hash_spec.rb +45 -219
  668. data/spec/mongoid/extensions/integer_spec.rb +53 -73
  669. data/spec/mongoid/extensions/module_spec.rb +1 -1
  670. data/spec/mongoid/extensions/nil_class_spec.rb +1 -1
  671. data/spec/mongoid/extensions/object_id_spec.rb +1 -1
  672. data/spec/mongoid/extensions/object_spec.rb +1 -177
  673. data/spec/mongoid/extensions/range_spec.rb +254 -64
  674. data/spec/mongoid/extensions/raw_value_spec.rb +67 -0
  675. data/spec/mongoid/extensions/regexp_spec.rb +59 -34
  676. data/spec/mongoid/extensions/set_spec.rb +105 -1
  677. data/spec/mongoid/extensions/string_spec.rb +21 -104
  678. data/spec/mongoid/extensions/stringified_symbol_spec.rb +1 -1
  679. data/spec/mongoid/extensions/symbol_spec.rb +15 -53
  680. data/spec/mongoid/extensions/time_spec.rb +345 -131
  681. data/spec/mongoid/extensions/time_with_zone_spec.rb +34 -107
  682. data/spec/mongoid/extensions/true_class_spec.rb +2 -9
  683. data/spec/mongoid/factory_spec.rb +63 -2
  684. data/spec/mongoid/fields/foreign_key_spec.rb +282 -120
  685. data/spec/mongoid/fields/localized_spec.rb +85 -42
  686. data/spec/mongoid/fields/standard_spec.rb +1 -1
  687. data/spec/mongoid/fields_spec.rb +826 -121
  688. data/spec/mongoid/findable_spec.rb +442 -80
  689. data/spec/mongoid/indexable/specification_spec.rb +132 -14
  690. data/spec/mongoid/indexable_spec.rb +361 -23
  691. data/spec/mongoid/inspectable_spec.rb +93 -5
  692. data/spec/mongoid/interceptable_spec.rb +926 -116
  693. data/spec/mongoid/interceptable_spec_models.rb +236 -4
  694. data/spec/mongoid/loading_spec.rb +110 -0
  695. data/spec/mongoid/loggable_spec.rb +1 -1
  696. data/spec/mongoid/matcher/extract_attribute_data/numeric_keys.yml +104 -0
  697. data/spec/mongoid/matcher/extract_attribute_data/traversal.yml +68 -88
  698. data/spec/mongoid/matcher/extract_attribute_spec.rb +5 -15
  699. data/spec/mongoid/mongoizable_spec.rb +286 -0
  700. data/spec/mongoid/monkey_patches_spec.rb +211 -0
  701. data/spec/mongoid/persistable/creatable_spec.rb +5 -5
  702. data/spec/mongoid/persistable/deletable_spec.rb +267 -27
  703. data/spec/mongoid/persistable/destroyable_spec.rb +409 -24
  704. data/spec/mongoid/persistable/incrementable_spec.rb +46 -9
  705. data/spec/mongoid/persistable/logical_spec.rb +42 -5
  706. data/spec/mongoid/persistable/maxable_spec.rb +147 -0
  707. data/spec/mongoid/persistable/minable_spec.rb +147 -0
  708. data/spec/mongoid/persistable/multipliable_spec.rb +227 -0
  709. data/spec/mongoid/persistable/poppable_spec.rb +41 -5
  710. data/spec/mongoid/persistable/pullable_spec.rb +81 -9
  711. data/spec/mongoid/persistable/pushable_spec.rb +81 -9
  712. data/spec/mongoid/persistable/renamable_spec.rb +40 -4
  713. data/spec/mongoid/persistable/savable_spec.rb +114 -20
  714. data/spec/mongoid/persistable/settable_spec.rb +77 -10
  715. data/spec/mongoid/persistable/unsettable_spec.rb +41 -5
  716. data/spec/mongoid/persistable/updatable_spec.rb +64 -52
  717. data/spec/mongoid/persistable/upsertable_spec.rb +124 -4
  718. data/spec/mongoid/persistable_spec.rb +4 -4
  719. data/spec/mongoid/persistence_context_spec.rb +58 -59
  720. data/spec/mongoid/positional_spec.rb +1 -1
  721. data/spec/mongoid/railties/bson_object_id_serializer_spec.rb +24 -0
  722. data/spec/mongoid/railties/console_sandbox_spec.rb +44 -0
  723. data/spec/mongoid/relations/proxy_spec.rb +7 -7
  724. data/spec/mongoid/reloadable_spec.rb +255 -30
  725. data/spec/mongoid/scopable_spec.rb +198 -58
  726. data/spec/mongoid/search_indexable_spec.rb +147 -0
  727. data/spec/mongoid/selectable_spec.rb +7 -7
  728. data/spec/mongoid/serializable_spec.rb +19 -40
  729. data/spec/mongoid/shardable_models.rb +15 -0
  730. data/spec/mongoid/shardable_spec.rb +181 -31
  731. data/spec/mongoid/stateful_spec.rb +152 -10
  732. data/spec/mongoid/tasks/database_rake_spec.rb +193 -42
  733. data/spec/mongoid/tasks/database_spec.rb +175 -2
  734. data/spec/mongoid/tasks/encryption_spec.rb +187 -0
  735. data/spec/mongoid/threaded_spec.rb +40 -3
  736. data/spec/mongoid/timestamps/created/short_spec.rb +2 -2
  737. data/spec/mongoid/timestamps/created_spec.rb +2 -2
  738. data/spec/mongoid/timestamps/timeless_spec.rb +3 -3
  739. data/spec/mongoid/timestamps/updated/short_spec.rb +4 -4
  740. data/spec/mongoid/timestamps/updated_spec.rb +4 -4
  741. data/spec/mongoid/timestamps_spec.rb +399 -11
  742. data/spec/mongoid/timestamps_spec_models.rb +68 -0
  743. data/spec/mongoid/touchable_spec.rb +971 -54
  744. data/spec/mongoid/touchable_spec_models.rb +154 -0
  745. data/spec/mongoid/traversable_spec.rb +79 -37
  746. data/spec/mongoid/validatable/associated_spec.rb +14 -31
  747. data/spec/mongoid/validatable/format_spec.rb +1 -1
  748. data/spec/mongoid/validatable/length_spec.rb +1 -1
  749. data/spec/mongoid/validatable/numericality_spec.rb +1 -1
  750. data/spec/mongoid/validatable/presence_spec.rb +27 -23
  751. data/spec/mongoid/validatable/uniqueness_spec.rb +170 -99
  752. data/spec/mongoid/validatable_spec.rb +4 -4
  753. data/spec/mongoid/warnings_spec.rb +36 -0
  754. data/spec/mongoid_spec.rb +61 -11
  755. data/spec/rails/controller_extension/controller_runtime_spec.rb +3 -3
  756. data/spec/rails/mongoid_spec.rb +28 -132
  757. data/spec/shared/bin/get-mongodb-download-url +17 -0
  758. data/spec/shared/bin/s3-copy +45 -0
  759. data/spec/shared/bin/s3-upload +69 -0
  760. data/spec/shared/lib/mrss/cluster_config.rb +24 -4
  761. data/spec/shared/lib/mrss/constraints.rb +77 -29
  762. data/spec/shared/lib/mrss/docker_runner.rb +40 -4
  763. data/spec/shared/lib/mrss/eg_config_utils.rb +51 -0
  764. data/spec/shared/lib/mrss/event_subscriber.rb +210 -0
  765. data/spec/shared/lib/mrss/lite_constraints.rb +64 -1
  766. data/spec/shared/lib/mrss/server_version_registry.rb +78 -34
  767. data/spec/shared/lib/mrss/session_registry.rb +69 -0
  768. data/spec/shared/lib/mrss/session_registry_legacy.rb +60 -0
  769. data/spec/shared/lib/mrss/spec_organizer.rb +32 -2
  770. data/spec/shared/lib/mrss/utils.rb +37 -0
  771. data/spec/shared/share/Dockerfile.erb +123 -71
  772. data/spec/shared/share/haproxy-1.conf +16 -0
  773. data/spec/shared/share/haproxy-2.conf +17 -0
  774. data/spec/shared/shlib/config.sh +27 -0
  775. data/spec/shared/shlib/distro.sh +2 -1
  776. data/spec/shared/shlib/server.sh +187 -40
  777. data/spec/shared/shlib/set_env.sh +49 -31
  778. data/spec/spec_helper.rb +46 -49
  779. data/spec/support/authorization.rb +1 -1
  780. data/spec/support/client_registry.rb +10 -0
  781. data/spec/support/constraints.rb +25 -1
  782. data/spec/support/crypt/models.rb +50 -0
  783. data/spec/support/crypt.rb +80 -0
  784. data/spec/support/expectations.rb +1 -1
  785. data/spec/support/feature_sandbox.rb +72 -0
  786. data/spec/support/helpers.rb +1 -0
  787. data/spec/support/immutable_ids.rb +119 -0
  788. data/spec/support/macros.rb +107 -1
  789. data/spec/support/models/account.rb +2 -2
  790. data/spec/support/models/acolyte.rb +1 -1
  791. data/spec/support/models/actor.rb +1 -1
  792. data/spec/support/models/actress.rb +1 -1
  793. data/spec/support/models/address.rb +7 -1
  794. data/spec/support/models/address_component.rb +1 -1
  795. data/spec/support/models/address_number.rb +1 -1
  796. data/spec/support/models/agency.rb +1 -1
  797. data/spec/support/models/agent.rb +1 -1
  798. data/spec/support/models/album.rb +1 -1
  799. data/spec/support/models/alert.rb +1 -1
  800. data/spec/support/models/animal.rb +1 -1
  801. data/spec/support/models/answer.rb +1 -1
  802. data/spec/support/models/appointment.rb +1 -1
  803. data/spec/support/models/armrest.rb +1 -1
  804. data/spec/support/models/array_field.rb +1 -1
  805. data/spec/support/models/article.rb +1 -1
  806. data/spec/support/models/artist.rb +3 -2
  807. data/spec/support/models/artwork.rb +1 -1
  808. data/spec/support/models/audible_sound.rb +4 -0
  809. data/spec/support/models/audio.rb +1 -1
  810. data/spec/support/models/augmentation.rb +13 -1
  811. data/spec/support/models/author.rb +1 -1
  812. data/spec/support/models/baby.rb +1 -1
  813. data/spec/support/models/band.rb +13 -1
  814. data/spec/support/models/bar.rb +1 -1
  815. data/spec/support/models/basic.rb +1 -1
  816. data/spec/support/models/bed.rb +1 -1
  817. data/spec/support/models/big_palette.rb +1 -1
  818. data/spec/support/models/birthday.rb +1 -1
  819. data/spec/support/models/bolt.rb +8 -0
  820. data/spec/support/models/bomb.rb +1 -1
  821. data/spec/support/models/book.rb +2 -1
  822. data/spec/support/models/breed.rb +1 -1
  823. data/spec/support/models/browser.rb +1 -1
  824. data/spec/support/models/building.rb +3 -1
  825. data/spec/support/models/building_address.rb +1 -1
  826. data/spec/support/models/bus.rb +1 -1
  827. data/spec/support/models/business.rb +1 -1
  828. data/spec/support/models/callback_test.rb +1 -1
  829. data/spec/support/models/canvas.rb +1 -1
  830. data/spec/support/models/car.rb +1 -1
  831. data/spec/support/models/cat.rb +1 -1
  832. data/spec/support/models/catalog.rb +25 -0
  833. data/spec/support/models/category.rb +1 -1
  834. data/spec/support/models/child.rb +1 -1
  835. data/spec/support/models/child_doc.rb +4 -4
  836. data/spec/support/models/church.rb +1 -1
  837. data/spec/support/models/circle.rb +1 -1
  838. data/spec/support/models/circuit.rb +1 -1
  839. data/spec/support/models/circus.rb +4 -1
  840. data/spec/support/models/code.rb +3 -1
  841. data/spec/support/models/coding/pull_request.rb +1 -1
  842. data/spec/support/models/coding.rb +1 -1
  843. data/spec/support/models/comment.rb +1 -1
  844. data/spec/support/models/company.rb +1 -1
  845. data/spec/support/models/consumption_period.rb +1 -1
  846. data/spec/support/models/contextable_item.rb +1 -1
  847. data/spec/support/models/contractor.rb +1 -1
  848. data/spec/support/models/cookie.rb +1 -1
  849. data/spec/support/models/country_code.rb +3 -1
  850. data/spec/support/models/courier_job.rb +1 -1
  851. data/spec/support/models/cover.rb +11 -0
  852. data/spec/support/models/crate.rb +1 -1
  853. data/spec/support/models/customer.rb +1 -1
  854. data/spec/support/models/customer_address.rb +1 -1
  855. data/spec/support/models/deed.rb +1 -1
  856. data/spec/support/models/definition.rb +1 -1
  857. data/spec/support/models/delegating_patient.rb +1 -1
  858. data/spec/support/models/description.rb +1 -1
  859. data/spec/support/models/dictionary.rb +1 -1
  860. data/spec/support/models/division.rb +1 -1
  861. data/spec/support/models/doctor.rb +1 -1
  862. data/spec/support/models/dog.rb +1 -1
  863. data/spec/support/models/dokument.rb +1 -1
  864. data/spec/support/models/draft.rb +1 -1
  865. data/spec/support/models/dragon.rb +1 -1
  866. data/spec/support/models/driver.rb +1 -1
  867. data/spec/support/models/drug.rb +1 -1
  868. data/spec/support/models/dungeon.rb +1 -1
  869. data/spec/support/models/edit.rb +1 -1
  870. data/spec/support/models/email.rb +1 -1
  871. data/spec/support/models/employer.rb +1 -1
  872. data/spec/support/models/entry.rb +1 -1
  873. data/spec/support/models/eraser.rb +1 -1
  874. data/spec/support/models/even.rb +1 -1
  875. data/spec/support/models/event.rb +1 -1
  876. data/spec/support/models/exhibition.rb +1 -1
  877. data/spec/support/models/exhibitor.rb +1 -1
  878. data/spec/support/models/explosion.rb +1 -1
  879. data/spec/support/models/eye.rb +1 -1
  880. data/spec/support/models/eye_bowl.rb +1 -1
  881. data/spec/support/models/face.rb +1 -1
  882. data/spec/support/models/fanatic.rb +9 -0
  883. data/spec/support/models/favorite.rb +8 -2
  884. data/spec/support/models/filesystem.rb +1 -1
  885. data/spec/support/models/fire_hydrant.rb +1 -1
  886. data/spec/support/models/firefox.rb +1 -1
  887. data/spec/support/models/fish.rb +1 -1
  888. data/spec/support/models/folder.rb +1 -1
  889. data/spec/support/models/folder_item.rb +1 -1
  890. data/spec/support/models/fruits.rb +1 -1
  891. data/spec/support/models/game.rb +1 -1
  892. data/spec/support/models/ghost.rb +1 -1
  893. data/spec/support/models/guitar.rb +1 -1
  894. data/spec/support/models/hole.rb +13 -0
  895. data/spec/support/models/home.rb +1 -1
  896. data/spec/support/models/house.rb +1 -1
  897. data/spec/support/models/html_writer.rb +1 -1
  898. data/spec/support/models/id_key.rb +1 -1
  899. data/spec/support/models/idnodef.rb +1 -1
  900. data/spec/support/models/image.rb +1 -1
  901. data/spec/support/models/implant.rb +10 -1
  902. data/spec/support/models/instrument.rb +1 -1
  903. data/spec/support/models/item.rb +1 -1
  904. data/spec/support/models/jar.rb +1 -1
  905. data/spec/support/models/kaleidoscope.rb +1 -1
  906. data/spec/support/models/kangaroo.rb +1 -1
  907. data/spec/support/models/label.rb +5 -2
  908. data/spec/support/models/language.rb +1 -1
  909. data/spec/support/models/lat_lng.rb +1 -1
  910. data/spec/support/models/league.rb +1 -1
  911. data/spec/support/models/learner.rb +1 -1
  912. data/spec/support/models/line_item.rb +1 -1
  913. data/spec/support/models/location.rb +1 -1
  914. data/spec/support/models/login.rb +1 -1
  915. data/spec/support/models/manufacturer.rb +1 -1
  916. data/spec/support/models/meat.rb +1 -1
  917. data/spec/support/models/membership.rb +2 -1
  918. data/spec/support/models/message.rb +1 -1
  919. data/spec/support/models/minim.rb +1 -1
  920. data/spec/support/models/mixed_drink.rb +1 -1
  921. data/spec/support/models/mop.rb +10 -1
  922. data/spec/support/models/movie.rb +1 -1
  923. data/spec/support/models/my_hash.rb +1 -1
  924. data/spec/support/models/name.rb +11 -1
  925. data/spec/support/models/name_only.rb +1 -1
  926. data/spec/support/models/node.rb +1 -1
  927. data/spec/support/models/note.rb +1 -1
  928. data/spec/support/models/nut.rb +8 -0
  929. data/spec/support/models/odd.rb +1 -1
  930. data/spec/support/models/order.rb +3 -1
  931. data/spec/support/models/ordered_post.rb +2 -2
  932. data/spec/support/models/ordered_preference.rb +1 -1
  933. data/spec/support/models/oscar.rb +1 -1
  934. data/spec/support/models/other_owner_object.rb +1 -1
  935. data/spec/support/models/override.rb +1 -1
  936. data/spec/support/models/ownable.rb +1 -1
  937. data/spec/support/models/owner.rb +1 -1
  938. data/spec/support/models/pack.rb +1 -1
  939. data/spec/support/models/page.rb +1 -1
  940. data/spec/support/models/page_question.rb +1 -1
  941. data/spec/support/models/palette.rb +1 -1
  942. data/spec/support/models/parent.rb +1 -1
  943. data/spec/support/models/parent_doc.rb +1 -1
  944. data/spec/support/models/passport.rb +15 -1
  945. data/spec/support/models/patient.rb +1 -1
  946. data/spec/support/models/pdf_writer.rb +1 -1
  947. data/spec/support/models/pencil.rb +1 -1
  948. data/spec/support/models/person.rb +19 -1
  949. data/spec/support/models/pet.rb +1 -1
  950. data/spec/support/models/pet_owner.rb +1 -1
  951. data/spec/support/models/phone.rb +3 -2
  952. data/spec/support/models/piano.rb +1 -1
  953. data/spec/support/models/pizza.rb +1 -1
  954. data/spec/support/models/player.rb +3 -1
  955. data/spec/support/models/post.rb +1 -1
  956. data/spec/support/models/post_genre.rb +1 -1
  957. data/spec/support/models/powerup.rb +13 -1
  958. data/spec/support/models/preference.rb +1 -1
  959. data/spec/support/models/princess.rb +1 -1
  960. data/spec/support/models/product.rb +2 -1
  961. data/spec/support/models/profile.rb +1 -1
  962. data/spec/support/models/pronunciation.rb +1 -1
  963. data/spec/support/models/pub.rb +1 -1
  964. data/spec/support/models/publication/encyclopedia.rb +1 -1
  965. data/spec/support/models/publication/review.rb +1 -1
  966. data/spec/support/models/publication.rb +1 -1
  967. data/spec/support/models/purchase.rb +1 -1
  968. data/spec/support/models/purchased_item.rb +11 -0
  969. data/spec/support/models/purse.rb +9 -0
  970. data/spec/support/models/question.rb +1 -1
  971. data/spec/support/models/quiz.rb +1 -1
  972. data/spec/support/models/rating.rb +1 -1
  973. data/spec/support/models/record.rb +1 -1
  974. data/spec/support/models/registry.rb +2 -1
  975. data/spec/support/models/role.rb +1 -1
  976. data/spec/support/models/root_category.rb +1 -1
  977. data/spec/support/models/sandbox/app/models/app_models_message.rb +4 -0
  978. data/spec/support/models/sandbox/lib/models/lib_models_message.rb +4 -0
  979. data/spec/support/models/sandbox/sandbox_message.rb +4 -0
  980. data/spec/support/models/sandbox/sandbox_user.rb +4 -0
  981. data/spec/support/models/sandbox/subdir/sandbox_comment.rb +4 -0
  982. data/spec/support/models/sandwich.rb +1 -1
  983. data/spec/support/models/scheduler.rb +1 -1
  984. data/spec/support/models/school.rb +15 -0
  985. data/spec/support/models/scribe.rb +1 -1
  986. data/spec/support/models/sealer.rb +8 -0
  987. data/spec/support/models/seat.rb +1 -1
  988. data/spec/support/models/seo.rb +1 -1
  989. data/spec/support/models/series.rb +1 -1
  990. data/spec/support/models/server.rb +1 -1
  991. data/spec/support/models/service.rb +1 -1
  992. data/spec/support/models/shape.rb +1 -1
  993. data/spec/support/models/shelf.rb +1 -1
  994. data/spec/support/models/shield.rb +19 -0
  995. data/spec/support/models/shipment_address.rb +1 -1
  996. data/spec/support/models/shipping_container.rb +1 -1
  997. data/spec/support/models/shipping_pack.rb +1 -1
  998. data/spec/support/models/shirt.rb +12 -0
  999. data/spec/support/models/shop.rb +1 -1
  1000. data/spec/support/models/short_agent.rb +1 -1
  1001. data/spec/support/models/short_quiz.rb +1 -1
  1002. data/spec/support/models/simple.rb +1 -1
  1003. data/spec/support/models/slave.rb +1 -1
  1004. data/spec/support/models/song.rb +1 -1
  1005. data/spec/support/models/sound.rb +1 -1
  1006. data/spec/support/models/spacer.rb +8 -0
  1007. data/spec/support/models/square.rb +1 -1
  1008. data/spec/support/models/staff.rb +1 -1
  1009. data/spec/support/models/store_as_dup_test1.rb +1 -1
  1010. data/spec/support/models/store_as_dup_test2.rb +1 -1
  1011. data/spec/support/models/store_as_dup_test3.rb +1 -1
  1012. data/spec/support/models/store_as_dup_test4.rb +1 -1
  1013. data/spec/support/models/strategy.rb +1 -1
  1014. data/spec/support/models/student.rb +15 -0
  1015. data/spec/support/models/sub_item.rb +1 -1
  1016. data/spec/support/models/subscription.rb +1 -1
  1017. data/spec/support/models/survey.rb +1 -1
  1018. data/spec/support/models/symptom.rb +1 -1
  1019. data/spec/support/models/system_role.rb +1 -0
  1020. data/spec/support/models/tag.rb +1 -1
  1021. data/spec/support/models/target.rb +1 -1
  1022. data/spec/support/models/template.rb +1 -1
  1023. data/spec/support/models/thing.rb +1 -1
  1024. data/spec/support/models/threadlocker.rb +8 -0
  1025. data/spec/support/models/title.rb +1 -1
  1026. data/spec/support/models/tool.rb +1 -1
  1027. data/spec/support/models/topping.rb +1 -1
  1028. data/spec/support/models/toy.rb +1 -1
  1029. data/spec/support/models/track.rb +1 -1
  1030. data/spec/support/models/translation.rb +1 -1
  1031. data/spec/support/models/tree.rb +1 -1
  1032. data/spec/support/models/truck.rb +1 -1
  1033. data/spec/support/models/updatable.rb +1 -1
  1034. data/spec/support/models/user.rb +1 -1
  1035. data/spec/support/models/user_account.rb +1 -1
  1036. data/spec/support/models/validation_callback.rb +1 -1
  1037. data/spec/support/models/vehicle.rb +1 -1
  1038. data/spec/support/models/version.rb +1 -1
  1039. data/spec/support/models/vertex.rb +1 -1
  1040. data/spec/support/models/vet_visit.rb +1 -1
  1041. data/spec/support/models/video.rb +1 -1
  1042. data/spec/support/models/video_game.rb +1 -1
  1043. data/spec/support/models/washer.rb +8 -0
  1044. data/spec/support/models/weapon.rb +13 -1
  1045. data/spec/support/models/wiki_page.rb +1 -1
  1046. data/spec/support/models/word.rb +1 -1
  1047. data/spec/support/models/word_origin.rb +1 -1
  1048. data/spec/support/models/writer.rb +1 -1
  1049. data/spec/support/rails_mock.rb +32 -0
  1050. data/spec/support/schema_maps/schema_map_aws.json +17 -0
  1051. data/spec/support/schema_maps/schema_map_aws_key_alt_names.json +12 -0
  1052. data/spec/support/schema_maps/schema_map_azure.json +17 -0
  1053. data/spec/support/schema_maps/schema_map_azure_key_alt_names.json +12 -0
  1054. data/spec/support/schema_maps/schema_map_gcp.json +17 -0
  1055. data/spec/support/schema_maps/schema_map_gcp_key_alt_names.json +12 -0
  1056. data/spec/support/schema_maps/schema_map_kmip.json +17 -0
  1057. data/spec/support/schema_maps/schema_map_kmip_key_alt_names.json +12 -0
  1058. data/spec/support/schema_maps/schema_map_local.json +18 -0
  1059. data/spec/support/schema_maps/schema_map_local_key_alt_names.json +12 -0
  1060. data/spec/support/shared/time.rb +3 -22
  1061. data/spec/support/sinatra_mock.rb +7 -0
  1062. data/spec/support/spec_config.rb +42 -7
  1063. data.tar.gz.sig +0 -0
  1064. metadata +883 -562
  1065. metadata.gz.sig +0 -0
  1066. data/lib/mongoid/association/referenced/eager.rb +0 -184
  1067. data/lib/mongoid/association/referenced/has_one/nested_builder.rb +0 -128
  1068. data/lib/mongoid/contextual/geo_near.rb +0 -269
  1069. data/lib/mongoid/errors/eager_load.rb +0 -26
  1070. data/lib/mongoid/errors/invalid_session_use.rb +0 -26
  1071. data/lib/mongoid/errors/invalid_storage_parent.rb +0 -28
  1072. data/lib/mongoid/errors/invalid_value.rb +0 -18
  1073. data/lib/mongoid/query_cache.rb +0 -333
  1074. data/lib/support/ruby_version.rb +0 -29
  1075. data/spec/mongoid/contextual/geo_near_spec.rb +0 -472
  1076. data/spec/mongoid/criteria/queryable/extensions/bignum_spec.rb +0 -61
  1077. data/spec/mongoid/criteria/queryable/extensions/fixnum_spec.rb +0 -61
  1078. data/spec/mongoid/extensions_spec.rb +0 -32
  1079. data/spec/mongoid/query_cache_middleware_spec.rb +0 -61
  1080. data/spec/mongoid/query_cache_spec.rb +0 -978
  1081. data/spec/support/cluster_config.rb +0 -158
  1082. data/spec/support/session_registry.rb +0 -50
@@ -1,10 +1,40 @@
1
1
  # frozen_string_literal: true
2
- # encoding: utf-8
2
+ # rubocop:todo all
3
3
 
4
4
  require "spec_helper"
5
5
 
6
6
  describe Mongoid::Contextual::Memory do
7
7
 
8
+ shared_examples "raises an error when no documents" do
9
+ context "when there are no matching documents" do
10
+ let(:criteria) do
11
+ Address.all.tap do |crit|
12
+ crit.documents = []
13
+ end
14
+ end
15
+
16
+ it "returns nil" do
17
+ expect do
18
+ context.send(method)
19
+ end.to raise_error(Mongoid::Errors::DocumentNotFound, /Could not find a document of class Address./)
20
+ end
21
+ end
22
+ end
23
+
24
+ shared_examples "returns nil when no documents" do
25
+ context "when there are no matching documents" do
26
+ let(:criteria) do
27
+ Address.all.tap do |crit|
28
+ crit.documents = []
29
+ end
30
+ end
31
+
32
+ it "returns nil" do
33
+ expect(context.send(method)).to be_nil
34
+ end
35
+ end
36
+ end
37
+
8
38
  [ :blank?, :empty? ].each do |method|
9
39
 
10
40
  describe "##{method}" do
@@ -168,19 +198,19 @@ describe Mongoid::Contextual::Memory do
168
198
  [ :delete, :delete_all ].each do |method|
169
199
 
170
200
  let(:person) do
171
- Person.create
201
+ Person.create!
172
202
  end
173
203
 
174
204
  let(:hobrecht) do
175
- person.addresses.create(street: "hobrecht")
205
+ person.addresses.create!(street: "hobrecht")
176
206
  end
177
207
 
178
208
  let(:friedel) do
179
- person.addresses.create(street: "friedel")
209
+ person.addresses.create!(street: "friedel")
180
210
  end
181
211
 
182
212
  let(:pfluger) do
183
- person.addresses.create(street: "pfluger")
213
+ person.addresses.create!(street: "pfluger")
184
214
  end
185
215
 
186
216
  describe "##{method}" do
@@ -233,11 +263,11 @@ describe Mongoid::Contextual::Memory do
233
263
  context "when embedded multiple levels" do
234
264
 
235
265
  let!(:home) do
236
- hobrecht.locations.create(name: "home")
266
+ hobrecht.locations.create!(name: "home")
237
267
  end
238
268
 
239
269
  let!(:work) do
240
- hobrecht.locations.create(name: "work")
270
+ hobrecht.locations.create!(name: "work")
241
271
  end
242
272
 
243
273
  let(:criteria) do
@@ -299,19 +329,19 @@ describe Mongoid::Contextual::Memory do
299
329
  [ :destroy, :destroy_all ].each do |method|
300
330
 
301
331
  let(:person) do
302
- Person.create
332
+ Person.create!
303
333
  end
304
334
 
305
335
  let(:hobrecht) do
306
- person.addresses.create(street: "hobrecht")
336
+ person.addresses.create!(street: "hobrecht")
307
337
  end
308
338
 
309
339
  let(:friedel) do
310
- person.addresses.create(street: "friedel")
340
+ person.addresses.create!(street: "friedel")
311
341
  end
312
342
 
313
343
  let(:pfluger) do
314
- person.addresses.create(street: "pfluger")
344
+ person.addresses.create!(street: "pfluger")
315
345
  end
316
346
 
317
347
  let(:criteria) do
@@ -379,61 +409,183 @@ describe Mongoid::Contextual::Memory do
379
409
  end
380
410
 
381
411
  describe "#distinct" do
412
+ let(:depeche) { Band.create!(name: "Depeche Mode", years: 30, sales: "1E2") }
413
+ let(:new_order) { Band.create!(name: "New Order", years: 25, sales: "2E3") }
414
+ let(:maniacs) { Band.create!(name: "10,000 Maniacs", years: 20, sales: "1E2") }
382
415
 
383
- let(:hobrecht) do
384
- Address.new(street: "hobrecht")
416
+ let(:criteria) do
417
+ Band.all.tap do |crit|
418
+ crit.documents = [ depeche, new_order, maniacs ]
419
+ end
385
420
  end
386
421
 
387
- let(:friedel) do
388
- Address.new(street: "friedel")
422
+ let(:context) do
423
+ described_class.new(criteria)
389
424
  end
390
425
 
391
426
  context "when limiting the result set" do
392
427
 
393
428
  let(:criteria) do
394
- Address.where(street: "hobrecht").tap do |crit|
395
- crit.documents = [ hobrecht, hobrecht, friedel ]
429
+ Band.where(name: "Depeche Mode").tap do |crit|
430
+ crit.documents = [ depeche ]
396
431
  end
397
432
  end
398
433
 
399
- let(:context) do
400
- described_class.new(criteria)
434
+ it "returns the distinct matching fields" do
435
+ expect(context.distinct(:name)).to eq([ "Depeche Mode" ])
401
436
  end
437
+ end
438
+
439
+ context "when not limiting the result set" do
402
440
 
403
441
  it "returns the distinct field values" do
404
- expect(context.distinct(:street)).to eq([ "hobrecht" ])
442
+ expect(context.distinct(:name).sort).to eq([ "10,000 Maniacs", "Depeche Mode", "New Order" ].sort)
405
443
  end
406
444
  end
407
445
 
408
- context "when not limiting the result set" do
446
+ context "when providing an aliased field" do
447
+
448
+ it "returns the distinct field values" do
449
+ expect(context.distinct(:years).sort).to eq([ 20, 25, 30 ])
450
+ end
451
+ end
452
+
453
+ context "when providing a demongoizable field" do
454
+
455
+ it "returns the non-demongoized distinct field values" do
456
+ expect(context.distinct(:sales).sort).to eq([ BigDecimal("1E2"), BigDecimal("2E3") ])
457
+ end
458
+ end
459
+
460
+ context "when getting a localized field" do
461
+ with_default_i18n_configs
462
+
463
+ before do
464
+ I18n.locale = :en
465
+ d = Dictionary.create!(description: 'english-text')
466
+ I18n.locale = :de
467
+ d.description = 'deutsch-text'
468
+ d.save!
469
+ end
409
470
 
410
471
  let(:criteria) do
411
- Address.all.tap do |crit|
412
- crit.documents = [ hobrecht, friedel, friedel ]
472
+ Dictionary.all.tap do |crit|
473
+ crit.documents = [ Dictionary.first ]
413
474
  end
414
475
  end
415
476
 
416
- let(:context) do
417
- described_class.new(criteria)
477
+ context "when getting the field without _translations" do
478
+ it "gets the demongoized localized field" do
479
+ expect(context.distinct(:description)).to eq([ 'deutsch-text' ])
480
+ end
418
481
  end
419
482
 
420
- it "returns the distinct field values" do
421
- expect(context.distinct(:street)).to eq([ "hobrecht", "friedel" ])
483
+ context "when getting the field with _translations" do
484
+
485
+ it "gets the full hash" do
486
+ expect(context.distinct(:description_translations)).to eq([ { "de" => "deutsch-text", "en" => "english-text" } ])
487
+ end
488
+ end
489
+
490
+ context 'when plucking a specific locale' do
491
+
492
+ let(:distinct) do
493
+ context.distinct(:'description.de')
494
+ end
495
+
496
+ it 'returns the specific translation' do
497
+ expect(distinct).to eq([ "deutsch-text" ])
498
+ end
499
+ end
500
+
501
+ context 'when plucking a specific locale from _translations field' do
502
+
503
+ let(:distinct) do
504
+ context.distinct(:'description_translations.de')
505
+ end
506
+
507
+ it 'returns the specific translations' do
508
+ expect(distinct).to eq(['deutsch-text'])
509
+ end
510
+ end
511
+
512
+ context 'when fallbacks are enabled with a locale list' do
513
+ require_fallbacks
514
+ with_default_i18n_configs
515
+
516
+ before do
517
+ I18n.fallbacks[:he] = [ :en ]
518
+ end
519
+
520
+ let(:distinct) do
521
+ context.distinct(:description).first
522
+ end
523
+
524
+ it "correctly uses the fallback" do
525
+ I18n.locale = :en
526
+ Dictionary.create!(description: 'english-text')
527
+ I18n.locale = :he
528
+ distinct.should == "english-text"
529
+ end
530
+ end
531
+
532
+ context "when the localized field is embedded" do
533
+ with_default_i18n_configs
534
+
535
+ let(:person) do
536
+ p = Passport.new
537
+ I18n.locale = :en
538
+ p.name = "Neil"
539
+ I18n.locale = :he
540
+ p.name = "Nissim"
541
+
542
+ Person.create!(passport: p, employer_id: 12345)
543
+ end
544
+
545
+ let(:criteria) do
546
+ Person.where(employer_id: 12345).tap do |crit|
547
+ crit.documents = [ person ]
548
+ end
549
+ end
550
+
551
+ let(:distinct) do
552
+ context.distinct("pass.name").first
553
+ end
554
+
555
+ let(:distinct_translations) do
556
+ context.distinct("pass.name_translations").first
557
+ end
558
+
559
+ let(:distinct_translations_field) do
560
+ context.distinct("pass.name_translations.en").first
561
+ end
562
+
563
+ it "returns the translation for the current locale" do
564
+ expect(distinct).to eq("Nissim")
565
+ end
566
+
567
+ it "returns the full _translation hash" do
568
+ expect(distinct_translations).to eq({ "en" => "Neil", "he" => "Nissim" })
569
+ end
570
+
571
+ it "returns the translation for the requested locale" do
572
+ expect(distinct_translations_field).to eq("Neil")
573
+ end
422
574
  end
423
575
  end
424
576
 
425
- context 'when there is a collation on the criteria' do
577
+ context "when getting an embedded field" do
426
578
 
579
+ let(:label) { Label.new(sales: "1E2") }
580
+ let!(:band) { Band.create!(label: label) }
427
581
  let(:criteria) do
428
- Address.where(street: "hobrecht").tap do |crit|
429
- crit.documents = [ hobrecht, hobrecht, friedel ]
430
- end.collation(locale: 'en_US', strength: 2)
582
+ Band.where(_id: band.id).tap do |crit|
583
+ crit.documents = [ band ]
584
+ end
431
585
  end
432
586
 
433
- it "raises an exception" do
434
- expect {
435
- context.distinct(:street)
436
- }.to raise_exception(Mongoid::Errors::InMemoryCollationNotSupported)
587
+ it "returns the distinct matching fields" do
588
+ expect(context.distinct("label.sales")).to eq([ BigDecimal("1E2") ])
437
589
  end
438
590
  end
439
591
  end
@@ -549,52 +701,158 @@ describe Mongoid::Contextual::Memory do
549
701
  Address.new(street: "friedel")
550
702
  end
551
703
 
552
- context "when there are matching documents" do
704
+ let(:criteria) do
705
+ Address.where(street: "hobrecht").tap do |crit|
706
+ crit.documents = [ hobrecht, friedel ]
707
+ end
708
+ end
553
709
 
554
- let(:criteria) do
555
- Address.where(street: "hobrecht").tap do |crit|
556
- crit.documents = [ hobrecht, friedel ]
710
+ context "when not passing options" do
711
+
712
+ context "when there are matching documents" do
713
+
714
+ let(:context) do
715
+ described_class.new(criteria)
716
+ end
717
+
718
+ it "returns true" do
719
+ expect(context).to be_exists
557
720
  end
558
721
  end
559
722
 
560
- let(:context) do
561
- described_class.new(criteria)
723
+ context "when there are no matching documents" do
724
+
725
+ let(:criteria) do
726
+ Address.where(street: "pfluger").tap do |crit|
727
+ crit.documents = [ hobrecht, friedel ]
728
+ end
729
+ end
730
+
731
+ let(:context) do
732
+ described_class.new(criteria)
733
+ end
734
+
735
+ it "returns false" do
736
+ expect(context).to_not be_exists
737
+ end
562
738
  end
563
739
 
564
- it "returns true" do
565
- expect(context).to be_exists
740
+ context 'when there is a collation on the criteria' do
741
+
742
+ let(:criteria) do
743
+ Address.where(street: "pfluger").tap do |crit|
744
+ crit.documents = [ hobrecht, friedel ]
745
+ end.collation(locale: 'en_US', strength: 2)
746
+ end
747
+
748
+ it "raises an exception" do
749
+ expect {
750
+ context
751
+ }.to raise_exception(Mongoid::Errors::InMemoryCollationNotSupported)
752
+ end
566
753
  end
567
754
  end
568
755
 
569
- context "when there are no matching documents" do
756
+ context "when passing an _id" do
570
757
 
571
- let(:criteria) do
572
- Address.where(street: "pfluger").tap do |crit|
573
- crit.documents = [ hobrecht, friedel ]
758
+ context "when its of type BSON::ObjectId" do
759
+
760
+ context "when calling it on an empty criteria" do
761
+
762
+ it "returns true" do
763
+ expect(criteria.exists?(hobrecht._id)).to be true
764
+ end
765
+ end
766
+
767
+ context "when calling it on a criteria that includes the object" do
768
+
769
+ it "returns true" do
770
+ expect(criteria.where(street: hobrecht.street).exists?(hobrecht._id)).to be true
771
+ end
772
+ end
773
+
774
+ context "when calling it on a criteria that does not include the object" do
775
+
776
+ it "returns false" do
777
+ expect(criteria.where(street: "bogus").exists?(hobrecht._id)).to be false
778
+ end
779
+ end
780
+
781
+ context "when the id does not exist" do
782
+
783
+ it "returns false" do
784
+ expect(criteria.exists?(BSON::ObjectId.new)).to be false
785
+ end
574
786
  end
575
787
  end
576
788
 
577
- let(:context) do
578
- described_class.new(criteria)
789
+ context "when its of type String" do
790
+
791
+ context "when the id exists" do
792
+
793
+ it "returns true" do
794
+ expect(criteria.exists?(hobrecht._id.to_s)).to be true
795
+ end
796
+ end
797
+
798
+ context "when the id does not exist" do
799
+
800
+ it "returns false" do
801
+ expect(criteria.exists?(BSON::ObjectId.new.to_s)).to be false
802
+ end
803
+ end
804
+ end
805
+ end
806
+
807
+ context "when passing a hash" do
808
+
809
+ context "when calling it on an empty criteria" do
810
+
811
+ it "returns true" do
812
+ expect(criteria.exists?(street: hobrecht.street)).to be true
813
+ end
814
+ end
815
+
816
+ context "when calling it on a criteria that includes the object" do
817
+
818
+ it "returns true" do
819
+ expect(criteria.where(_id: hobrecht._id).exists?(street: hobrecht.street)).to be true
820
+ end
821
+ end
822
+
823
+ context "when calling it on a criteria that does not include the object" do
824
+
825
+ it "returns false" do
826
+ expect(criteria.where(_id: BSON::ObjectId.new).exists?(street: hobrecht.street)).to be false
827
+ end
828
+ end
829
+
830
+ context "when the conditions don't match" do
831
+
832
+ it "returns false" do
833
+ expect(criteria.exists?(street: "bogus")).to be false
834
+ end
579
835
  end
836
+ end
837
+
838
+ context "when passing false" do
580
839
 
581
840
  it "returns false" do
582
- expect(context).to_not be_exists
841
+ expect(criteria.exists?(false)).to be false
583
842
  end
584
843
  end
585
844
 
586
- context 'when there is a collation on the criteria' do
845
+ context "when passing nil" do
587
846
 
588
- let(:criteria) do
589
- Address.where(street: "pfluger").tap do |crit|
590
- crit.documents = [ hobrecht, friedel ]
591
- end.collation(locale: 'en_US', strength: 2)
847
+ it "returns false" do
848
+ expect(criteria.exists?(nil)).to be false
592
849
  end
850
+ end
593
851
 
594
- it "raises an exception" do
595
- expect {
596
- context
597
- }.to raise_exception(Mongoid::Errors::InMemoryCollationNotSupported)
852
+ context "when the limit is 0" do
853
+
854
+ it "returns false" do
855
+ expect(criteria.limit(0).exists?).to be false
598
856
  end
599
857
  end
600
858
  end
@@ -603,6 +861,8 @@ describe Mongoid::Contextual::Memory do
603
861
 
604
862
  describe "##{method}" do
605
863
 
864
+ let(:method) { method }
865
+
606
866
  let(:hobrecht) do
607
867
  Address.new(street: "hobrecht")
608
868
  end
@@ -625,6 +885,16 @@ describe Mongoid::Contextual::Memory do
625
885
  expect(context.send(method)).to eq(hobrecht)
626
886
  end
627
887
 
888
+ it "returns a list when passing a limit" do
889
+ expect(context.send(method, 2)).to eq([ hobrecht, friedel ])
890
+ end
891
+
892
+ it "returns a list when passing 1" do
893
+ expect(context.send(method, 1)).to eq([ hobrecht ])
894
+ end
895
+
896
+ include_examples "returns nil when no documents"
897
+
628
898
  context 'when there is a collation on the criteria' do
629
899
 
630
900
  let(:criteria) do
@@ -642,38 +912,163 @@ describe Mongoid::Contextual::Memory do
642
912
  end
643
913
  end
644
914
 
645
- describe "#initialize" do
915
+ describe "#first!" do
646
916
 
647
- context "when the criteria has no options" do
917
+ let(:method) { :first! }
648
918
 
649
- let(:hobrecht) do
650
- Address.new(street: "hobrecht")
651
- end
919
+ let(:hobrecht) do
920
+ Address.new(street: "hobrecht")
921
+ end
652
922
 
653
- let(:friedel) do
654
- Address.new(street: "friedel")
655
- end
923
+ let(:friedel) do
924
+ Address.new(street: "friedel")
925
+ end
656
926
 
657
- let(:criteria) do
658
- Address.where(street: "hobrecht").tap do |crit|
659
- crit.documents = [ hobrecht, friedel ]
660
- end
927
+ let(:criteria) do
928
+ Address.where(:street.in => [ "hobrecht", "friedel" ]).tap do |crit|
929
+ crit.documents = [ hobrecht, friedel ]
661
930
  end
931
+ end
662
932
 
663
- let(:context) do
664
- described_class.new(criteria)
665
- end
933
+ let(:context) do
934
+ described_class.new(criteria)
935
+ end
666
936
 
667
- it "sets the criteria" do
668
- expect(context.criteria).to eq(criteria)
669
- end
937
+ it "returns the first matching document" do
938
+ expect(context.first!).to eq(hobrecht)
939
+ end
670
940
 
671
- it "sets the klass" do
672
- expect(context.klass).to eq(Address)
673
- end
941
+ include_examples "raises an error when no documents"
942
+ end
674
943
 
675
- it "sets the matching documents" do
676
- expect(context.documents).to eq([ hobrecht ])
944
+ describe "#take" do
945
+
946
+ let(:method) { :take }
947
+
948
+ let(:hobrecht) do
949
+ Address.new(street: "hobrecht")
950
+ end
951
+
952
+ let(:friedel) do
953
+ Address.new(street: "friedel")
954
+ end
955
+
956
+ let(:criteria) do
957
+ Address.where(:street.in => [ "hobrecht", "friedel" ]).tap do |crit|
958
+ crit.documents = [ hobrecht, friedel ]
959
+ end
960
+ end
961
+
962
+ let(:context) do
963
+ described_class.new(criteria)
964
+ end
965
+
966
+ it "returns the first matching document" do
967
+ expect(context.take).to eq(hobrecht)
968
+ end
969
+
970
+ it "returns an array when passing a limit" do
971
+ expect(context.take(2)).to eq([ hobrecht, friedel ])
972
+ end
973
+
974
+ it "returns an array when passing a limit as 1" do
975
+ expect(context.take(1)).to eq([ hobrecht ])
976
+ end
977
+
978
+ include_examples "returns nil when no documents"
979
+
980
+ context 'when there is a collation on the criteria' do
981
+
982
+ let(:criteria) do
983
+ Address.where(:street.in => [ "hobrecht", "friedel" ]).tap do |crit|
984
+ crit.documents = [ hobrecht, friedel ]
985
+ end.collation(locale: 'en_US', strength: 2)
986
+ end
987
+
988
+ it "raises an exception" do
989
+ expect {
990
+ context.take
991
+ }.to raise_exception(Mongoid::Errors::InMemoryCollationNotSupported)
992
+ end
993
+ end
994
+ end
995
+
996
+ describe "#take!" do
997
+
998
+ let(:method) { :take! }
999
+
1000
+ let(:hobrecht) do
1001
+ Address.new(street: "hobrecht")
1002
+ end
1003
+
1004
+ let(:friedel) do
1005
+ Address.new(street: "friedel")
1006
+ end
1007
+
1008
+ let(:criteria) do
1009
+ Address.where(:street.in => [ "hobrecht", "friedel" ]).tap do |crit|
1010
+ crit.documents = [ hobrecht, friedel ]
1011
+ end
1012
+ end
1013
+
1014
+ let(:context) do
1015
+ described_class.new(criteria)
1016
+ end
1017
+
1018
+ it "returns the first matching document" do
1019
+ expect(context.take!).to eq(hobrecht)
1020
+ end
1021
+
1022
+ include_examples "raises an error when no documents"
1023
+
1024
+ context 'when there is a collation on the criteria' do
1025
+
1026
+ let(:criteria) do
1027
+ Address.where(:street.in => [ "hobrecht", "friedel" ]).tap do |crit|
1028
+ crit.documents = [ hobrecht, friedel ]
1029
+ end.collation(locale: 'en_US', strength: 2)
1030
+ end
1031
+
1032
+ it "raises an exception" do
1033
+ expect {
1034
+ context.take
1035
+ }.to raise_exception(Mongoid::Errors::InMemoryCollationNotSupported)
1036
+ end
1037
+ end
1038
+ end
1039
+
1040
+ describe "#initialize" do
1041
+
1042
+ context "when the criteria has no options" do
1043
+
1044
+ let(:hobrecht) do
1045
+ Address.new(street: "hobrecht")
1046
+ end
1047
+
1048
+ let(:friedel) do
1049
+ Address.new(street: "friedel")
1050
+ end
1051
+
1052
+ let(:criteria) do
1053
+ Address.where(street: "hobrecht").tap do |crit|
1054
+ crit.documents = [ hobrecht, friedel ]
1055
+ end
1056
+ end
1057
+
1058
+ let(:context) do
1059
+ described_class.new(criteria)
1060
+ end
1061
+
1062
+ it "sets the criteria" do
1063
+ expect(context.criteria).to eq(criteria)
1064
+ end
1065
+
1066
+ it "sets the klass" do
1067
+ expect(context.klass).to eq(Address)
1068
+ end
1069
+
1070
+ it "sets the matching documents" do
1071
+ expect(context.documents).to eq([ hobrecht ])
677
1072
  end
678
1073
  end
679
1074
 
@@ -745,6 +1140,8 @@ describe Mongoid::Contextual::Memory do
745
1140
 
746
1141
  describe "#last" do
747
1142
 
1143
+ let(:method) { :last }
1144
+
748
1145
  let(:hobrecht) do
749
1146
  Address.new(street: "hobrecht")
750
1147
  end
@@ -767,6 +1164,16 @@ describe Mongoid::Contextual::Memory do
767
1164
  expect(context.last).to eq(friedel)
768
1165
  end
769
1166
 
1167
+ it "returns a list when a limit is passed" do
1168
+ expect(context.last(2)).to eq([ hobrecht, friedel ])
1169
+ end
1170
+
1171
+ it "returns a list when the limit is 1" do
1172
+ expect(context.last(1)).to eq([ friedel ])
1173
+ end
1174
+
1175
+ include_examples "returns nil when no documents"
1176
+
770
1177
  context 'when there is a collation on the criteria' do
771
1178
 
772
1179
  let(:criteria) do
@@ -783,6 +1190,102 @@ describe Mongoid::Contextual::Memory do
783
1190
  end
784
1191
  end
785
1192
 
1193
+ describe "#last!" do
1194
+ let(:method) { :last! }
1195
+
1196
+ let(:hobrecht) do
1197
+ Address.new(street: "hobrecht")
1198
+ end
1199
+
1200
+ let(:friedel) do
1201
+ Address.new(street: "friedel")
1202
+ end
1203
+
1204
+ let(:criteria) do
1205
+ Address.where(:street.in => [ "hobrecht", "friedel" ]).tap do |crit|
1206
+ crit.documents = [ hobrecht, friedel ]
1207
+ end
1208
+ end
1209
+
1210
+ let(:context) do
1211
+ described_class.new(criteria)
1212
+ end
1213
+
1214
+ it "returns the last matching document" do
1215
+ expect(context.last!).to eq(friedel)
1216
+ end
1217
+
1218
+ include_examples "raises an error when no documents"
1219
+ end
1220
+
1221
+ [ :second,
1222
+ :third,
1223
+ :fourth,
1224
+ :fifth,
1225
+ :second_to_last,
1226
+ :third_to_last
1227
+ ].each do |meth|
1228
+ describe "##{meth}" do
1229
+ let(:method) { meth }
1230
+
1231
+ let(:addresses) do
1232
+ [
1233
+ Address.new,
1234
+ Address.new,
1235
+ Address.new,
1236
+ Address.new,
1237
+ Address.new,
1238
+ ]
1239
+ end
1240
+
1241
+ let(:criteria) do
1242
+ Address.all.tap do |crit|
1243
+ crit.documents = addresses
1244
+ end
1245
+ end
1246
+
1247
+ let(:context) do
1248
+ described_class.new(criteria)
1249
+ end
1250
+
1251
+ it "returns the matching document" do
1252
+ expect(context.send(method)).to eq(addresses.send(method))
1253
+ end
1254
+
1255
+ include_examples "returns nil when no documents"
1256
+ end
1257
+
1258
+ describe "##{meth}!" do
1259
+ let(:method) { "#{meth}!" }
1260
+
1261
+ let(:addresses) do
1262
+ [
1263
+ Address.new,
1264
+ Address.new,
1265
+ Address.new,
1266
+ Address.new,
1267
+ Address.new,
1268
+ ]
1269
+ end
1270
+
1271
+ let(:criteria) do
1272
+ Address.all.tap do |crit|
1273
+ crit.documents = addresses
1274
+ end
1275
+ end
1276
+
1277
+ let(:context) do
1278
+ described_class.new(criteria)
1279
+ end
1280
+
1281
+ it "returns the matching document" do
1282
+ expect(context.send(method)).to eq(addresses.send(meth))
1283
+ end
1284
+
1285
+ include_examples "raises an error when no documents"
1286
+ end
1287
+ end
1288
+
786
1289
  [ :length, :size ].each do |method|
787
1290
 
788
1291
  describe "##{method}" do
@@ -920,72 +1423,921 @@ describe Mongoid::Contextual::Memory do
920
1423
 
921
1424
  describe "#pluck" do
922
1425
 
923
- let(:hobrecht) do
924
- Address.new(street: "hobrecht")
1426
+ let(:context) do
1427
+ described_class.new(criteria)
925
1428
  end
926
1429
 
927
- let(:friedel) do
928
- Address.new(street: "friedel")
1430
+ let!(:depeche) do
1431
+ Band.create!(name: "Depeche Mode", likes: 3)
1432
+ end
1433
+
1434
+ let!(:tool) do
1435
+ Band.create!(name: "Tool", likes: 3)
1436
+ end
1437
+
1438
+ let!(:photek) do
1439
+ Band.create!(name: "Photek", likes: 1)
1440
+ end
1441
+
1442
+ let!(:maniacs) do
1443
+ Band.create!(name: "10,000 Maniacs", likes: 1, sales: "1E2")
929
1444
  end
930
1445
 
931
1446
  let(:criteria) do
932
- Address.all.tap do |crit|
933
- crit.documents = [ hobrecht, friedel ]
1447
+ Band.all.tap do |crit|
1448
+ crit.documents = [ depeche, tool, photek, maniacs ]
934
1449
  end
935
1450
  end
936
1451
 
937
- let(:context) do
938
- described_class.new(criteria)
939
- end
1452
+ context "when the field is aliased" do
1453
+
1454
+ let!(:expensive) do
1455
+ Product.create!(price: 100000)
1456
+ end
940
1457
 
941
- context "when plucking" do
1458
+ let!(:cheap) do
1459
+ Product.create!(price: 1)
1460
+ end
942
1461
 
943
- let!(:plucked) do
944
- context.pluck(:street)
1462
+ let(:criteria) do
1463
+ Product.all.tap do |crit|
1464
+ crit.documents = [ expensive, cheap ]
1465
+ end
945
1466
  end
946
1467
 
947
- it "returns the values" do
948
- expect(plucked).to eq([ "hobrecht", "friedel" ])
1468
+ context "when using alias_attribute" do
1469
+
1470
+ let(:plucked) do
1471
+ context.pluck(:price)
1472
+ end
1473
+
1474
+ it "uses the aliases" do
1475
+ expect(plucked).to eq([ 100000, 1 ])
1476
+ end
949
1477
  end
950
1478
  end
951
1479
 
952
- context "when plucking a field that doesnt exist" do
1480
+ context "when the criteria matches" do
953
1481
 
954
- context "when pluck one field" do
1482
+ context "when there are no duplicate values" do
1483
+
1484
+ let!(:plucked) do
1485
+ context.pluck(:name)
1486
+ end
1487
+
1488
+ it "returns the values" do
1489
+ expect(plucked).to contain_exactly("10,000 Maniacs", "Depeche Mode", "Tool", "Photek")
1490
+ end
1491
+
1492
+ context "when subsequently executing the criteria without a pluck" do
1493
+
1494
+ it "does not limit the fields" do
1495
+ expect(context.first.likes).to eq(3)
1496
+ end
1497
+ end
1498
+
1499
+ context 'when the field is a subdocument' do
1500
+
1501
+ context 'when a top-level field and a subdocument field are plucked' do
1502
+ let(:criteria) do
1503
+ Band.where(name: 'FKA Twigs').tap do |crit|
1504
+ crit.documents = [
1505
+ Band.create!(name: 'FKA Twigs'),
1506
+ Band.create!(name: 'FKA Twigs', records: [ Record.new(name: 'LP1') ])
1507
+ ]
1508
+ end
1509
+ end
1510
+
1511
+ let(:embedded_pluck) do
1512
+ context.pluck(:name, 'records.name')
1513
+ end
1514
+
1515
+ let(:expected) do
1516
+ [
1517
+ ["FKA Twigs", []],
1518
+ ['FKA Twigs', ["LP1"]]
1519
+ ]
1520
+ end
1521
+
1522
+ it 'returns the list of top-level field and subdocument values' do
1523
+ expect(embedded_pluck).to eq(expected)
1524
+ end
1525
+ end
1526
+
1527
+ context 'when only a subdocument field is plucked' do
1528
+
1529
+ let(:criteria) do
1530
+ Band.where(name: 'FKA Twigs').tap do |crit|
1531
+ crit.documents = [
1532
+ Band.create!(name: 'FKA Twigs'),
1533
+ Band.create!(name: 'FKA Twigs', records: [ Record.new(name: 'LP1') ])
1534
+ ]
1535
+ end
1536
+ end
1537
+
1538
+ let(:embedded_pluck) do
1539
+ context.pluck('records.name')
1540
+ end
1541
+
1542
+ let(:expected) do
1543
+ [
1544
+ [],
1545
+ ["LP1"]
1546
+ ]
1547
+ end
1548
+
1549
+ it 'returns the list of subdocument values' do
1550
+ expect(embedded_pluck).to eq(expected)
1551
+ end
1552
+ end
1553
+ end
1554
+ end
1555
+
1556
+ context "when plucking multi-fields" do
955
1557
 
956
1558
  let(:plucked) do
957
- context.pluck(:foo)
1559
+ context.pluck(:name, :likes)
958
1560
  end
959
1561
 
960
- it "returns a empty array" do
961
- expect(plucked).to eq([])
1562
+ it "returns the values" do
1563
+ expect(plucked).to contain_exactly(["10,000 Maniacs", 1], ["Depeche Mode", 3], ["Tool", 3], ["Photek", 1])
962
1564
  end
963
1565
  end
964
1566
 
965
- context "when pluck multiple fields" do
1567
+ context "when there are duplicate values" do
966
1568
 
967
1569
  let(:plucked) do
968
- context.pluck(:foo, :bar)
1570
+ context.pluck(:likes)
969
1571
  end
970
1572
 
971
- it "returns a empty array" do
972
- expect(plucked).to eq([[], []])
1573
+ it "returns the duplicates" do
1574
+ expect(plucked).to contain_exactly(1, 3, 3, 1)
973
1575
  end
974
1576
  end
975
1577
  end
976
1578
 
977
- context 'when there is a collation on the criteria' do
1579
+ context "when plucking an aliased field" do
978
1580
 
979
- let(:criteria) do
980
- Address.all.tap do |crit|
981
- crit.documents = [ hobrecht, friedel ]
982
- end.collation(locale: 'en_US', strength: 2)
1581
+ let(:plucked) do
1582
+ context.pluck(:id)
983
1583
  end
984
1584
 
985
- it "raises an exception" do
986
- expect {
987
- context.pluck(:foo, :bar)
988
- }.to raise_exception(Mongoid::Errors::InMemoryCollationNotSupported)
1585
+ it "returns the field values" do
1586
+ expect(plucked).to eq([ depeche.id, tool.id, photek.id, maniacs.id ])
1587
+ end
1588
+ end
1589
+
1590
+ context "when plucking existent and non-existent fields" do
1591
+
1592
+ let(:plucked) do
1593
+ context.pluck(:id, :fooz)
1594
+ end
1595
+
1596
+ it "returns nil for the field that doesnt exist" do
1597
+ expect(plucked).to eq([[depeche.id, nil], [tool.id, nil], [photek.id, nil], [maniacs.id, nil] ])
1598
+ end
1599
+ end
1600
+
1601
+ context "when plucking a field that doesnt exist" do
1602
+
1603
+ context "when pluck one field" do
1604
+
1605
+ let(:plucked) do
1606
+ context.pluck(:foo)
1607
+ end
1608
+
1609
+ it "returns an array with nil values" do
1610
+ expect(plucked).to eq([nil, nil, nil, nil])
1611
+ end
1612
+ end
1613
+
1614
+ context "when pluck multiple fields" do
1615
+
1616
+ let(:plucked) do
1617
+ context.pluck(:foo, :bar)
1618
+ end
1619
+
1620
+ it "returns an array of arrays with nil values" do
1621
+ expect(plucked).to eq([[nil, nil], [nil, nil], [nil, nil], [nil, nil]])
1622
+ end
1623
+ end
1624
+ end
1625
+
1626
+ context 'when plucking a localized field' do
1627
+ with_default_i18n_configs
1628
+
1629
+ before do
1630
+ I18n.locale = :en
1631
+ d = Dictionary.create!(description: 'english-text')
1632
+ I18n.locale = :de
1633
+ d.description = 'deutsch-text'
1634
+ d.save!
1635
+ end
1636
+
1637
+ let(:criteria) do
1638
+ Dictionary.all.tap do |crit|
1639
+ crit.documents = [ Dictionary.first ]
1640
+ end
1641
+ end
1642
+
1643
+ context 'when plucking the entire field' do
1644
+
1645
+ let(:plucked) do
1646
+ context.pluck(:description)
1647
+ end
1648
+
1649
+ let(:plucked_translations) do
1650
+ context.pluck(:description_translations)
1651
+ end
1652
+
1653
+ let(:plucked_translations_both) do
1654
+ context.pluck(:description_translations, :description)
1655
+ end
1656
+
1657
+ it 'returns the demongoized translations' do
1658
+ expect(plucked.first).to eq('deutsch-text')
1659
+ end
1660
+
1661
+ it 'returns the full translations hash to _translations' do
1662
+ expect(plucked_translations.first).to eq({"de"=>"deutsch-text", "en"=>"english-text"})
1663
+ end
1664
+
1665
+ it 'returns both' do
1666
+ expect(plucked_translations_both.first).to eq([{"de"=>"deutsch-text", "en"=>"english-text"}, "deutsch-text"])
1667
+ end
1668
+ end
1669
+
1670
+ context 'when plucking a specific locale' do
1671
+
1672
+ let(:plucked) do
1673
+ context.pluck(:'description.de')
1674
+ end
1675
+
1676
+ it 'returns the specific translations' do
1677
+ expect(plucked.first).to eq('deutsch-text')
1678
+ end
1679
+ end
1680
+
1681
+ context 'when plucking a specific locale from _translations field' do
1682
+
1683
+ let(:plucked) do
1684
+ context.pluck(:'description_translations.de')
1685
+ end
1686
+
1687
+ it 'returns the specific translations' do
1688
+ expect(plucked.first).to eq('deutsch-text')
1689
+ end
1690
+ end
1691
+
1692
+ context 'when fallbacks are enabled with a locale list' do
1693
+ require_fallbacks
1694
+ with_default_i18n_configs
1695
+
1696
+ before do
1697
+ I18n.fallbacks[:he] = [ :en ]
1698
+ end
1699
+
1700
+ let(:plucked) do
1701
+ context.pluck(:description).first
1702
+ end
1703
+
1704
+ it "correctly uses the fallback" do
1705
+ I18n.locale = :en
1706
+ Dictionary.create!(description: 'english-text')
1707
+ I18n.locale = :he
1708
+ plucked.should == "english-text"
1709
+ end
1710
+ end
1711
+
1712
+ context "when the localized field is embedded" do
1713
+ with_default_i18n_configs
1714
+
1715
+ before do
1716
+ p = Passport.new
1717
+ I18n.locale = :en
1718
+ p.name = "Neil"
1719
+ I18n.locale = :he
1720
+ p.name = "Nissim"
1721
+
1722
+ Person.create!(passport: p, employer_id: 12345)
1723
+ end
1724
+
1725
+ let(:plucked) do
1726
+ Person.where(employer_id: 12345).pluck("pass.name").first
1727
+ end
1728
+
1729
+ let(:plucked_translations) do
1730
+ Person.where(employer_id: 12345).pluck("pass.name_translations").first
1731
+ end
1732
+
1733
+ let(:plucked_translations_field) do
1734
+ Person.where(employer_id: 12345).pluck("pass.name_translations.en").first
1735
+ end
1736
+
1737
+ it "returns the translation for the current locale" do
1738
+ expect(plucked).to eq("Nissim")
1739
+ end
1740
+
1741
+ it "returns the full _translation hash" do
1742
+ expect(plucked_translations).to eq({ "en" => "Neil", "he" => "Nissim" })
1743
+ end
1744
+
1745
+ it "returns the translation for the requested locale" do
1746
+ expect(plucked_translations_field).to eq("Neil")
1747
+ end
1748
+ end
1749
+ end
1750
+
1751
+ context 'when plucking a field to be demongoized' do
1752
+
1753
+ let(:plucked) do
1754
+ Band.where(name: maniacs.name).pluck(:sales)
1755
+ end
1756
+
1757
+ with_config_values :map_big_decimal_to_decimal128, true, false do
1758
+
1759
+ it "demongoizes the field" do
1760
+ expect(plucked.first).to be_a(BigDecimal)
1761
+ expect(plucked.first).to eq(BigDecimal("1E2"))
1762
+ end
1763
+ end
1764
+ end
1765
+
1766
+ context "when plucking an embedded field" do
1767
+ let(:label) { Label.new(sales: "1E2") }
1768
+ let!(:band) { Band.create!(label: label) }
1769
+
1770
+ let(:plucked) do
1771
+ Band.where(_id: band.id).tap do |crit|
1772
+ crit.documents = [ band ]
1773
+ end.pluck("label.sales")
1774
+ end
1775
+
1776
+ it "demongoizes the field" do
1777
+ expect(plucked).to eq([ BigDecimal("1E2") ])
1778
+ end
1779
+ end
1780
+
1781
+ context "when plucking an embeds_many field" do
1782
+ let(:label) { Label.new(sales: "1E2") }
1783
+ let!(:band) { Band.create!(labels: [label]) }
1784
+
1785
+ let(:plucked) { Band.where(_id: band.id).pluck("labels.sales") }
1786
+
1787
+ it "demongoizes the field" do
1788
+ expect(plucked.first).to eq([ BigDecimal("1E2") ])
1789
+ end
1790
+ end
1791
+
1792
+ context "when plucking a nonexistent embedded field" do
1793
+ let(:label) { Label.new(sales: "1E2") }
1794
+ let!(:band) { Band.create!(label: label) }
1795
+
1796
+ let(:plucked) do
1797
+ Band.where(_id: band.id).tap do |crit|
1798
+ crit.documents = [ band ]
1799
+ end.pluck("label.qwerty")
1800
+ end
1801
+
1802
+ it "returns nil" do
1803
+ expect(plucked.first).to eq(nil)
1804
+ end
1805
+ end
1806
+
1807
+ context "when plucking deeply nested arrays/embedded associations" do
1808
+
1809
+ let(:criteria) do
1810
+ Person.all.tap do |crit|
1811
+ crit.documents = [
1812
+ Person.create!(addresses: [ Address.new(code: Code.new(deepest: Deepest.new(array: [ { y: { z: 1 } }, { y: { z: 2 } } ]))) ]),
1813
+ Person.create!(addresses: [ Address.new(code: Code.new(deepest: Deepest.new(array: [ { y: { z: 1 } }, { y: { z: 2 } } ]))) ]),
1814
+ Person.create!(addresses: [ Address.new(code: Code.new(deepest: Deepest.new(array: [ { y: { z: 1 } }, { y: { z: 3 } } ]))) ]),
1815
+ ]
1816
+ end
1817
+ end
1818
+
1819
+ let(:plucked) do
1820
+ context.pluck("addresses.code.deepest.array.y.z")
1821
+ end
1822
+
1823
+ it "returns the correct hash" do
1824
+ expect(plucked).to eq([
1825
+ [ [ 1, 2 ] ], [ [ 1, 2 ] ], [ [ 1, 3 ] ]
1826
+ ])
1827
+ end
1828
+ end
1829
+ end
1830
+
1831
+ describe "#pick" do
1832
+
1833
+ let(:depeche) do
1834
+ Band.create!(name: "Depeche Mode", likes: 3)
1835
+ end
1836
+
1837
+ let(:tool) do
1838
+ Band.create!(name: "Tool", likes: 3)
1839
+ end
1840
+
1841
+ let(:criteria) do
1842
+ Band.all.tap do |crit|
1843
+ crit.documents = [ depeche, tool ]
1844
+ end
1845
+ end
1846
+
1847
+ let(:context) do
1848
+ described_class.new(criteria)
1849
+ end
1850
+
1851
+ context "when picking a field" do
1852
+
1853
+ let(:picked) do
1854
+ context.pick(:name)
1855
+ end
1856
+
1857
+ it "returns one element" do
1858
+ expect(picked).to eq("Depeche Mode")
1859
+ end
1860
+ end
1861
+
1862
+ context "when picking multiple fields" do
1863
+
1864
+ let(:picked) do
1865
+ context.pick(:name, :likes)
1866
+ end
1867
+
1868
+ it "returns an array" do
1869
+ expect(picked).to eq([ "Depeche Mode", 3 ])
1870
+ end
1871
+ end
1872
+
1873
+ context "when no documents to pick" do
1874
+
1875
+ let(:criteria) do
1876
+ Band.all.tap do |crit|
1877
+ crit.documents = []
1878
+ end
1879
+ end
1880
+
1881
+ let(:picked) do
1882
+ context.pick(:name)
1883
+ end
1884
+
1885
+ it "returns nil" do
1886
+ expect(picked).to be_nil
1887
+ end
1888
+ end
1889
+ end
1890
+
1891
+ describe "#tally" do
1892
+ let(:fans1) { [ Fanatic.new(age:1), Fanatic.new(age:2) ] }
1893
+ let(:fans2) { [ Fanatic.new(age:1), Fanatic.new(age:2) ] }
1894
+ let(:fans3) { [ Fanatic.new(age:1), Fanatic.new(age:3) ] }
1895
+
1896
+ let(:genres1) { [ { x: 1, y: { z: 1 } }, { x: 2, y: { z: 2 } }, { y: 3 } ]}
1897
+ let(:genres2) { [ { x: 1, y: { z: 1 } }, { x: 2, y: { z: 2 } }, { y: 4 } ]}
1898
+ let(:genres3) { [ { x: 1, y: { z: 1 } }, { x: 3, y: { z: 3 } }, { y: 5 } ]}
1899
+
1900
+ let(:label1) { Label.new(name: "Atlantic") }
1901
+ let(:label2) { Label.new(name: "Atlantic") }
1902
+ let(:label3) { Label.new(name: "Columbia") }
1903
+
1904
+
1905
+ let(:band1) { Band.new(origin: "tally", name: "Depeche Mode", years: 30, sales: "1E2", label: label1, genres: genres1) }
1906
+ let(:band2) { Band.new(origin: "tally", name: "New Order", years: 30, sales: "2E3", label: label2, genres: genres2) }
1907
+ let(:band3) { Band.new(origin: "tally", name: "10,000 Maniacs", years: 30, sales: "1E2", label: label3, genres: genres3) }
1908
+ let(:band4) { Band.new(origin: "tally2", fanatics: fans1, genres: [1, 2]) }
1909
+ let(:band5) { Band.new(origin: "tally2", fanatics: fans2, genres: [1, 2]) }
1910
+ let(:band6) { Band.new(origin: "tally2", fanatics: fans3, genres: [1, 3]) }
1911
+
1912
+ let(:criteria) do
1913
+ Band.where(origin: "tally").all.tap do |crit|
1914
+ crit.documents = [ band1, band2, band3 ]
1915
+ end
1916
+ end
1917
+
1918
+ let(:criteria2) do
1919
+ Band.where(origin: "tally2").tap do |crit|
1920
+ crit.documents = [ band4, band5, band6 ]
1921
+ end
1922
+ end
1923
+
1924
+ let(:context) do
1925
+ described_class.new(criteria)
1926
+ end
1927
+
1928
+ let(:context2) do
1929
+ described_class.new(criteria2)
1930
+ end
1931
+
1932
+ context "when tallying a string" do
1933
+ let(:tally) do
1934
+ context.tally(:name)
1935
+ end
1936
+
1937
+ it "returns the correct hash" do
1938
+ expect(tally).to eq("Depeche Mode" => 1, "New Order" => 1, "10,000 Maniacs" => 1)
1939
+ end
1940
+ end
1941
+
1942
+ context "using an aliased field" do
1943
+ let(:tally) do
1944
+ context.tally(:years)
1945
+ end
1946
+
1947
+ it "returns the correct hash" do
1948
+ expect(tally).to eq(30 => 3)
1949
+ end
1950
+ end
1951
+
1952
+ context "when tallying a demongoizable field" do
1953
+ let(:tally) do
1954
+ context.tally(:sales)
1955
+ end
1956
+
1957
+ it "returns the correct hash" do
1958
+ expect(tally).to eq(BigDecimal("1E2") => 2, BigDecimal("2E3") => 1)
1959
+ end
1960
+ end
1961
+
1962
+ context "when tallying a localized field" do
1963
+ with_default_i18n_configs
1964
+
1965
+ let(:d1) { Dictionary.new(description: 'en1') }
1966
+ let(:d2) { Dictionary.new(description: 'en1') }
1967
+ let(:d3) { Dictionary.new(description: 'en1') }
1968
+ let(:d4) { Dictionary.new(description: 'en2') }
1969
+
1970
+ before do
1971
+ I18n.locale = :en
1972
+ d1
1973
+ d2
1974
+ d3
1975
+ d4
1976
+ I18n.locale = :de
1977
+ d1.description = 'de1'
1978
+ d2.description = 'de1'
1979
+ d3.description = 'de2'
1980
+ d4.description = 'de3'
1981
+ I18n.locale = :en
1982
+ end
1983
+
1984
+ let(:criteria) do
1985
+ Dictionary.all.tap do |crit|
1986
+ crit.documents = [ d1, d2, d3, d4 ]
1987
+ end
1988
+ end
1989
+
1990
+ context "when getting the demongoized field" do
1991
+ let(:tallied) do
1992
+ context.tally(:description)
1993
+ end
1994
+
1995
+ it "returns the translation for the current locale" do
1996
+ expect(tallied).to eq("en1" => 3, "en2" => 1)
1997
+ end
1998
+ end
1999
+
2000
+ context "when getting a specific locale" do
2001
+ let(:tallied) do
2002
+ context.tally("description.de")
2003
+ end
2004
+
2005
+ it "returns the translation for the the specific locale" do
2006
+ expect(tallied).to eq("de1" => 2, "de2" => 1, "de3" => 1)
2007
+ end
2008
+ end
2009
+
2010
+ context "when getting the full hash" do
2011
+ let(:tallied) do
2012
+ context.tally("description_translations")
2013
+ end
2014
+
2015
+ it "returns the correct hash" do
2016
+ expect(tallied).to eq(
2017
+ {"de" => "de1", "en" => "en1" } => 2,
2018
+ {"de" => "de2", "en" => "en1" } => 1,
2019
+ {"de" => "de3", "en" => "en2" } => 1
2020
+ )
2021
+ end
2022
+ end
2023
+ end
2024
+
2025
+ context "when tallying an embedded localized field" do
2026
+ with_default_i18n_configs
2027
+
2028
+ let(:person1) { Person.create!(addresses: [ address1a, address1b ]) }
2029
+ let(:person2) { Person.create!(addresses: [ address2a, address2b ]) }
2030
+
2031
+ let(:address1a) { Address.new(name: "en1") }
2032
+ let(:address1b) { Address.new(name: "en2") }
2033
+ let(:address2a) { Address.new(name: "en1") }
2034
+ let(:address2b) { Address.new(name: "en3") }
2035
+
2036
+ before do
2037
+ I18n.locale = :en
2038
+ address1a
2039
+ address1b
2040
+ address2a
2041
+ address2b
2042
+ I18n.locale = :de
2043
+ address1a.name = "de1"
2044
+ address1b.name = "de2"
2045
+ address2a.name = "de1"
2046
+ address2b.name = "de3"
2047
+ person1
2048
+ person2
2049
+ I18n.locale = :en
2050
+ end
2051
+
2052
+ let(:criteria) do
2053
+ Person.all.tap do |crit|
2054
+ crit.documents = [ person1, person2 ]
2055
+ end
2056
+ end
2057
+
2058
+ context "when getting the demongoized field" do
2059
+ let(:tallied) do
2060
+ context.tally("addresses.name")
2061
+ end
2062
+
2063
+ it "returns the translation for the current locale" do
2064
+ expect(tallied).to eq(
2065
+ [ "en1", "en2" ] => 1,
2066
+ [ "en1", "en3" ] => 1,
2067
+ )
2068
+ end
2069
+ end
2070
+
2071
+ context "when getting a specific locale" do
2072
+ let(:tallied) do
2073
+ context.tally("addresses.name.de")
2074
+ end
2075
+
2076
+ it "returns the translation for the the specific locale" do
2077
+ expect(tallied).to eq(
2078
+ [ "de1", "de2" ] => 1,
2079
+ [ "de1", "de3" ] => 1,
2080
+ )
2081
+ end
2082
+ end
2083
+
2084
+ context "when getting the full hash" do
2085
+ let(:tallied) do
2086
+ context.tally("addresses.name_translations")
2087
+ end
2088
+
2089
+ it "returns the correct hash" do
2090
+ expect(tallied).to eq(
2091
+ [{ "de" => "de1", "en" => "en1" }, { "de" => "de2", "en" => "en2" }] => 1,
2092
+ [{ "de" => "de1", "en" => "en1" }, { "de" => "de3", "en" => "en3" }] => 1,
2093
+ )
2094
+ end
2095
+ end
2096
+ end
2097
+
2098
+ context "when tallying an embedded field" do
2099
+ let(:tally) do
2100
+ context.tally("label.name")
2101
+ end
2102
+
2103
+ it "returns the correct hash" do
2104
+ expect(tally).to eq("Atlantic" => 2, "Columbia" => 1)
2105
+ end
2106
+ end
2107
+
2108
+ context "when tallying an element in an embeds_many field" do
2109
+
2110
+ let(:tally) do
2111
+ context2.tally("fanatics.age")
2112
+ end
2113
+
2114
+ it "returns the correct hash" do
2115
+ expect(tally).to eq(
2116
+ [1, 2] => 2,
2117
+ [1, 3] => 1
2118
+ )
2119
+ end
2120
+ end
2121
+
2122
+ context "when tallying an embeds_many field" do
2123
+
2124
+ let(:tally) do
2125
+ context2.tally("fanatics")
2126
+ end
2127
+
2128
+ it "returns the correct hash" do
2129
+ expect(tally).to eq(
2130
+ fans1 => 1,
2131
+ fans2 => 1,
2132
+ fans3 => 1,
2133
+ )
2134
+ end
2135
+ end
2136
+
2137
+ context "when tallying a field of type array" do
2138
+
2139
+ let(:tally) do
2140
+ context2.tally("genres")
2141
+ end
2142
+
2143
+ it "returns the correct hash" do
2144
+ expect(tally).to eq(
2145
+ [1, 2] => 2,
2146
+ [1, 3] => 1
2147
+ )
2148
+ end
2149
+ end
2150
+
2151
+ context "when tallying an element from an array of hashes" do
2152
+
2153
+ let(:tally) do
2154
+ context.tally("genres.x")
2155
+ end
2156
+
2157
+ it "returns the correct hash without the nil keys" do
2158
+ expect(tally).to eq(
2159
+ [1, 2] => 2,
2160
+ [1, 3] => 1
2161
+ )
2162
+ end
2163
+ end
2164
+
2165
+ context "when tallying an element from an array of hashes; with duplicate" do
2166
+
2167
+ let(:band4) { Band.new(origin: "tally", genres: [ { x: 1 }, {x: 1} ] ) }
2168
+
2169
+ let(:criteria) do
2170
+ Band.where(origin: "tally").all.tap do |crit|
2171
+ crit.documents = [ band1, band2, band3, band4 ]
2172
+ end
2173
+ end
2174
+
2175
+ let(:tally) do
2176
+ context.tally("genres.x")
2177
+ end
2178
+
2179
+ it "returns the correct hash without the nil keys" do
2180
+ expect(tally).to eq(
2181
+ [1, 2] => 2,
2182
+ [1, 3] => 1,
2183
+ [1, 1] => 1,
2184
+ )
2185
+ end
2186
+ end
2187
+
2188
+ context "when tallying an aliased field of type array" do
2189
+
2190
+ let(:person1) { Person.new(array: [ 1, 2 ]) }
2191
+ let(:person2) { Person.new(array: [ 1, 3 ]) }
2192
+
2193
+ let(:criteria) do
2194
+ Person.all.tap do |crit|
2195
+ crit.documents = [ person1, person2 ]
2196
+ end
2197
+ end
2198
+
2199
+ let(:tally) do
2200
+ context.tally("array")
2201
+ end
2202
+
2203
+ it "returns the correct hash" do
2204
+ expect(tally).to eq(
2205
+ [1, 2] => 1,
2206
+ [1, 3] => 1
2207
+ )
2208
+ end
2209
+ end
2210
+
2211
+ context "when going multiple levels deep in arrays" do
2212
+
2213
+ let(:tally) do
2214
+ context.tally("genres.y.z")
2215
+ end
2216
+
2217
+ it "returns the correct hash" do
2218
+ expect(tally).to eq(
2219
+ [1, 2] => 2,
2220
+ [1, 3] => 1
2221
+ )
2222
+ end
2223
+ end
2224
+
2225
+ context "when going multiple levels deep in an array" do
2226
+
2227
+ let(:tally) do
2228
+ context.tally("genres.y.z")
2229
+ end
2230
+
2231
+ it "returns the correct hash" do
2232
+ expect(tally).to eq(
2233
+ [1, 2] => 2,
2234
+ [1, 3] => 1
2235
+ )
2236
+ end
2237
+ end
2238
+
2239
+ context "when tallying deeply nested arrays/embedded associations" do
2240
+
2241
+ let(:person1) { Person.new(addresses: [ Address.new(code: Code.new(deepest: Deepest.new(array: [ { y: { z: 1 } }, { y: { z: 2 } } ]))) ]) }
2242
+ let(:person2) { Person.new(addresses: [ Address.new(code: Code.new(deepest: Deepest.new(array: [ { y: { z: 1 } }, { y: { z: 2 } } ]))) ]) }
2243
+ let(:person3) { Person.new(addresses: [ Address.new(code: Code.new(deepest: Deepest.new(array: [ { y: { z: 1 } }, { y: { z: 3 } } ]))) ]) }
2244
+
2245
+ let(:criteria) do
2246
+ Person.all.tap do |crit|
2247
+ crit.documents = [ person1, person2, person3 ]
2248
+ end
2249
+ end
2250
+
2251
+ let(:tally) do
2252
+ context.tally("addresses.code.deepest.array.y.z")
2253
+ end
2254
+
2255
+ it "returns the correct hash" do
2256
+ expect(tally).to eq(
2257
+ [ [ 1, 2 ] ] => 2,
2258
+ [ [ 1, 3 ] ] => 1
2259
+ )
2260
+ end
2261
+ end
2262
+
2263
+ context "when tallying deeply nested arrays/embedded associations" do
2264
+
2265
+ let(:person1) do
2266
+ Person.new(addresses: [ Address.new(code: Code.new(deepest: Deepest.new(array: [ { y: { z: 1 } }, { y: { z: 2 } } ]))),
2267
+ Address.new(code: Code.new(deepest: Deepest.new(array: [ { y: { z: 1 } }, { y: { z: 2 } } ]))) ])
2268
+ end
2269
+
2270
+ let(:person2) do
2271
+ Person.new(addresses: [ Address.new(code: Code.new(deepest: Deepest.new(array: [ { y: { z: 1 } }, { y: { z: 2 } } ]))),
2272
+ Address.new(code: Code.new(deepest: Deepest.new(array: [ { y: { z: 1 } }, { y: { z: 2 } } ]))) ])
2273
+ end
2274
+
2275
+ let(:person3) do
2276
+ Person.new(addresses: [ Address.new(code: Code.new(deepest: Deepest.new(array: [ { y: { z: 1 } }, { y: { z: 3 } } ]))),
2277
+ Address.new(code: Code.new(deepest: Deepest.new(array: [ { y: { z: 1 } }, { y: { z: 3 } } ]))) ])
2278
+ end
2279
+
2280
+ let(:criteria) do
2281
+ Person.all.tap do |crit|
2282
+ crit.documents = [ person1, person2, person3 ]
2283
+ end
2284
+ end
2285
+
2286
+ let(:tally) do
2287
+ context.tally("addresses.code.deepest.array.y.z")
2288
+ end
2289
+
2290
+ it "returns the correct hash" do
2291
+ expect(tally).to eq(
2292
+ [ [ 1, 2 ], [ 1, 2 ] ] => 2,
2293
+ [ [ 1, 3 ], [ 1, 3 ] ] => 1
2294
+ )
2295
+ end
2296
+ end
2297
+
2298
+ context "when some keys are missing" do
2299
+
2300
+ let(:criteria) do
2301
+ Band.where(origin: "tally").all.tap do |crit|
2302
+ crit.documents = [ band1, band2, band3 ]
2303
+ 3.times{ crit.documents << Band.new(origin: "tally") }
2304
+ end
2305
+ end
2306
+
2307
+ let(:tally) do
2308
+ context.tally(:name)
2309
+ end
2310
+
2311
+ it "returns the correct hash" do
2312
+ expect(tally).to eq(
2313
+ "Depeche Mode" => 1,
2314
+ "New Order" => 1,
2315
+ "10,000 Maniacs" => 1,
2316
+ nil => 3
2317
+ )
2318
+ end
2319
+ end
2320
+
2321
+ context "when the first element is an embeds_one" do
2322
+ let(:person1) { Person.create!(name: Name.new(translations: [ Translation.new(language: 1), Translation.new(language: 2) ])) }
2323
+ let(:person2) { Person.create!(name: Name.new(translations: [ Translation.new(language: 1), Translation.new(language: 2) ])) }
2324
+ let(:person3) { Person.create!(name: Name.new(translations: [ Translation.new(language: 1), Translation.new(language: 3) ])) }
2325
+
2326
+ let(:criteria) do
2327
+ Person.all.tap do |crit|
2328
+ crit.documents = [ person1, person2, person3 ]
2329
+ end
2330
+ end
2331
+
2332
+ let(:tally) do
2333
+ context.tally("name.translations.language")
2334
+ end
2335
+
2336
+ it "returns the correct hash" do
2337
+ expect(tally).to eq(
2338
+ [1, 2] => 2,
2339
+ [1, 3] => 1
2340
+ )
989
2341
  end
990
2342
  end
991
2343
  end
@@ -1252,19 +2604,19 @@ describe Mongoid::Contextual::Memory do
1252
2604
  describe "#update" do
1253
2605
 
1254
2606
  let(:person) do
1255
- Person.create
2607
+ Person.create!
1256
2608
  end
1257
2609
 
1258
2610
  let(:hobrecht) do
1259
- person.addresses.create(street: "hobrecht")
2611
+ person.addresses.create!(street: "hobrecht")
1260
2612
  end
1261
2613
 
1262
2614
  let(:friedel) do
1263
- person.addresses.create(street: "friedel")
2615
+ person.addresses.create!(street: "friedel")
1264
2616
  end
1265
2617
 
1266
2618
  let(:pfluger) do
1267
- person.addresses.create(street: "pfluger")
2619
+ person.addresses.create!(street: "pfluger")
1268
2620
  end
1269
2621
 
1270
2622
  context "when the documents are embedded one level" do
@@ -1324,11 +2676,11 @@ describe Mongoid::Contextual::Memory do
1324
2676
  context "when the documents are embedded multiple levels" do
1325
2677
 
1326
2678
  let!(:home) do
1327
- hobrecht.locations.create(name: "home")
2679
+ hobrecht.locations.create!(name: "home")
1328
2680
  end
1329
2681
 
1330
2682
  let!(:work) do
1331
- hobrecht.locations.create(name: "work")
2683
+ hobrecht.locations.create!(name: "work")
1332
2684
  end
1333
2685
 
1334
2686
  let(:criteria) do
@@ -1392,19 +2744,19 @@ describe Mongoid::Contextual::Memory do
1392
2744
  describe "#update_all" do
1393
2745
 
1394
2746
  let(:person) do
1395
- Person.create
2747
+ Person.create!
1396
2748
  end
1397
2749
 
1398
2750
  let(:hobrecht) do
1399
- person.addresses.create(street: "hobrecht")
2751
+ person.addresses.create!(street: "hobrecht")
1400
2752
  end
1401
2753
 
1402
2754
  let(:friedel) do
1403
- person.addresses.create(street: "friedel")
2755
+ person.addresses.create!(street: "friedel")
1404
2756
  end
1405
2757
 
1406
2758
  let(:pfluger) do
1407
- person.addresses.create(street: "pfluger")
2759
+ person.addresses.create!(street: "pfluger")
1408
2760
  end
1409
2761
 
1410
2762
  context 'when there is a collation on the criteria' do
@@ -1423,7 +2775,7 @@ describe Mongoid::Contextual::Memory do
1423
2775
  context "when the documents are empty" do
1424
2776
 
1425
2777
  let(:person_two) do
1426
- Person.create
2778
+ Person.create!
1427
2779
  end
1428
2780
 
1429
2781
  let(:criteria) do
@@ -1526,11 +2878,11 @@ describe Mongoid::Contextual::Memory do
1526
2878
  context "when the documents are embedded multiple levels" do
1527
2879
 
1528
2880
  let!(:home) do
1529
- hobrecht.locations.create(name: "home")
2881
+ hobrecht.locations.create!(name: "home")
1530
2882
  end
1531
2883
 
1532
2884
  let!(:work) do
1533
- hobrecht.locations.create(name: "work")
2885
+ hobrecht.locations.create!(name: "work")
1534
2886
  end
1535
2887
 
1536
2888
  let(:criteria) do