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,15 +1,20 @@
1
1
  # frozen_string_literal: true
2
- # encoding: utf-8
2
+ # rubocop:todo all
3
3
 
4
+ require 'mongoid/atomic_update_preparer'
5
+ require "mongoid/contextual/mongo/documents_loader"
4
6
  require "mongoid/contextual/atomic"
5
7
  require "mongoid/contextual/aggregable/mongo"
6
8
  require "mongoid/contextual/command"
7
- require "mongoid/contextual/geo_near"
8
9
  require "mongoid/contextual/map_reduce"
9
10
  require "mongoid/association/eager_loadable"
10
11
 
11
12
  module Mongoid
12
13
  module Contextual
14
+
15
+ # Context object used for performing bulk query and persistence
16
+ # operations on documents which are persisted in the database and
17
+ # have not been loaded into application memory.
13
18
  class Mongo
14
19
  extend Forwardable
15
20
  include Enumerable
@@ -19,8 +24,6 @@ module Mongoid
19
24
  include Queryable
20
25
 
21
26
  # Options constant.
22
- #
23
- # @since 5.0.0
24
27
  OPTIONS = [ :hint,
25
28
  :limit,
26
29
  :skip,
@@ -38,17 +41,17 @@ module Mongoid
38
41
  # @attribute [r] view The Mongo collection view.
39
42
  attr_reader :view
40
43
 
41
- # Is the context cached?
44
+ # Run an explain on the criteria.
42
45
  #
43
- # @example Is the context cached?
44
- # context.cached?
46
+ # @example Explain the criteria.
47
+ # Band.where(name: "Depeche Mode").explain
45
48
  #
46
- # @return [ true, false ] If the context is cached.
49
+ # @param [ Hash ] options customizable options (See Mongo::Collection::View::Explainable)
47
50
  #
48
- # @since 3.0.0
49
- def cached?
50
- !!@cache
51
- end
51
+ # @return [ Hash ] The explain result.
52
+ def_delegator :view, :explain
53
+
54
+ attr_reader :documents_loader
52
55
 
53
56
  # Get the number of documents matching the query.
54
57
  #
@@ -67,11 +70,16 @@ module Mongoid
67
70
  # into the count.
68
71
  #
69
72
  # @return [ Integer ] The number of matches.
70
- #
71
- # @since 3.0.0
72
73
  def count(options = {}, &block)
73
74
  return super(&block) if block_given?
74
- try_cache(:count) { view.count_documents(options) }
75
+
76
+ if valid_for_count_documents?
77
+ view.count_documents(options)
78
+ else
79
+ # TODO: Remove this when we remove the deprecated for_js API.
80
+ # https://jira.mongodb.org/browse/MONGOID-5681
81
+ view.count(options)
82
+ end
75
83
  end
76
84
 
77
85
  # Get the estimated number of documents matching the query.
@@ -88,9 +96,13 @@ module Mongoid
88
96
  # @return [ Integer ] The number of matches.
89
97
  def estimated_count(options = {})
90
98
  unless self.criteria.selector.empty?
91
- raise Mongoid::Errors::InvalidEstimatedCountCriteria.new(self.klass)
99
+ if klass.default_scoping?
100
+ raise Mongoid::Errors::InvalidEstimatedCountScoping.new(self.klass)
101
+ else
102
+ raise Mongoid::Errors::InvalidEstimatedCountCriteria.new(self.klass)
103
+ end
92
104
  end
93
- try_cache(:estimated_count) { view.estimated_document_count(options) }
105
+ view.estimated_document_count(options)
94
106
  end
95
107
 
96
108
  # Delete all documents in the database that match the selector.
@@ -99,8 +111,6 @@ module Mongoid
99
111
  # context.delete
100
112
  #
101
113
  # @return [ nil ] Nil.
102
- #
103
- # @since 3.0.0
104
114
  def delete
105
115
  view.delete_many.deleted_count
106
116
  end
@@ -112,8 +122,6 @@ module Mongoid
112
122
  # context.destroy
113
123
  #
114
124
  # @return [ nil ] Nil.
115
- #
116
- # @since 3.0.0
117
125
  def destroy
118
126
  each.inject(0) do |count, doc|
119
127
  doc.destroy
@@ -128,14 +136,15 @@ module Mongoid
128
136
  # @example Get the distinct values.
129
137
  # context.distinct(:name)
130
138
  #
131
- # @param [ String, Symbol ] field The name of the field.
139
+ # @param [ String | Symbol ] field The name of the field.
132
140
  #
133
141
  # @return [ Array<Object> ] The distinct values for the field.
134
- #
135
- # @since 3.0.0
136
142
  def distinct(field)
137
- view.distinct(klass.database_field_name(field)).map do |value|
138
- value.class.demongoize(value)
143
+ name = klass.cleanse_localized_field_names(field)
144
+
145
+ view.distinct(name).map do |value|
146
+ is_translation = "#{name}_translations" == field.to_s
147
+ recursive_demongoize(name, value, is_translation)
139
148
  end
140
149
  end
141
150
 
@@ -148,14 +157,11 @@ module Mongoid
148
157
  # end
149
158
  #
150
159
  # @return [ Enumerator ] The enumerator.
151
- #
152
- # @since 3.0.0
153
160
  def each(&block)
154
161
  if block_given?
155
162
  documents_for_iteration.each do |doc|
156
163
  yield_document(doc, &block)
157
164
  end
158
- @cache_loaded = true
159
165
  self
160
166
  else
161
167
  to_enum
@@ -167,34 +173,30 @@ module Mongoid
167
173
  # @example Do any documents exist for the context.
168
174
  # context.exists?
169
175
  #
170
- # @note We don't use count here since Mongo does not use counted
171
- # b-tree indexes, unless a count is already cached then that is
172
- # used to determine the value.
176
+ # @example Do any documents exist for given _id.
177
+ # context.exists?(BSON::ObjectId(...))
173
178
  #
174
- # @return [ true, false ] If the count is more than zero.
179
+ # @example Do any documents exist for given conditions.
180
+ # context.exists?(name: "...")
175
181
  #
176
- # @since 3.0.0
177
- def exists?
178
- return !documents.empty? if cached? && cache_loaded?
179
- return @count > 0 if instance_variable_defined?(:@count)
180
-
181
- try_cache(:exists) do
182
- !!(view.projection(_id: 1).limit(1).first)
182
+ # @note We don't use count here since Mongo does not use counted
183
+ # b-tree indexes.
184
+ #
185
+ # @param [ Hash | Object | false ] id_or_conditions an _id to
186
+ # search for, a hash of conditions, nil or false.
187
+ #
188
+ # @return [ true | false ] If the count is more than zero.
189
+ # Always false if passed nil or false.
190
+ def exists?(id_or_conditions = :none)
191
+ return false if self.view.limit == 0
192
+ case id_or_conditions
193
+ when :none then !!(view.projection(_id: 1).limit(1).first)
194
+ when nil, false then false
195
+ when Hash then Mongo.new(criteria.where(id_or_conditions)).exists?
196
+ else Mongo.new(criteria.where(_id: id_or_conditions)).exists?
183
197
  end
184
198
  end
185
199
 
186
- # Run an explain on the criteria.
187
- #
188
- # @example Explain the criteria.
189
- # Band.where(name: "Depeche Mode").explain
190
- #
191
- # @return [ Hash ] The explain result.
192
- #
193
- # @since 3.0.0
194
- def explain
195
- view.explain
196
- end
197
-
198
200
  # Execute the find and modify command, used for MongoDB's
199
201
  # $findAndModify.
200
202
  #
@@ -204,13 +206,11 @@ module Mongoid
204
206
  # @param [ Hash ] update The updates.
205
207
  # @param [ Hash ] options The command options.
206
208
  #
207
- # @option options [ :before, :after ] :return_document Return the updated document
209
+ # @option options [ :before | :after ] :return_document Return the updated document
208
210
  # from before or after update.
209
- # @option options [ true, false ] :upsert Create the document if it doesn't exist.
211
+ # @option options [ true | false ] :upsert Create the document if it doesn't exist.
210
212
  #
211
213
  # @return [ Document ] The result of the command.
212
- #
213
- # @since 5.0.0
214
214
  def find_one_and_update(update, options = {})
215
215
  if doc = view.find_one_and_update(update, options)
216
216
  Factory.from_db(klass, doc)
@@ -226,13 +226,11 @@ module Mongoid
226
226
  # @param [ Hash ] replacement The replacement.
227
227
  # @param [ Hash ] options The command options.
228
228
  #
229
- # @option options [ :before, :after ] :return_document Return the updated document
229
+ # @option options [ :before | :after ] :return_document Return the updated document
230
230
  # from before or after update.
231
- # @option options [ true, false ] :upsert Create the document if it doesn't exist.
231
+ # @option options [ true | false ] :upsert Create the document if it doesn't exist.
232
232
  #
233
233
  # @return [ Document ] The result of the command.
234
- #
235
- # @since 5.0.0
236
234
  def find_one_and_replace(replacement, options = {})
237
235
  if doc = view.find_one_and_replace(replacement, options)
238
236
  Factory.from_db(klass, doc)
@@ -246,112 +244,22 @@ module Mongoid
246
244
  # context.find_one_and_delete
247
245
  #
248
246
  # @return [ Document ] The result of the command.
249
- #
250
- # @since 5.0.0
251
247
  def find_one_and_delete
252
248
  if doc = view.find_one_and_delete
253
249
  Factory.from_db(klass, doc)
254
250
  end
255
251
  end
256
252
 
257
- # Get the first document in the database for the criteria's selector.
258
- #
259
- # @example Get the first document.
260
- # context.first
261
- #
262
- # @note Automatically adding a sort on _id when no other sort is
263
- # defined on the criteria has the potential to cause bad performance issues.
264
- # If you experience unexpected poor performance when using #first or #last
265
- # and have no sort defined on the criteria, use the option { id_sort: :none }.
266
- # Be aware that #first/#last won't guarantee order in this case.
267
- #
268
- # @param [ Hash ] opts The options for the query returning the first document.
269
- #
270
- # @option opts [ :none ] :id_sort Don't apply a sort on _id if no other sort
271
- # is defined on the criteria.
272
- #
273
- # @return [ Document ] The first document.
274
- #
275
- # @since 3.0.0
276
- def first(opts = {})
277
- return documents.first if cached? && cache_loaded?
278
- try_cache(:first) do
279
- if sort = view.sort || ({ _id: 1 } unless opts[:id_sort] == :none)
280
- if raw_doc = view.sort(sort).limit(1).first
281
- doc = Factory.from_db(klass, raw_doc, criteria)
282
- eager_load([doc]).first
283
- end
284
- else
285
- if raw_doc = view.limit(1).first
286
- doc = Factory.from_db(klass, raw_doc, criteria)
287
- eager_load([doc]).first
288
- end
289
- end
290
- end
291
- end
292
- alias :one :first
293
-
294
253
  # Return the first result without applying sort
295
254
  #
296
255
  # @api private
297
- #
298
- # @since 4.0.2
299
256
  def find_first
300
- return documents.first if cached? && cache_loaded?
301
257
  if raw_doc = view.first
302
258
  doc = Factory.from_db(klass, raw_doc, criteria)
303
259
  eager_load([doc]).first
304
260
  end
305
261
  end
306
262
 
307
- # Execute a $geoNear command against the database.
308
- #
309
- # @example Find documents close to 10, 10.
310
- # context.geo_near([ 10, 10 ])
311
- #
312
- # @example Find with spherical distance.
313
- # context.geo_near([ 10, 10 ]).spherical
314
- #
315
- # @example Find with a max distance.
316
- # context.geo_near([ 10, 10 ]).max_distance(0.5)
317
- #
318
- # @example Provide a distance multiplier.
319
- # context.geo_near([ 10, 10 ]).distance_multiplier(1133)
320
- #
321
- # @param [ Array<Float> ] coordinates The coordinates.
322
- #
323
- # @return [ GeoNear ] The GeoNear command.
324
- #
325
- # @deprecated
326
- #
327
- # @since 3.1.0
328
- def geo_near(coordinates)
329
- GeoNear.new(collection, criteria, coordinates)
330
- end
331
-
332
- # Invoke the block for each element of Contextual. Create a new array
333
- # containing the values returned by the block.
334
- #
335
- # If the symbol field name is passed instead of the block, additional
336
- # optimizations would be used.
337
- #
338
- # @example Map by some field.
339
- # context.map(:field1)
340
- #
341
- # @example Map with block.
342
- # context.map(&:field1)
343
- #
344
- # @param [ Symbol ] field The field name.
345
- #
346
- # @return [ Array ] The result of mapping.
347
- def map(field = nil, &block)
348
- if block_given?
349
- super(&block)
350
- else
351
- criteria.pluck(field)
352
- end
353
- end
354
-
355
263
  # Create the new Mongo context. This delegates operations to the
356
264
  # underlying driver.
357
265
  #
@@ -359,10 +267,8 @@ module Mongoid
359
267
  # Mongo.new(criteria)
360
268
  #
361
269
  # @param [ Criteria ] criteria The criteria.
362
- #
363
- # @since 3.0.0
364
270
  def initialize(criteria)
365
- @criteria, @klass, @cache = criteria, criteria.klass, criteria.options[:cache]
271
+ @criteria, @klass = criteria, criteria.klass
366
272
  @collection = @klass.collection
367
273
  criteria.send(:merge_type_selection)
368
274
  @view = collection.find(criteria.selector, session: _session)
@@ -371,44 +277,15 @@ module Mongoid
371
277
 
372
278
  def_delegator :@klass, :database_field_name
373
279
 
374
- # Get the last document in the database for the criteria's selector.
375
- #
376
- # @example Get the last document.
377
- # context.last
378
- #
379
- # @note Automatically adding a sort on _id when no other sort is
380
- # defined on the criteria has the potential to cause bad performance issues.
381
- # If you experience unexpected poor performance when using #first or #last
382
- # and have no sort defined on the criteria, use the option { id_sort: :none }.
383
- # Be aware that #first/#last won't guarantee order in this case.
384
- #
385
- # @param [ Hash ] opts The options for the query returning the first document.
386
- #
387
- # @option opts [ :none ] :id_sort Don't apply a sort on _id if no other sort
388
- # is defined on the criteria.
389
- #
390
- # @since 3.0.0
391
- def last(opts = {})
392
- try_cache(:last) do
393
- with_inverse_sorting(opts) do
394
- if raw_doc = view.limit(1).first
395
- doc = Factory.from_db(klass, raw_doc, criteria)
396
- eager_load([doc]).first
397
- end
398
- end
399
- end
400
- end
401
-
402
- # Get's the number of documents matching the query selector.
280
+ # Returns the number of documents in the database matching
281
+ # the query selector.
403
282
  #
404
283
  # @example Get the length.
405
284
  # context.length
406
285
  #
407
286
  # @return [ Integer ] The number of documents.
408
- #
409
- # @since 3.0.0
410
287
  def length
411
- @length ||= self.count
288
+ self.count
412
289
  end
413
290
  alias :size :length
414
291
 
@@ -420,8 +297,6 @@ module Mongoid
420
297
  # @param [ Integer ] value The number of documents to return.
421
298
  #
422
299
  # @return [ Mongo ] The context.
423
- #
424
- # @since 3.0.0
425
300
  def limit(value)
426
301
  @view = view.limit(value) and self
427
302
  end
@@ -435,40 +310,165 @@ module Mongoid
435
310
  # @param [ String ] reduce The reduce js function.
436
311
  #
437
312
  # @return [ MapReduce ] The map/reduce lazy wrapper.
438
- #
439
- # @since 3.0.0
440
313
  def map_reduce(map, reduce)
441
314
  MapReduce.new(collection, criteria, map, reduce)
442
315
  end
443
316
 
444
- # Pluck the single field values from the database. Will return duplicates
445
- # if they exist and only works for top level fields.
317
+ # Pluck the field value(s) from the database. Returns one
318
+ # result for each document found in the database for
319
+ # the context. The results are normalized according to their
320
+ # Mongoid field types. Note that the results may include
321
+ # duplicates and nil values.
446
322
  #
447
323
  # @example Pluck a field.
448
324
  # context.pluck(:_id)
449
325
  #
450
- # @note This method will return the raw db values - it performs no custom
451
- # serialization.
452
- #
453
- # @param [ String, Symbol, Array ] fields Fields to pluck.
454
- #
455
- # @return [ Array<Object, Array> ] The plucked values.
326
+ # @param [ [ String | Symbol ]... ] *fields Field(s) to pluck,
327
+ # which may include nested fields using dot-notation.
456
328
  #
457
- # @since 3.1.0
329
+ # @return [ Array<Object> | Array<Array<Object>> ] The plucked values.
330
+ # If the *fields arg contains a single value, each result
331
+ # in the array will be a single value. Otherwise, each
332
+ # result in the array will be an array of values.
458
333
  def pluck(*fields)
334
+ # Multiple fields can map to the same field name. For example, plucking
335
+ # a field and its _translations field map to the same field in the database.
336
+ # because of this, we need to keep track of the fields requested.
337
+ normalized_field_names = []
459
338
  normalized_select = fields.inject({}) do |hash, f|
460
- hash[klass.database_field_name(f)] = 1
339
+ db_fn = klass.database_field_name(f)
340
+ normalized_field_names.push(db_fn)
341
+ hash[klass.cleanse_localized_field_names(f)] = true
461
342
  hash
462
343
  end
463
344
 
464
345
  view.projection(normalized_select).reduce([]) do |plucked, doc|
465
- values = normalized_select.keys.map do |n|
466
- n =~ /\./ ? doc[n.partition('.')[0]] : doc[n]
346
+ values = normalized_field_names.map do |n|
347
+ extract_value(doc, n)
467
348
  end
468
349
  plucked << (values.size == 1 ? values.first : values)
469
350
  end
470
351
  end
471
352
 
353
+ # Pick the single field values from the database.
354
+ #
355
+ # @example Pick a field.
356
+ # context.pick(:_id)
357
+ #
358
+ # @param [ [ String | Symbol ]... ] *fields Field(s) to pick.
359
+ #
360
+ # @return [ Object | Array<Object> ] The picked values.
361
+ def pick(*fields)
362
+ limit(1).pluck(*fields).first
363
+ end
364
+
365
+ # Take the given number of documents from the database.
366
+ #
367
+ # @example Take 10 documents
368
+ # context.take(10)
369
+ #
370
+ # @param [ Integer | nil ] limit The number of documents to return or nil.
371
+ #
372
+ # @return [ Document | Array<Document> ] The list of documents, or one
373
+ # document if no value was given.
374
+ def take(limit = nil)
375
+ if limit
376
+ limit(limit).to_a
377
+ else
378
+ # Do to_a first so that the Mongo#first method is not used and the
379
+ # result is not sorted.
380
+ limit(1).to_a.first
381
+ end
382
+ end
383
+
384
+ # Take one document from the database and raise an error if there are none.
385
+ #
386
+ # @example Take a document
387
+ # context.take!
388
+ #
389
+ # @return [ Document ] The document.
390
+ #
391
+ # @raise [ Mongoid::Errors::DocumentNotFound ] raises when there are no
392
+ # documents to take.
393
+ def take!
394
+ # Do to_a first so that the Mongo#first method is not used and the
395
+ # result is not sorted.
396
+ if fst = limit(1).to_a.first
397
+ fst
398
+ else
399
+ raise Errors::DocumentNotFound.new(klass, nil, nil)
400
+ end
401
+ end
402
+
403
+ # Get a hash of counts for the values of a single field. For example,
404
+ # if the following documents were in the database:
405
+ #
406
+ # { _id: 1, age: 21 }
407
+ # { _id: 2, age: 21 }
408
+ # { _id: 3, age: 22 }
409
+ #
410
+ # Model.tally("age")
411
+ #
412
+ # would yield the following result:
413
+ #
414
+ # { 21 => 2, 22 => 1 }
415
+ #
416
+ # When tallying a field inside an array or embeds_many association:
417
+ #
418
+ # { _id: 1, array: [ { x: 1 }, { x: 2 } ] }
419
+ # { _id: 2, array: [ { x: 1 }, { x: 2 } ] }
420
+ # { _id: 3, array: [ { x: 1 }, { x: 3 } ] }
421
+ #
422
+ # Model.tally("array.x")
423
+ #
424
+ # The keys of the resulting hash are arrays:
425
+ #
426
+ # { [ 1, 2 ] => 2, [ 1, 3 ] => 1 }
427
+ #
428
+ # Note that if tallying an element in an array of hashes, and the key
429
+ # doesn't exist in some of the hashes, tally will not include those
430
+ # nil keys in the resulting hash:
431
+ #
432
+ # { _id: 1, array: [ { x: 1 }, { x: 2 }, { y: 3 } ] }
433
+ #
434
+ # Model.tally("array.x")
435
+ # # => { [ 1, 2 ] => 1 }
436
+ #
437
+ # @param [ String | Symbol ] field The field name.
438
+ #
439
+ # @return [ Hash ] The hash of counts.
440
+ def tally(field)
441
+ name = klass.cleanse_localized_field_names(field)
442
+
443
+ fld = klass.traverse_association_tree(name)
444
+ pipeline = [ { "$group" => { _id: "$#{name}", counts: { "$sum": 1 } } } ]
445
+ pipeline.unshift("$match" => view.filter) unless view.filter.blank?
446
+
447
+ collection.aggregate(pipeline).reduce({}) do |tallies, doc|
448
+ is_translation = "#{name}_translations" == field.to_s
449
+ val = doc["_id"]
450
+
451
+ key = if val.is_a?(Array)
452
+ val.map do |v|
453
+ demongoize_with_field(fld, v, is_translation)
454
+ end
455
+ else
456
+ demongoize_with_field(fld, val, is_translation)
457
+ end
458
+
459
+ # The only time where a key will already exist in the tallies hash
460
+ # is when the values are stored differently in the database, but
461
+ # demongoize to the same value. A good example of when this happens
462
+ # is when using localized fields. While the server query won't group
463
+ # together hashes that have other values in different languages, the
464
+ # demongoized value is just the translation in the current locale,
465
+ # which can be the same across multiple of those unequal hashes.
466
+ tallies[key] ||= 0
467
+ tallies[key] += doc["counts"]
468
+ tallies
469
+ end
470
+ end
471
+
472
472
  # Skips the provided number of documents.
473
473
  #
474
474
  # @example Skip the documents.
@@ -477,8 +477,6 @@ module Mongoid
477
477
  # @param [ Integer ] value The number of documents to skip.
478
478
  #
479
479
  # @return [ Mongo ] The context.
480
- #
481
- # @since 3.0.0
482
480
  def skip(value)
483
481
  @view = view.skip(value) and self
484
482
  end
@@ -492,8 +490,6 @@ module Mongoid
492
490
  # pairs.
493
491
  #
494
492
  # @return [ Mongo ] The context.
495
- #
496
- # @since 3.0.0
497
493
  def sort(values = nil, &block)
498
494
  if block_given?
499
495
  super(&block)
@@ -516,9 +512,7 @@ module Mongoid
516
512
  # @option opts [ Array ] :array_filters A set of filters specifying to which array elements
517
513
  # an update should apply.
518
514
  #
519
- # @return [ nil, false ] False if no attributes were provided.
520
- #
521
- # @since 3.0.0
515
+ # @return [ nil | false ] False if no attributes were provided.
522
516
  def update(attributes = nil, opts = {})
523
517
  update_documents(attributes, :update_one, opts)
524
518
  end
@@ -534,33 +528,257 @@ module Mongoid
534
528
  # @option opts [ Array ] :array_filters A set of filters specifying to which array elements
535
529
  # an update should apply.
536
530
  #
537
- # @return [ nil, false ] False if no attributes were provided.
538
- #
539
- # @since 3.0.0
531
+ # @return [ nil | false ] False if no attributes were provided.
540
532
  def update_all(attributes = nil, opts = {})
541
533
  update_documents(attributes, :update_many, opts)
542
534
  end
543
535
 
544
- private
536
+ # Get the first document in the database for the criteria's selector.
537
+ #
538
+ # @example Get the first document.
539
+ # context.first
540
+ #
541
+ # @note Automatically adding a sort on _id when no other sort is
542
+ # defined on the criteria has the potential to cause bad performance issues.
543
+ # If you experience unexpected poor performance when using #first or #last
544
+ # and have no sort defined on the criteria, use #take instead.
545
+ # Be aware that #take won't guarantee order.
546
+ #
547
+ # @param [ Integer ] limit The number of documents to return.
548
+ #
549
+ # @return [ Document | nil ] The first document or nil if none is found.
550
+ def first(limit = nil)
551
+ if limit.nil?
552
+ retrieve_nth(0)
553
+ else
554
+ retrieve_nth_with_limit(0, limit)
555
+ end
556
+ end
557
+ alias :one :first
545
558
 
546
- # yield the block given or return the cached value
559
+ # Get the first document in the database for the criteria's selector or
560
+ # raise an error if none is found.
561
+ #
562
+ # @example Get the first document.
563
+ # context.first!
564
+ #
565
+ # @note Automatically adding a sort on _id when no other sort is
566
+ # defined on the criteria has the potential to cause bad performance issues.
567
+ # If you experience unexpected poor performance when using #first! or #last!
568
+ # and have no sort defined on the criteria, use #take! instead.
569
+ # Be aware that #take! won't guarantee order.
547
570
  #
548
- # @param [ String, Symbol ] key The instance variable name
571
+ # @return [ Document ] The first document.
549
572
  #
550
- # @return the result of the block
573
+ # @raise [ Mongoid::Errors::DocumentNotFound ] raises when there are no
574
+ # documents available.
575
+ def first!
576
+ first || raise_document_not_found_error
577
+ end
578
+
579
+ # Get the last document in the database for the criteria's selector.
551
580
  #
552
- # @since 3.1.4
553
- def try_cache(key, &block)
554
- unless cached?
555
- yield
581
+ # @example Get the last document.
582
+ # context.last
583
+ #
584
+ # @note Automatically adding a sort on _id when no other sort is
585
+ # defined on the criteria has the potential to cause bad performance issues.
586
+ # If you experience unexpected poor performance when using #first or #last
587
+ # and have no sort defined on the criteria, use #take instead.
588
+ # Be aware that #take won't guarantee order.
589
+ #
590
+ # @param [ Integer ] limit The number of documents to return.
591
+ #
592
+ # @return [ Document | nil ] The last document or nil if none is found.
593
+ def last(limit = nil)
594
+ if limit.nil?
595
+ retrieve_nth_to_last(0)
556
596
  else
557
- unless ret = instance_variable_get("@#{key}")
558
- instance_variable_set("@#{key}", ret = yield)
559
- end
560
- ret
597
+ retrieve_nth_to_last_with_limit(0, limit)
561
598
  end
562
599
  end
563
600
 
601
+ # Get the last document in the database for the criteria's selector or
602
+ # raise an error if none is found.
603
+ #
604
+ # @example Get the last document.
605
+ # context.last!
606
+ #
607
+ # @note Automatically adding a sort on _id when no other sort is
608
+ # defined on the criteria has the potential to cause bad performance issues.
609
+ # If you experience unexpected poor performance when using #first! or #last!
610
+ # and have no sort defined on the criteria, use #take! instead.
611
+ # Be aware that #take! won't guarantee order.
612
+ #
613
+ # @return [ Document ] The last document.
614
+ #
615
+ # @raise [ Mongoid::Errors::DocumentNotFound ] raises when there are no
616
+ # documents available.
617
+ def last!
618
+ last || raise_document_not_found_error
619
+ end
620
+
621
+ # Get the second document in the database for the criteria's selector.
622
+ #
623
+ # @example Get the second document.
624
+ # context.second
625
+ #
626
+ # @return [ Document | nil ] The second document or nil if none is found.
627
+ def second
628
+ retrieve_nth(1)
629
+ end
630
+
631
+ # Get the second document in the database for the criteria's selector or
632
+ # raise an error if none is found.
633
+ #
634
+ # @example Get the second document.
635
+ # context.second!
636
+ #
637
+ # @return [ Document ] The second document.
638
+ #
639
+ # @raise [ Mongoid::Errors::DocumentNotFound ] raises when there are no
640
+ # documents available.
641
+ def second!
642
+ second || raise_document_not_found_error
643
+ end
644
+
645
+ # Get the third document in the database for the criteria's selector.
646
+ #
647
+ # @example Get the third document.
648
+ # context.third
649
+ #
650
+ # @return [ Document | nil ] The third document or nil if none is found.
651
+ def third
652
+ retrieve_nth(2)
653
+ end
654
+
655
+ # Get the third document in the database for the criteria's selector or
656
+ # raise an error if none is found.
657
+ #
658
+ # @example Get the third document.
659
+ # context.third!
660
+ #
661
+ # @return [ Document ] The third document.
662
+ #
663
+ # @raise [ Mongoid::Errors::DocumentNotFound ] raises when there are no
664
+ # documents available.
665
+ def third!
666
+ third || raise_document_not_found_error
667
+ end
668
+
669
+ # Get the fourth document in the database for the criteria's selector.
670
+ #
671
+ # @example Get the fourth document.
672
+ # context.fourth
673
+ #
674
+ # @return [ Document | nil ] The fourth document or nil if none is found.
675
+ def fourth
676
+ retrieve_nth(3)
677
+ end
678
+
679
+ # Get the fourth document in the database for the criteria's selector or
680
+ # raise an error if none is found.
681
+ #
682
+ # @example Get the fourth document.
683
+ # context.fourth!
684
+ #
685
+ # @return [ Document ] The fourth document.
686
+ #
687
+ # @raise [ Mongoid::Errors::DocumentNotFound ] raises when there are no
688
+ # documents available.
689
+ def fourth!
690
+ fourth || raise_document_not_found_error
691
+ end
692
+
693
+ # Get the fifth document in the database for the criteria's selector.
694
+ #
695
+ # @example Get the fifth document.
696
+ # context.fifth
697
+ #
698
+ # @return [ Document | nil ] The fifth document or nil if none is found.
699
+ def fifth
700
+ retrieve_nth(4)
701
+ end
702
+
703
+ # Get the fifth document in the database for the criteria's selector or
704
+ # raise an error if none is found.
705
+ #
706
+ # @example Get the fifth document.
707
+ # context.fifth!
708
+ #
709
+ # @return [ Document ] The fifth document.
710
+ #
711
+ # @raise [ Mongoid::Errors::DocumentNotFound ] raises when there are no
712
+ # documents available.
713
+ def fifth!
714
+ fifth || raise_document_not_found_error
715
+ end
716
+
717
+ # Get the second to last document in the database for the criteria's
718
+ # selector.
719
+ #
720
+ # @example Get the second to last document.
721
+ # context.second_to_last
722
+ #
723
+ # @return [ Document | nil ] The second to last document or nil if none
724
+ # is found.
725
+ def second_to_last
726
+ retrieve_nth_to_last(1)
727
+ end
728
+
729
+ # Get the second to last document in the database for the criteria's
730
+ # selector or raise an error if none is found.
731
+ #
732
+ # @example Get the second to last document.
733
+ # context.second_to_last!
734
+ #
735
+ # @return [ Document ] The second to last document.
736
+ #
737
+ # @raise [ Mongoid::Errors::DocumentNotFound ] raises when there are no
738
+ # documents available.
739
+ def second_to_last!
740
+ second_to_last || raise_document_not_found_error
741
+ end
742
+
743
+ # Get the third to last document in the database for the criteria's
744
+ # selector.
745
+ #
746
+ # @example Get the third to last document.
747
+ # context.third_to_last
748
+ #
749
+ # @return [ Document | nil ] The third to last document or nil if none
750
+ # is found.
751
+ def third_to_last
752
+ retrieve_nth_to_last(2)
753
+ end
754
+
755
+ # Get the third to last document in the database for the criteria's
756
+ # selector or raise an error if none is found.
757
+ #
758
+ # @example Get the third to last document.
759
+ # context.third_to_last!
760
+ #
761
+ # @return [ Document ] The third to last document.
762
+ #
763
+ # @raise [ Mongoid::Errors::DocumentNotFound ] raises when there are no
764
+ # documents available.
765
+ def third_to_last!
766
+ third_to_last || raise_document_not_found_error
767
+ end
768
+
769
+ # Schedule a task to load documents for the context.
770
+ #
771
+ # Depending on the Mongoid configuration, the scheduled task can be executed
772
+ # immediately on the caller's thread, or can be scheduled for an
773
+ # asynchronous execution.
774
+ #
775
+ # @api private
776
+ def load_async
777
+ @documents_loader ||= DocumentsLoader.new(view, klass, criteria)
778
+ end
779
+
780
+ private
781
+
564
782
  # Update the documents for the provided method.
565
783
  #
566
784
  # @api private
@@ -571,13 +789,11 @@ module Mongoid
571
789
  # @param [ Hash ] attributes The updates.
572
790
  # @param [ Symbol ] method The method to use.
573
791
  #
574
- # @return [ true, false ] If the update succeeded.
575
- #
576
- # @since 3.0.4
792
+ # @return [ true | false ] If the update succeeded.
577
793
  def update_documents(attributes, method = :update_one, opts = {})
578
794
  return false unless attributes
579
- attributes = Hash[attributes.map { |k, v| [klass.database_field_name(k.to_s), v] }]
580
- view.send(method, attributes.__consolidate__(klass), opts)
795
+
796
+ view.send(method, AtomicUpdatePreparer.prepare(attributes, klass), opts)
581
797
  end
582
798
 
583
799
  # Apply the field limitations.
@@ -586,8 +802,6 @@ module Mongoid
586
802
  #
587
803
  # @example Apply the field limitations.
588
804
  # context.apply_fields
589
- #
590
- # @since 3.0.0
591
805
  def apply_fields
592
806
  if spec = criteria.options[:fields]
593
807
  @view = view.projection(spec)
@@ -600,8 +814,6 @@ module Mongoid
600
814
  #
601
815
  # @example Apply all options.
602
816
  # context.apply_options
603
- #
604
- # @since 3.1.0
605
817
  def apply_options
606
818
  apply_fields
607
819
  OPTIONS.each do |name|
@@ -618,8 +830,6 @@ module Mongoid
618
830
  #
619
831
  # @example Apply the skip option.
620
832
  # context.apply_option(:skip)
621
- #
622
- # @since 3.1.0
623
833
  def apply_option(name)
624
834
  if spec = criteria.options[name]
625
835
  @view = view.send(name, spec)
@@ -629,115 +839,234 @@ module Mongoid
629
839
  # Map the inverse sort symbols to the correct MongoDB values.
630
840
  #
631
841
  # @api private
842
+ def inverse_sorting
843
+ sort = view.sort || { _id: 1 }
844
+ Hash[sort.map{|k, v| [k, -1*v]}]
845
+ end
846
+
847
+ # Get the documents the context should iterate.
848
+ #
849
+ # If the documents have been already preloaded by `Document::Loader`
850
+ # instance, they will be used.
632
851
  #
633
- # @example Apply the inverse sorting params to the given block
634
- # context.with_inverse_sorting
852
+ # @return [ Array<Document> | Mongo::Collection::View ] The docs to iterate.
635
853
  #
636
- # @since 3.0.0
637
- def with_inverse_sorting(opts = {})
638
- begin
639
- if sort = criteria.options[:sort] || ( { _id: 1 } unless opts[:id_sort] == :none )
640
- @view = view.sort(Hash[sort.map{|k, v| [k, -1*v]}])
854
+ # @api private
855
+ def documents_for_iteration
856
+ if @documents_loader
857
+ if @documents_loader.started?
858
+ @documents_loader.value!
859
+ else
860
+ @documents_loader.unschedule
861
+ @documents_loader.execute
641
862
  end
642
- yield
643
- ensure
644
- apply_option(:sort)
863
+ else
864
+ return view unless eager_loadable?
865
+ docs = view.map do |doc|
866
+ Factory.from_db(klass, doc, criteria)
867
+ end
868
+ eager_load(docs)
645
869
  end
646
870
  end
647
871
 
648
- # Is the cache able to be added to?
872
+ # Yield to the document.
649
873
  #
650
874
  # @api private
651
875
  #
652
- # @example Is the context cacheable?
653
- # context.cacheable?
654
- #
655
- # @return [ true, false ] If caching, and the cache isn't loaded.
876
+ # @example Yield the document.
877
+ # context.yield_document(doc) do |doc|
878
+ # ...
879
+ # end
656
880
  #
657
- # @since 3.0.0
658
- def cacheable?
659
- cached? && !cache_loaded?
881
+ # @param [ Document ] document The document to yield to.
882
+ def yield_document(document, &block)
883
+ doc = document.respond_to?(:_id) ?
884
+ document : Factory.from_db(klass, document, criteria)
885
+ yield(doc)
660
886
  end
661
887
 
662
- # Is the cache fully loaded? Will be true if caching after one full
663
- # iteration.
664
- #
665
- # @api private
666
- #
667
- # @example Is the cache loaded?
668
- # context.cache_loaded?
669
- #
670
- # @return [ true, false ] If the cache is loaded.
671
- #
672
- # @since 3.0.0
673
- def cache_loaded?
674
- !!@cache_loaded
888
+ def _session
889
+ @criteria.send(:_session)
675
890
  end
676
891
 
677
- # Get the documents for cached queries.
678
- #
679
- # @api private
680
- #
681
- # @example Get the cached documents.
682
- # context.documents
683
- #
684
- # @return [ Array<Document> ] The documents.
685
- #
686
- # @since 3.0.0
687
- def documents
688
- @documents ||= []
892
+ def acknowledged_write?
893
+ collection.write_concern.nil? || collection.write_concern.acknowledged?
689
894
  end
690
895
 
691
- # Get the documents the context should iterate. This follows 3 rules:
896
+ # Fetch the element from the given hash and demongoize it using the
897
+ # given field. If the obj is an array, map over it and call this method
898
+ # on all of its elements.
692
899
  #
693
- # 1. If the query is cached, and we already have documents loaded, use
694
- # them.
695
- # 2. If we are eager loading, then eager load the documents and use
696
- # those.
697
- # 3. Use the query.
900
+ # @param [ Hash | Array<Hash> ] obj The hash or array of hashes to fetch from.
901
+ # @param [ String ] meth The key to fetch from the hash.
902
+ # @param [ Field ] field The field to use for demongoization.
698
903
  #
699
- # @api private
904
+ # @return [ Object ] The demongoized value.
700
905
  #
701
- # @example Get the documents for iteration.
702
- # context.documents_for_iteration
906
+ # @api private
907
+ def fetch_and_demongoize(obj, meth, field)
908
+ if obj.is_a?(Array)
909
+ obj.map { |doc| fetch_and_demongoize(doc, meth, field) }
910
+ else
911
+ res = obj.try(:fetch, meth, nil)
912
+ field ? field.demongoize(res) : res.class.demongoize(res)
913
+ end
914
+ end
915
+
916
+ # Extracts the value for the given field name from the given attribute
917
+ # hash.
703
918
  #
704
- # @return [ Array<Document>, Mongo::Collection::View ] The docs to iterate.
919
+ # @param [ Hash ] attrs The attributes hash.
920
+ # @param [ String ] field_name The name of the field to extract.
705
921
  #
706
- # @since 3.0.0
707
- def documents_for_iteration
708
- return documents if cached? && !documents.empty?
709
- return view unless eager_loadable?
710
- docs = view.map{ |doc| Factory.from_db(klass, doc, criteria) }
711
- eager_load(docs)
922
+ # @param [ Object ] The value for the given field name
923
+ def extract_value(attrs, field_name)
924
+ i = 1
925
+ num_meths = field_name.count('.') + 1
926
+ curr = attrs.dup
927
+
928
+ klass.traverse_association_tree(field_name) do |meth, obj, is_field|
929
+ field = obj if is_field
930
+ is_translation = false
931
+ # If no association or field was found, check if the meth is an
932
+ # _translations field.
933
+ if obj.nil? & tr = meth.match(/(.*)_translations\z/)&.captures&.first
934
+ is_translation = true
935
+ meth = tr
936
+ end
937
+
938
+ # 1. If curr is an array fetch from all elements in the array.
939
+ # 2. If the field is localized, and is not an _translations field
940
+ # (_translations fields don't show up in the fields hash).
941
+ # - If this is the end of the methods, return the translation for
942
+ # the current locale.
943
+ # - Otherwise, return the whole translations hash so the next method
944
+ # can select the language it wants.
945
+ # 3. If the meth is an _translations field, do not demongoize the
946
+ # value so the full hash is returned.
947
+ # 4. Otherwise, fetch and demongoize the value for the key meth.
948
+ curr = if curr.is_a? Array
949
+ res = fetch_and_demongoize(curr, meth, field)
950
+ res.empty? ? nil : res
951
+ elsif !is_translation && field&.localized?
952
+ if i < num_meths
953
+ curr.try(:fetch, meth, nil)
954
+ else
955
+ fetch_and_demongoize(curr, meth, field)
956
+ end
957
+ elsif is_translation
958
+ curr.try(:fetch, meth, nil)
959
+ else
960
+ fetch_and_demongoize(curr, meth, field)
961
+ end
962
+
963
+ i += 1
964
+ end
965
+ curr
712
966
  end
713
967
 
714
- # Yield to the document.
968
+ # Recursively demongoize the given value. This method recursively traverses
969
+ # the class tree to find the correct field to use to demongoize the value.
970
+ #
971
+ # @param [ String ] field_name The name of the field to demongoize.
972
+ # @param [ Object ] value The value to demongoize.
973
+ # @param [ true | false ] is_translation The field we are retrieving is an
974
+ # _translations field.
975
+ #
976
+ # @return [ Object ] The demongoized value.
977
+ def recursive_demongoize(field_name, value, is_translation)
978
+ field = klass.traverse_association_tree(field_name)
979
+ demongoize_with_field(field, value, is_translation)
980
+ end
981
+
982
+ # Demongoize the value for the given field. If the field is nil or the
983
+ # field is a translations field, the value is demongoized using its class.
715
984
  #
716
- # @api private
985
+ # @param [ Field ] field The field to use to demongoize.
986
+ # @param [ Object ] value The value to demongoize.
987
+ # @param [ true | false ] is_translation The field we are retrieving is an
988
+ # _translations field.
717
989
  #
718
- # @example Yield the document.
719
- # context.yield_document(doc) do |doc|
720
- # ...
721
- # end
990
+ # @return [ Object ] The demongoized value.
722
991
  #
723
- # @param [ Document ] document The document to yield to.
992
+ # @api private
993
+ def demongoize_with_field(field, value, is_translation)
994
+ if field
995
+ # If it's a localized field that's not a hash, don't demongoize
996
+ # again, we already have the translation. If it's an _translations
997
+ # field, don't demongoize, we want the full hash not just a
998
+ # specific translation.
999
+ # If it is a hash, and it's not a translations field, we need to
1000
+ # demongoize to get the correct translation.
1001
+ if field.localized? && (!value.is_a?(Hash) || is_translation)
1002
+ value.class.demongoize(value)
1003
+ else
1004
+ field.demongoize(value)
1005
+ end
1006
+ else
1007
+ value.class.demongoize(value)
1008
+ end
1009
+ end
1010
+
1011
+ # Process the raw documents retrieved for #first/#last.
724
1012
  #
725
- # @since 3.0.0
726
- def yield_document(document, &block)
727
- doc = document.respond_to?(:_id) ?
728
- document : Factory.from_db(klass, document, criteria)
729
- yield(doc)
730
- documents.push(doc) if cacheable?
1013
+ # @return [ Array<Document> | Document ] The list of documents or a
1014
+ # single document.
1015
+ def process_raw_docs(raw_docs, limit)
1016
+ docs = raw_docs.map do |d|
1017
+ Factory.from_db(klass, d, criteria)
1018
+ end
1019
+ docs = eager_load(docs)
1020
+ limit ? docs : docs.first
731
1021
  end
732
1022
 
733
- private
1023
+ # Queries whether the current context is valid for use with
1024
+ # the #count_documents? predicate. A context is valid if it
1025
+ # does not include a `$where` operator.
1026
+ #
1027
+ # @return [ true | false ] whether or not the current context
1028
+ # excludes a `$where` operator.
1029
+ #
1030
+ # TODO: Remove this method when we remove the deprecated for_js API.
1031
+ # https://jira.mongodb.org/browse/MONGOID-5681
1032
+ def valid_for_count_documents?(hash = view.filter)
1033
+ # Note that `view.filter` is a BSON::Document, and all keys in a
1034
+ # BSON::Document are strings; we don't need to worry about symbol
1035
+ # representations of `$where`.
1036
+ hash.keys.each do |key|
1037
+ return false if key == '$where'
1038
+ return false if hash[key].is_a?(Hash) && !valid_for_count_documents?(hash[key])
1039
+ end
734
1040
 
735
- def _session
736
- @criteria.send(:_session)
1041
+ true
737
1042
  end
738
1043
 
739
- def acknowledged_write?
740
- collection.write_concern.nil? || collection.write_concern.acknowledged?
1044
+ def raise_document_not_found_error
1045
+ raise Errors::DocumentNotFound.new(klass, nil, nil)
1046
+ end
1047
+
1048
+ def retrieve_nth(n)
1049
+ retrieve_nth_with_limit(n, 1).first
1050
+ end
1051
+
1052
+ def retrieve_nth_with_limit(n, limit)
1053
+ sort = view.sort || { _id: 1 }
1054
+ v = view.sort(sort).limit(limit || 1)
1055
+ v = v.skip(n) if n > 0
1056
+ if raw_docs = v.to_a
1057
+ process_raw_docs(raw_docs, limit)
1058
+ end
1059
+ end
1060
+
1061
+ def retrieve_nth_to_last(n)
1062
+ retrieve_nth_to_last_with_limit(n, 1).first
1063
+ end
1064
+
1065
+ def retrieve_nth_to_last_with_limit(n, limit)
1066
+ v = view.sort(inverse_sorting).skip(n).limit(limit || 1)
1067
+ v = v.skip(n) if n > 0
1068
+ raw_docs = v.to_a.reverse
1069
+ process_raw_docs(raw_docs, limit)
741
1070
  end
742
1071
  end
743
1072
  end