mongoid 7.4.3 → 8.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (383) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/README.md +3 -3
  4. data/Rakefile +25 -0
  5. data/lib/config/locales/en.yml +52 -28
  6. data/lib/mongoid/association/accessors.rb +38 -9
  7. data/lib/mongoid/association/bindable.rb +50 -2
  8. data/lib/mongoid/association/builders.rb +4 -2
  9. data/lib/mongoid/association/constrainable.rb +0 -1
  10. data/lib/mongoid/association/eager_loadable.rb +29 -7
  11. data/lib/mongoid/association/embedded/batchable.rb +33 -10
  12. data/lib/mongoid/association/embedded/cyclic.rb +1 -1
  13. data/lib/mongoid/association/embedded/embedded_in/binding.rb +24 -2
  14. data/lib/mongoid/association/embedded/embedded_in/proxy.rb +2 -2
  15. data/lib/mongoid/association/embedded/embedded_in.rb +3 -2
  16. data/lib/mongoid/association/embedded/embeds_many/binding.rb +1 -0
  17. data/lib/mongoid/association/embedded/embeds_many/buildable.rb +1 -1
  18. data/lib/mongoid/association/embedded/embeds_many/proxy.rb +65 -41
  19. data/lib/mongoid/association/embedded/embeds_many.rb +2 -2
  20. data/lib/mongoid/association/embedded/embeds_one/buildable.rb +18 -4
  21. data/lib/mongoid/association/embedded/embeds_one/proxy.rb +23 -4
  22. data/lib/mongoid/association/embedded/embeds_one.rb +3 -3
  23. data/lib/mongoid/association/macros.rb +28 -1
  24. data/lib/mongoid/association/many.rb +11 -7
  25. data/lib/mongoid/association/nested/many.rb +5 -4
  26. data/lib/mongoid/association/nested/nested_buildable.rb +4 -4
  27. data/lib/mongoid/association/nested/one.rb +5 -5
  28. data/lib/mongoid/association/one.rb +2 -2
  29. data/lib/mongoid/association/options.rb +9 -9
  30. data/lib/mongoid/association/proxy.rb +14 -3
  31. data/lib/mongoid/association/referenced/auto_save.rb +4 -3
  32. data/lib/mongoid/association/referenced/belongs_to/binding.rb +1 -0
  33. data/lib/mongoid/association/referenced/belongs_to/buildable.rb +1 -1
  34. data/lib/mongoid/association/referenced/belongs_to/proxy.rb +5 -6
  35. data/lib/mongoid/association/referenced/belongs_to.rb +2 -2
  36. data/lib/mongoid/association/referenced/counter_cache.rb +10 -10
  37. data/lib/mongoid/association/referenced/eager.rb +2 -2
  38. data/lib/mongoid/association/referenced/has_and_belongs_to_many/proxy.rb +70 -13
  39. data/lib/mongoid/association/referenced/has_and_belongs_to_many.rb +6 -3
  40. data/lib/mongoid/association/referenced/has_many/enumerable.rb +20 -24
  41. data/lib/mongoid/association/referenced/has_many/proxy.rb +26 -16
  42. data/lib/mongoid/association/referenced/has_many.rb +3 -3
  43. data/lib/mongoid/association/referenced/has_one/buildable.rb +1 -1
  44. data/lib/mongoid/association/referenced/has_one/nested_builder.rb +5 -5
  45. data/lib/mongoid/association/referenced/has_one/proxy.rb +9 -12
  46. data/lib/mongoid/association/referenced/has_one.rb +3 -3
  47. data/lib/mongoid/association/referenced/syncable.rb +4 -4
  48. data/lib/mongoid/association/reflections.rb +2 -2
  49. data/lib/mongoid/association/relatable.rb +44 -10
  50. data/lib/mongoid/association.rb +5 -5
  51. data/lib/mongoid/atomic/modifiers.rb +2 -2
  52. data/lib/mongoid/atomic.rb +7 -0
  53. data/lib/mongoid/attributes/dynamic.rb +3 -3
  54. data/lib/mongoid/attributes/nested.rb +5 -5
  55. data/lib/mongoid/attributes/processing.rb +37 -6
  56. data/lib/mongoid/attributes/projector.rb +1 -1
  57. data/lib/mongoid/attributes/readonly.rb +2 -2
  58. data/lib/mongoid/attributes.rb +43 -40
  59. data/lib/mongoid/cacheable.rb +2 -2
  60. data/lib/mongoid/changeable.rb +43 -10
  61. data/lib/mongoid/clients/options.rb +5 -1
  62. data/lib/mongoid/clients/sessions.rb +2 -14
  63. data/lib/mongoid/clients/validators/storage.rb +3 -3
  64. data/lib/mongoid/config/options.rb +3 -0
  65. data/lib/mongoid/config/validators/client.rb +6 -6
  66. data/lib/mongoid/config.rb +62 -17
  67. data/lib/mongoid/contextual/aggregable/memory.rb +24 -16
  68. data/lib/mongoid/contextual/aggregable/mongo.rb +5 -5
  69. data/lib/mongoid/contextual/aggregable/none.rb +1 -1
  70. data/lib/mongoid/contextual/atomic.rb +1 -1
  71. data/lib/mongoid/contextual/geo_near.rb +7 -7
  72. data/lib/mongoid/contextual/map_reduce.rb +2 -2
  73. data/lib/mongoid/contextual/memory.rb +180 -21
  74. data/lib/mongoid/contextual/mongo.rb +260 -217
  75. data/lib/mongoid/contextual/none.rb +67 -5
  76. data/lib/mongoid/contextual/queryable.rb +1 -1
  77. data/lib/mongoid/contextual.rb +2 -2
  78. data/lib/mongoid/copyable.rb +32 -8
  79. data/lib/mongoid/criteria/findable.rb +7 -4
  80. data/lib/mongoid/criteria/includable.rb +24 -20
  81. data/lib/mongoid/criteria/marshalable.rb +10 -2
  82. data/lib/mongoid/criteria/permission.rb +1 -1
  83. data/lib/mongoid/criteria/queryable/aggregable.rb +2 -2
  84. data/lib/mongoid/criteria/queryable/extensions/array.rb +3 -14
  85. data/lib/mongoid/criteria/queryable/extensions/big_decimal.rb +25 -4
  86. data/lib/mongoid/criteria/queryable/extensions/boolean.rb +2 -2
  87. data/lib/mongoid/criteria/queryable/extensions/date.rb +6 -1
  88. data/lib/mongoid/criteria/queryable/extensions/date_time.rb +6 -1
  89. data/lib/mongoid/criteria/queryable/extensions/hash.rb +1 -15
  90. data/lib/mongoid/criteria/queryable/extensions/numeric.rb +1 -9
  91. data/lib/mongoid/criteria/queryable/extensions/object.rb +2 -1
  92. data/lib/mongoid/criteria/queryable/extensions/range.rb +13 -5
  93. data/lib/mongoid/criteria/queryable/extensions/regexp.rb +3 -3
  94. data/lib/mongoid/criteria/queryable/extensions/set.rb +1 -1
  95. data/lib/mongoid/criteria/queryable/extensions/string.rb +4 -14
  96. data/lib/mongoid/criteria/queryable/extensions/symbol.rb +4 -12
  97. data/lib/mongoid/criteria/queryable/extensions/time.rb +6 -1
  98. data/lib/mongoid/criteria/queryable/extensions/time_with_zone.rb +6 -1
  99. data/lib/mongoid/criteria/queryable/key.rb +3 -3
  100. data/lib/mongoid/criteria/queryable/mergeable.rb +21 -0
  101. data/lib/mongoid/criteria/queryable/optional.rb +5 -11
  102. data/lib/mongoid/criteria/queryable/options.rb +2 -2
  103. data/lib/mongoid/criteria/queryable/pipeline.rb +1 -1
  104. data/lib/mongoid/criteria/queryable/selectable.rb +31 -37
  105. data/lib/mongoid/criteria/queryable/selector.rb +93 -8
  106. data/lib/mongoid/criteria/queryable/smash.rb +40 -7
  107. data/lib/mongoid/criteria/queryable/storable.rb +1 -1
  108. data/lib/mongoid/criteria/queryable.rb +12 -7
  109. data/lib/mongoid/criteria/scopable.rb +2 -2
  110. data/lib/mongoid/criteria/translator.rb +45 -0
  111. data/lib/mongoid/criteria.rb +16 -35
  112. data/lib/mongoid/deprecable.rb +37 -0
  113. data/lib/mongoid/deprecation.rb +25 -0
  114. data/lib/mongoid/document.rb +135 -34
  115. data/lib/mongoid/equality.rb +8 -8
  116. data/lib/mongoid/errors/document_not_found.rb +33 -12
  117. data/lib/mongoid/errors/invalid_config_option.rb +1 -1
  118. data/lib/mongoid/errors/invalid_dependent_strategy.rb +1 -1
  119. data/lib/mongoid/errors/invalid_dot_dollar_assignment.rb +23 -0
  120. data/lib/mongoid/errors/invalid_field.rb +6 -2
  121. data/lib/mongoid/errors/invalid_field_type.rb +26 -0
  122. data/lib/mongoid/errors/invalid_relation.rb +1 -1
  123. data/lib/mongoid/errors/invalid_relation_option.rb +1 -1
  124. data/lib/mongoid/errors/invalid_session_use.rb +1 -1
  125. data/lib/mongoid/errors/invalid_storage_options.rb +1 -1
  126. data/lib/mongoid/errors/mongoid_error.rb +3 -3
  127. data/lib/mongoid/errors/nested_attributes_metadata_not_found.rb +1 -1
  128. data/lib/mongoid/errors/no_client_database.rb +1 -1
  129. data/lib/mongoid/errors/no_client_hosts.rb +1 -1
  130. data/lib/mongoid/errors/readonly_attribute.rb +1 -1
  131. data/lib/mongoid/errors/too_many_nested_attribute_records.rb +1 -1
  132. data/lib/mongoid/errors/unknown_attribute.rb +1 -1
  133. data/lib/mongoid/errors.rb +2 -2
  134. data/lib/mongoid/extensions/array.rb +9 -7
  135. data/lib/mongoid/extensions/big_decimal.rb +33 -10
  136. data/lib/mongoid/extensions/binary.rb +42 -0
  137. data/lib/mongoid/extensions/boolean.rb +8 -2
  138. data/lib/mongoid/extensions/date.rb +26 -20
  139. data/lib/mongoid/extensions/date_time.rb +1 -1
  140. data/lib/mongoid/extensions/false_class.rb +1 -1
  141. data/lib/mongoid/extensions/float.rb +7 -4
  142. data/lib/mongoid/extensions/hash.rb +37 -8
  143. data/lib/mongoid/extensions/integer.rb +7 -4
  144. data/lib/mongoid/extensions/module.rb +1 -1
  145. data/lib/mongoid/extensions/object.rb +8 -6
  146. data/lib/mongoid/extensions/range.rb +41 -10
  147. data/lib/mongoid/extensions/regexp.rb +11 -4
  148. data/lib/mongoid/extensions/set.rb +11 -4
  149. data/lib/mongoid/extensions/string.rb +11 -22
  150. data/lib/mongoid/extensions/symbol.rb +4 -15
  151. data/lib/mongoid/extensions/time.rb +27 -16
  152. data/lib/mongoid/extensions/time_with_zone.rb +1 -2
  153. data/lib/mongoid/extensions/true_class.rb +1 -1
  154. data/lib/mongoid/extensions.rb +1 -0
  155. data/lib/mongoid/factory.rb +55 -7
  156. data/lib/mongoid/fields/foreign_key.rb +11 -4
  157. data/lib/mongoid/fields/localized.rb +9 -4
  158. data/lib/mongoid/fields/standard.rb +7 -7
  159. data/lib/mongoid/fields/validators/macro.rb +3 -9
  160. data/lib/mongoid/fields.rb +233 -40
  161. data/lib/mongoid/findable.rb +34 -13
  162. data/lib/mongoid/indexable/specification.rb +2 -2
  163. data/lib/mongoid/indexable/validators/options.rb +6 -2
  164. data/lib/mongoid/interceptable.rb +185 -16
  165. data/lib/mongoid/matchable.rb +1 -1
  166. data/lib/mongoid/matcher.rb +33 -13
  167. data/lib/mongoid/persistable/creatable.rb +18 -9
  168. data/lib/mongoid/persistable/deletable.rb +1 -1
  169. data/lib/mongoid/persistable/destroyable.rb +1 -1
  170. data/lib/mongoid/persistable/savable.rb +2 -2
  171. data/lib/mongoid/persistable/unsettable.rb +1 -1
  172. data/lib/mongoid/persistable/updatable.rb +19 -12
  173. data/lib/mongoid/persistable/upsertable.rb +1 -1
  174. data/lib/mongoid/persistable.rb +3 -3
  175. data/lib/mongoid/persistence_context.rb +63 -10
  176. data/lib/mongoid/query_cache.rb +8 -260
  177. data/lib/mongoid/railties/controller_runtime.rb +1 -1
  178. data/lib/mongoid/reloadable.rb +10 -8
  179. data/lib/mongoid/scopable.rb +26 -22
  180. data/lib/mongoid/selectable.rb +1 -2
  181. data/lib/mongoid/serializable.rb +10 -6
  182. data/lib/mongoid/shardable.rb +35 -11
  183. data/lib/mongoid/stateful.rb +35 -9
  184. data/lib/mongoid/tasks/database.rb +0 -2
  185. data/lib/mongoid/threaded/lifecycle.rb +5 -5
  186. data/lib/mongoid/threaded.rb +42 -12
  187. data/lib/mongoid/timestamps/created.rb +1 -1
  188. data/lib/mongoid/timestamps/updated.rb +2 -2
  189. data/lib/mongoid/touchable.rb +2 -3
  190. data/lib/mongoid/traversable.rb +5 -4
  191. data/lib/mongoid/validatable/localizable.rb +1 -1
  192. data/lib/mongoid/validatable/macros.rb +0 -2
  193. data/lib/mongoid/validatable/presence.rb +2 -2
  194. data/lib/mongoid/validatable/uniqueness.rb +9 -8
  195. data/lib/mongoid/validatable.rb +6 -6
  196. data/lib/mongoid/version.rb +1 -1
  197. data/lib/mongoid/warnings.rb +28 -0
  198. data/lib/mongoid.rb +2 -0
  199. data/lib/rails/generators/mongoid/config/templates/mongoid.yml +4 -3
  200. data/spec/config/mongoid.yml +16 -0
  201. data/spec/integration/app_spec.rb +8 -12
  202. data/spec/integration/associations/belongs_to_spec.rb +18 -0
  203. data/spec/integration/associations/embedded_spec.rb +15 -0
  204. data/spec/integration/associations/embeds_many_spec.rb +15 -2
  205. data/spec/integration/associations/embeds_one_spec.rb +18 -0
  206. data/spec/integration/associations/foreign_key_spec.rb +9 -0
  207. data/spec/integration/associations/has_and_belongs_to_many_spec.rb +21 -0
  208. data/spec/integration/associations/has_one_spec.rb +97 -1
  209. data/spec/integration/associations/scope_option_spec.rb +1 -1
  210. data/spec/integration/callbacks_models.rb +95 -1
  211. data/spec/integration/callbacks_spec.rb +246 -4
  212. data/spec/integration/criteria/range_spec.rb +95 -1
  213. data/spec/integration/discriminator_key_spec.rb +115 -76
  214. data/spec/integration/dots_and_dollars_spec.rb +277 -0
  215. data/spec/integration/i18n_fallbacks_spec.rb +1 -17
  216. data/spec/integration/matcher_examples_spec.rb +20 -13
  217. data/spec/integration/matcher_operator_data/type_decimal.yml +3 -2
  218. data/spec/integration/matcher_operator_spec.rb +3 -5
  219. data/spec/integration/persistence/range_field_spec.rb +350 -0
  220. data/spec/mongoid/association/counter_cache_spec.rb +1 -1
  221. data/spec/mongoid/association/depending_spec.rb +9 -9
  222. data/spec/mongoid/association/eager_spec.rb +2 -1
  223. data/spec/mongoid/association/embedded/embedded_in/binding_spec.rb +2 -1
  224. data/spec/mongoid/association/embedded/embedded_in/buildable_spec.rb +54 -0
  225. data/spec/mongoid/association/embedded/embedded_in/proxy_spec.rb +69 -9
  226. data/spec/mongoid/association/embedded/embeds_many/buildable_spec.rb +112 -0
  227. data/spec/mongoid/association/embedded/embeds_many/proxy_spec.rb +235 -40
  228. data/spec/mongoid/association/embedded/embeds_many_models.rb +36 -0
  229. data/spec/mongoid/association/embedded/embeds_many_query_spec.rb +12 -0
  230. data/spec/mongoid/association/embedded/embeds_many_spec.rb +68 -0
  231. data/spec/mongoid/association/embedded/embeds_one/buildable_spec.rb +25 -0
  232. data/spec/mongoid/association/embedded/embeds_one_models.rb +19 -0
  233. data/spec/mongoid/association/embedded/embeds_one_spec.rb +28 -0
  234. data/spec/mongoid/association/referenced/belongs_to/binding_spec.rb +2 -1
  235. data/spec/mongoid/association/referenced/belongs_to/buildable_spec.rb +54 -0
  236. data/spec/mongoid/association/referenced/belongs_to/proxy_spec.rb +15 -0
  237. data/spec/mongoid/association/referenced/belongs_to_models.rb +11 -0
  238. data/spec/mongoid/association/referenced/belongs_to_spec.rb +2 -2
  239. data/spec/mongoid/association/referenced/has_and_belongs_to_many/proxy_spec.rb +202 -201
  240. data/spec/mongoid/association/referenced/has_and_belongs_to_many_models.rb +25 -0
  241. data/spec/mongoid/association/referenced/has_and_belongs_to_many_spec.rb +35 -2
  242. data/spec/mongoid/association/referenced/has_many/buildable_spec.rb +109 -0
  243. data/spec/mongoid/association/referenced/has_many/enumerable_spec.rb +8 -8
  244. data/spec/mongoid/association/referenced/has_many/proxy_spec.rb +160 -119
  245. data/spec/mongoid/association/referenced/has_many_models.rb +3 -1
  246. data/spec/mongoid/association/referenced/has_many_spec.rb +25 -0
  247. data/spec/mongoid/association/referenced/has_one/buildable_spec.rb +2 -2
  248. data/spec/mongoid/association/referenced/has_one/proxy_spec.rb +107 -1
  249. data/spec/mongoid/association/referenced/has_one_models.rb +16 -0
  250. data/spec/mongoid/association/syncable_spec.rb +14 -0
  251. data/spec/mongoid/atomic/paths_spec.rb +0 -14
  252. data/spec/mongoid/attributes/nested_spec.rb +80 -11
  253. data/spec/mongoid/attributes/nested_spec_models.rb +48 -0
  254. data/spec/mongoid/attributes/projector_spec.rb +1 -5
  255. data/spec/mongoid/attributes_spec.rb +551 -27
  256. data/spec/mongoid/cacheable_spec.rb +3 -3
  257. data/spec/mongoid/changeable_spec.rb +130 -13
  258. data/spec/mongoid/clients/factory_spec.rb +23 -30
  259. data/spec/mongoid/clients/options_spec.rb +1 -0
  260. data/spec/mongoid/clients/sessions_spec.rb +0 -38
  261. data/spec/mongoid/clients_spec.rb +57 -2
  262. data/spec/mongoid/config_spec.rb +78 -18
  263. data/spec/mongoid/contextual/aggregable/memory_spec.rb +396 -158
  264. data/spec/mongoid/contextual/aggregable/memory_table.yml +88 -0
  265. data/spec/mongoid/contextual/aggregable/memory_table_spec.rb +62 -0
  266. data/spec/mongoid/contextual/map_reduce_spec.rb +2 -16
  267. data/spec/mongoid/contextual/memory_spec.rb +1336 -69
  268. data/spec/mongoid/contextual/mongo_spec.rb +1253 -247
  269. data/spec/mongoid/contextual/none_spec.rb +38 -0
  270. data/spec/mongoid/copyable_spec.rb +451 -1
  271. data/spec/mongoid/criteria/findable_spec.rb +86 -210
  272. data/spec/mongoid/criteria/includable_spec.rb +1492 -0
  273. data/spec/mongoid/criteria/includable_spec_models.rb +54 -0
  274. data/spec/mongoid/criteria/marshalable_spec.rb +18 -1
  275. data/spec/mongoid/criteria/queryable/extensions/array_spec.rb +7 -19
  276. data/spec/mongoid/criteria/queryable/extensions/big_decimal_spec.rb +134 -26
  277. data/spec/mongoid/criteria/queryable/extensions/date_spec.rb +11 -0
  278. data/spec/mongoid/criteria/queryable/extensions/date_time_spec.rb +11 -0
  279. data/spec/mongoid/criteria/queryable/extensions/hash_spec.rb +0 -15
  280. data/spec/mongoid/criteria/queryable/extensions/numeric_spec.rb +73 -7
  281. data/spec/mongoid/criteria/queryable/extensions/string_spec.rb +0 -59
  282. data/spec/mongoid/criteria/queryable/extensions/symbol_spec.rb +0 -59
  283. data/spec/mongoid/criteria/queryable/extensions/time_spec.rb +11 -0
  284. data/spec/mongoid/criteria/queryable/extensions/time_with_zone_spec.rb +11 -0
  285. data/spec/mongoid/criteria/queryable/optional_spec.rb +15 -484
  286. data/spec/mongoid/criteria/queryable/selectable_logical_spec.rb +50 -0
  287. data/spec/mongoid/criteria/queryable/selectable_spec.rb +289 -124
  288. data/spec/mongoid/criteria/queryable/selector_spec.rb +89 -4
  289. data/spec/mongoid/criteria/queryable/storable_spec.rb +72 -0
  290. data/spec/mongoid/criteria/translator_spec.rb +132 -0
  291. data/spec/mongoid/criteria_projection_spec.rb +0 -1
  292. data/spec/mongoid/criteria_spec.rb +475 -1199
  293. data/spec/mongoid/document_fields_spec.rb +173 -24
  294. data/spec/mongoid/document_spec.rb +32 -41
  295. data/spec/mongoid/errors/document_not_found_spec.rb +76 -0
  296. data/spec/mongoid/errors/invalid_field_spec.rb +1 -1
  297. data/spec/mongoid/errors/invalid_field_type_spec.rb +55 -0
  298. data/spec/mongoid/errors/mongoid_error_spec.rb +3 -1
  299. data/spec/mongoid/errors/no_environment_spec.rb +3 -3
  300. data/spec/mongoid/errors/too_many_nested_attribute_records_spec.rb +1 -1
  301. data/spec/mongoid/extensions/array_spec.rb +16 -2
  302. data/spec/mongoid/extensions/big_decimal_spec.rb +712 -212
  303. data/spec/mongoid/extensions/binary_spec.rb +44 -9
  304. data/spec/mongoid/extensions/boolean_spec.rb +68 -82
  305. data/spec/mongoid/extensions/date_class_mongoize_spec.rb +7 -3
  306. data/spec/mongoid/extensions/date_spec.rb +71 -1
  307. data/spec/mongoid/extensions/date_time_spec.rb +15 -9
  308. data/spec/mongoid/extensions/float_spec.rb +53 -74
  309. data/spec/mongoid/extensions/hash_spec.rb +33 -3
  310. data/spec/mongoid/extensions/integer_spec.rb +50 -64
  311. data/spec/mongoid/extensions/range_spec.rb +255 -54
  312. data/spec/mongoid/extensions/regexp_spec.rb +58 -33
  313. data/spec/mongoid/extensions/set_spec.rb +106 -0
  314. data/spec/mongoid/extensions/string_spec.rb +53 -25
  315. data/spec/mongoid/extensions/symbol_spec.rb +18 -25
  316. data/spec/mongoid/extensions/time_spec.rb +634 -66
  317. data/spec/mongoid/extensions/time_with_zone_spec.rb +17 -31
  318. data/spec/mongoid/factory_spec.rb +61 -1
  319. data/spec/mongoid/fields/localized_spec.rb +37 -12
  320. data/spec/mongoid/fields_spec.rb +364 -50
  321. data/spec/mongoid/findable_spec.rb +80 -15
  322. data/spec/mongoid/indexable/specification_spec.rb +2 -2
  323. data/spec/mongoid/indexable_spec.rb +39 -20
  324. data/spec/mongoid/interceptable_spec.rb +807 -27
  325. data/spec/mongoid/interceptable_spec_models.rb +235 -4
  326. data/spec/mongoid/matcher/extract_attribute_spec.rb +1 -5
  327. data/spec/mongoid/mongoizable_spec.rb +285 -0
  328. data/spec/mongoid/persistable/creatable_spec.rb +2 -2
  329. data/spec/mongoid/persistable/deletable_spec.rb +2 -2
  330. data/spec/mongoid/persistable/destroyable_spec.rb +2 -2
  331. data/spec/mongoid/persistable/upsertable_spec.rb +14 -0
  332. data/spec/mongoid/persistence_context_spec.rb +50 -1
  333. data/spec/mongoid/query_cache_middleware_spec.rb +0 -18
  334. data/spec/mongoid/query_cache_spec.rb +0 -154
  335. data/spec/mongoid/reloadable_spec.rb +59 -2
  336. data/spec/mongoid/scopable_spec.rb +54 -16
  337. data/spec/mongoid/shardable_models.rb +14 -0
  338. data/spec/mongoid/shardable_spec.rb +157 -51
  339. data/spec/mongoid/stateful_spec.rb +28 -0
  340. data/spec/mongoid/timestamps_spec.rb +390 -0
  341. data/spec/mongoid/timestamps_spec_models.rb +67 -0
  342. data/spec/mongoid/touchable_spec.rb +116 -0
  343. data/spec/mongoid/touchable_spec_models.rb +12 -8
  344. data/spec/mongoid/traversable_spec.rb +4 -11
  345. data/spec/mongoid/validatable/presence_spec.rb +1 -1
  346. data/spec/mongoid/validatable/uniqueness_spec.rb +59 -31
  347. data/spec/mongoid/warnings_spec.rb +35 -0
  348. data/spec/mongoid_spec.rb +1 -1
  349. data/spec/rails/controller_extension/controller_runtime_spec.rb +2 -2
  350. data/spec/rails/mongoid_spec.rb +4 -16
  351. data/spec/shared/lib/mrss/docker_runner.rb +7 -0
  352. data/spec/shared/lib/mrss/lite_constraints.rb +10 -2
  353. data/spec/shared/lib/mrss/server_version_registry.rb +16 -23
  354. data/spec/shared/lib/mrss/utils.rb +28 -6
  355. data/spec/shared/share/Dockerfile.erb +36 -40
  356. data/spec/shared/shlib/server.sh +32 -8
  357. data/spec/shared/shlib/set_env.sh +4 -4
  358. data/spec/support/constraints.rb +24 -0
  359. data/spec/support/macros.rb +46 -0
  360. data/spec/support/models/augmentation.rb +12 -0
  361. data/spec/support/models/band.rb +3 -0
  362. data/spec/support/models/catalog.rb +24 -0
  363. data/spec/support/models/circus.rb +3 -0
  364. data/spec/support/models/code.rb +2 -0
  365. data/spec/support/models/fanatic.rb +8 -0
  366. data/spec/support/models/implant.rb +9 -0
  367. data/spec/support/models/label.rb +2 -0
  368. data/spec/support/models/passport.rb +9 -0
  369. data/spec/support/models/person.rb +2 -0
  370. data/spec/support/models/player.rb +2 -0
  371. data/spec/support/models/powerup.rb +12 -0
  372. data/spec/support/models/purse.rb +9 -0
  373. data/spec/support/models/registry.rb +1 -0
  374. data/spec/support/models/school.rb +14 -0
  375. data/spec/support/models/shield.rb +18 -0
  376. data/spec/support/models/student.rb +14 -0
  377. data/spec/support/models/weapon.rb +12 -0
  378. data.tar.gz.sig +4 -1
  379. metadata +682 -635
  380. metadata.gz.sig +0 -0
  381. data/lib/mongoid/errors/eager_load.rb +0 -23
  382. data/lib/mongoid/errors/invalid_value.rb +0 -17
  383. data/spec/mongoid/errors/eager_load_spec.rb +0 -31
@@ -9,7 +9,7 @@ module Mongoid
9
9
  # Get all the aggregate values for the provided field.
10
10
  # Provided for interface consistency with Aggregable::Mongo.
11
11
  #
12
- # @param [ String, Symbol ] field The field name.
12
+ # @param [ String | Symbol ] field The field name.
13
13
  #
14
14
  # @return [ Hash ] A Hash containing the aggregate values.
15
15
  # If no documents are present, then returned Hash will have
@@ -27,9 +27,13 @@ module Mongoid
27
27
  #
28
28
  # @param [ Symbol ] field The field to average.
29
29
  #
30
- # @return [ Float ] The average.
30
+ # @return [ Numeric ] The average.
31
31
  def avg(field)
32
- count > 0 ? sum(field).to_f / count.to_f : nil
32
+ total = count { |doc| !doc.send(field).nil? }
33
+ return nil unless total > 0
34
+
35
+ total = total.to_f if total.is_a?(Integer)
36
+ sum(field) / total
33
37
  end
34
38
 
35
39
  # Get the max value of the provided field. If provided a block, will
@@ -46,10 +50,12 @@ module Mongoid
46
50
  #
47
51
  # @param [ Symbol ] field The field to max.
48
52
  #
49
- # @return [ Float, Document ] The max value or document with the max
53
+ # @return [ Numeric | Document ] The max value or document with the max
50
54
  # value.
51
55
  def max(field = nil)
52
- block_given? ? super() : aggregate_by(field, :max_by)
56
+ return super() if block_given?
57
+
58
+ aggregate_by(field, :max)
53
59
  end
54
60
 
55
61
  # Get the min value of the provided field. If provided a block, will
@@ -66,10 +72,12 @@ module Mongoid
66
72
  #
67
73
  # @param [ Symbol ] field The field to min.
68
74
  #
69
- # @return [ Float, Document ] The min value or document with the min
75
+ # @return [ Numeric | Document ] The min value or document with the min
70
76
  # value.
71
77
  def min(field = nil)
72
- block_given? ? super() : aggregate_by(field, :min_by)
78
+ return super() if block_given?
79
+
80
+ aggregate_by(field, :min)
73
81
  end
74
82
 
75
83
  # Get the sum value of the provided field. If provided a block, will
@@ -83,13 +91,11 @@ module Mongoid
83
91
  #
84
92
  # @param [ Symbol ] field The field to sum.
85
93
  #
86
- # @return [ Float ] The sum value.
94
+ # @return [ Numeric ] The sum value.
87
95
  def sum(field = nil)
88
- if block_given?
89
- super()
90
- else
91
- count > 0 ? super(0) { |doc| doc.public_send(field) } : 0
92
- end
96
+ return super() if block_given?
97
+
98
+ aggregate_by(field, :sum) || 0
93
99
  end
94
100
 
95
101
  private
@@ -99,14 +105,16 @@ module Mongoid
99
105
  # @api private
100
106
  #
101
107
  # @example Aggregate by the field and method.
102
- # aggregable.aggregate_by(:name, :min_by)
108
+ # aggregable.aggregate_by(:likes, :min_by)
103
109
  #
104
110
  # @param [ Symbol ] field The field to aggregate on.
105
111
  # @param [ Symbol ] method The method (min_by or max_by).
106
112
  #
107
- # @return [ Integer ] The aggregate.
113
+ # @return [ Numeric | nil ] The aggregate.
108
114
  def aggregate_by(field, method)
109
- count > 0 ? send(method) { |doc| doc.public_send(field) }.public_send(field) : nil
115
+ return nil unless any?
116
+
117
+ map { |doc| doc.public_send(field) }.compact.public_send(method)
110
118
  end
111
119
  end
112
120
  end
@@ -20,13 +20,13 @@ module Mongoid
20
20
  # # "avg" => 750.0
21
21
  # # }
22
22
  #
23
- # @param [ String, Symbol ] field The field name.
23
+ # @param [ String | Symbol ] field The field name.
24
24
  #
25
25
  # @return [ Hash ] A Hash containing the aggregate values.
26
26
  # If no documents are found, then returned Hash will have
27
27
  # count, sum of 0 and max, min, avg of nil.
28
28
  def aggregates(field)
29
- result = collection.find.aggregate(pipeline(field), session: _session).to_a
29
+ result = collection.aggregate(pipeline(field), session: _session).to_a
30
30
  if result.empty?
31
31
  if Mongoid.broken_aggregables
32
32
  { "count" => 0, "sum" => nil, "avg" => nil, "min" => nil, "max" => nil }
@@ -64,7 +64,7 @@ module Mongoid
64
64
  #
65
65
  # @param [ Symbol ] field The field to max.
66
66
  #
67
- # @return [ Float, Document ] The max value or document with the max
67
+ # @return [ Float | Document ] The max value or document with the max
68
68
  # value.
69
69
  def max(field = nil)
70
70
  block_given? ? super() : aggregates(field)["max"]
@@ -84,7 +84,7 @@ module Mongoid
84
84
  #
85
85
  # @param [ Symbol ] field The field to min.
86
86
  #
87
- # @return [ Float, Document ] The min value or document with the min
87
+ # @return [ Float | Document ] The min value or document with the min
88
88
  # value.
89
89
  def min(field = nil)
90
90
  block_given? ? super() : aggregates(field)["min"]
@@ -115,7 +115,7 @@ module Mongoid
115
115
  # @example Get the pipeline.
116
116
  # aggregable.pipeline(:likes)
117
117
  #
118
- # @param [ String, Symbol ] field The name of the field.
118
+ # @param [ String | Symbol ] field The name of the field.
119
119
  #
120
120
  # @return [ Array ] The array of pipeline operators.
121
121
  def pipeline(field)
@@ -11,7 +11,7 @@ module Mongoid
11
11
  # Get all the aggregate values for the provided field in null context.
12
12
  # Provided for interface consistency with Aggregable::Mongo.
13
13
  #
14
- # @param [ String, Symbol ] _field The field name.
14
+ # @param [ String | Symbol ] _field The field name.
15
15
  #
16
16
  # @return [ Hash ] A Hash with count, sum of 0 and max, min, avg of nil.
17
17
  def aggregates(_field)
@@ -150,7 +150,7 @@ module Mongoid
150
150
  # @example Unset the field on the matches.
151
151
  # context.unset(:name)
152
152
  #
153
- # @param [ String | Symbol | Array<String|Symbol> | Hash ] args
153
+ # @param [ String | Symbol | Array<String | Symbol> | Hash ] args
154
154
  # The name(s) of the field(s) to unset.
155
155
  # If a Hash is specified, its keys will be used irrespective of what
156
156
  # each key's value is, even if the value is nil or false.
@@ -16,7 +16,7 @@ module Mongoid
16
16
  # @example Get the average distance.
17
17
  # geo_near.average_distance
18
18
  #
19
- # @return [ Float, nil ] The average distance.
19
+ # @return [ Float | nil ] The average distance.
20
20
  def average_distance
21
21
  average = stats["avgDistance"]
22
22
  (average.nil? || average.nan?) ? nil : average
@@ -46,7 +46,7 @@ module Mongoid
46
46
  # @example Provide the distance multiplier.
47
47
  # geo_near.distance_multiplier(13113.1)
48
48
  #
49
- # @param [ Integer, Float ] value The distance multiplier.
49
+ # @param [ Integer | Float ] value The distance multiplier.
50
50
  #
51
51
  # @return [ GeoNear ] The GeoNear wrapper.
52
52
  def distance_multiplier(value)
@@ -98,9 +98,9 @@ module Mongoid
98
98
  # @example Get the max distance.
99
99
  # geo_near.max_distance
100
100
  #
101
- # @param [ Integer, Float ] value The maximum distance.
101
+ # @param [ Integer | Float ] value The maximum distance.
102
102
  #
103
- # @return [ GeoNear, Float ] The GeoNear command or the value.
103
+ # @return [ GeoNear | Float ] The GeoNear command or the value.
104
104
  def max_distance(value = nil)
105
105
  if value
106
106
  command[:maxDistance] = value
@@ -115,7 +115,7 @@ module Mongoid
115
115
  # @example Set the min distance.
116
116
  # geo_near.min_distance(0.5)
117
117
  #
118
- # @param [ Integer, Float ] value The minimum distance.
118
+ # @param [ Integer | Float ] value The minimum distance.
119
119
  #
120
120
  # @return [ GeoNear ] The GeoNear command.
121
121
  def min_distance(value)
@@ -139,7 +139,7 @@ module Mongoid
139
139
  # @example Set the unique flag.
140
140
  # geo_near.unique(false)
141
141
  #
142
- # @param [ true, false ] value Whether to return unique documents.
142
+ # @param [ true | false ] value Whether to return unique documents.
143
143
  #
144
144
  # @return [ GeoNear ] The command.
145
145
  def unique(value = true)
@@ -211,7 +211,7 @@ module Mongoid
211
211
  # @example Get the documents.
212
212
  # geo_near.documents
213
213
  #
214
- # @return [ Array, Cursor ] The documents.
214
+ # @return [ Array | Cursor ] The documents.
215
215
  def documents
216
216
  results["results"].map do |attributes|
217
217
  doc = Factory.from_db(criteria.klass, attributes["obj"], criteria)
@@ -121,7 +121,7 @@ module Mongoid
121
121
  # @return [ MapReduce ] The map/reduce object.
122
122
  def out(location)
123
123
  normalized = location.dup
124
- normalized.update_values do |value|
124
+ normalized.transform_values! do |value|
125
125
  value.is_a?(::Symbol) ? value.to_s : value
126
126
  end
127
127
  @map_reduce = @map_reduce.out(normalized)
@@ -147,7 +147,7 @@ module Mongoid
147
147
  def raw
148
148
  validate_out!
149
149
  cmd = command
150
- opts = { read: cmd.delete(:read) } if cmd[:read]
150
+ opts = { read: criteria.options.fetch(:read) } if criteria.options[:read]
151
151
  @map_reduce.database.command(cmd, (opts || {}).merge(session: _session)).first
152
152
  end
153
153
  alias :results :raw
@@ -25,7 +25,7 @@ module Mongoid
25
25
  #
26
26
  # @param [ Array ] other The other array.
27
27
  #
28
- # @return [ true, false ] If the objects are equal.
28
+ # @return [ true | false ] If the objects are equal.
29
29
  def ==(other)
30
30
  return false unless other.respond_to?(:entries)
31
31
  entries == other.entries
@@ -74,11 +74,15 @@ module Mongoid
74
74
  # @example Get the distinct values.
75
75
  # context.distinct(:name)
76
76
  #
77
- # @param [ String, Symbol ] field The name of the field.
77
+ # @param [ String | Symbol ] field The name of the field.
78
78
  #
79
79
  # @return [ Array<Object> ] The distinct values for the field.
80
80
  def distinct(field)
81
- documents.map{ |doc| doc.send(field) }.uniq
81
+ if Mongoid.legacy_pluck_distinct
82
+ documents.map{ |doc| doc.send(field) }.uniq
83
+ else
84
+ pluck(field).uniq
85
+ end
82
86
  end
83
87
 
84
88
  # Iterate over the context. If provided a block, yield to a Mongoid
@@ -106,9 +110,9 @@ module Mongoid
106
110
  # @example Do any documents exist for the context.
107
111
  # context.exists?
108
112
  #
109
- # @return [ true, false ] If the count is more than zero.
113
+ # @return [ true | false ] If the count is more than zero.
110
114
  def exists?
111
- count > 0
115
+ any?
112
116
  end
113
117
 
114
118
  # Get the first document in the database for the criteria's selector.
@@ -116,9 +120,15 @@ module Mongoid
116
120
  # @example Get the first document.
117
121
  # context.first
118
122
  #
123
+ # @param [ Integer ] limit The number of documents to return.
124
+ #
119
125
  # @return [ Document ] The first document.
120
- def first(*args)
121
- eager_load([documents.first]).first
126
+ def first(limit = nil)
127
+ if limit
128
+ eager_load(documents.first(limit))
129
+ else
130
+ eager_load([documents.first]).first
131
+ end
122
132
  end
123
133
  alias :one :first
124
134
  alias :find_first :first
@@ -159,9 +169,48 @@ module Mongoid
159
169
  # @example Get the last document.
160
170
  # context.last
161
171
  #
172
+ # @param [ Integer ] limit The number of documents to return.
173
+ #
162
174
  # @return [ Document ] The last document.
163
- def last
164
- eager_load([documents.last]).first
175
+ def last(limit = nil)
176
+ if limit
177
+ eager_load(documents.last(limit))
178
+ else
179
+ eager_load([documents.last]).first
180
+ end
181
+ end
182
+
183
+ # Take the given number of documents from the database.
184
+ #
185
+ # @example Take a document.
186
+ # context.take
187
+ #
188
+ # @param [ Integer | nil ] limit The number of documents to take or nil.
189
+ #
190
+ # @return [ Document ] The document.
191
+ def take(limit = nil)
192
+ if limit
193
+ eager_load(documents.take(limit))
194
+ else
195
+ eager_load([documents.first]).first
196
+ end
197
+ end
198
+
199
+ # Take the given number of documents from the database.
200
+ #
201
+ # @example Take a document.
202
+ # context.take
203
+ #
204
+ # @return [ Document ] The document.
205
+ #
206
+ # @raises [ Mongoid::Errors::DocumentNotFound ] raises when there are no
207
+ # documents to take.
208
+ def take!
209
+ if documents.empty?
210
+ raise Errors::DocumentNotFound.new(klass, nil, nil)
211
+ else
212
+ eager_load([documents.first]).first
213
+ end
165
214
  end
166
215
 
167
216
  # Get the length of matching documents in the context.
@@ -182,21 +231,58 @@ module Mongoid
182
231
  #
183
232
  # @param [ Integer ] value The number of documents to return.
184
233
  #
185
- # @return [ Mongo ] The context.
234
+ # @return [ Memory ] The context.
186
235
  def limit(value)
187
236
  self.limiting = value
188
237
  self
189
238
  end
190
239
 
240
+ # Pluck the field values in memory.
241
+ #
242
+ # @example Get the values in memory.
243
+ # context.pluck(:name)
244
+ #
245
+ # @param [ String | Symbol ] *fields Field(s) to pluck.
246
+ #
247
+ # @return [ Array<Object> | Array<Array<Object>> ] The plucked values.
191
248
  def pluck(*fields)
192
- fields = Array.wrap(fields)
193
- documents.map do |doc|
194
- if fields.size == 1
195
- doc[fields.first]
196
- else
197
- fields.map { |n| doc[n] }.compact
249
+ if Mongoid.legacy_pluck_distinct
250
+ documents.pluck(*fields)
251
+ else
252
+ documents.map do |doc|
253
+ pluck_from_doc(doc, *fields)
198
254
  end
199
- end.compact
255
+ end
256
+ end
257
+
258
+ # Pick the field values in memory.
259
+ #
260
+ # @example Get the values in memory.
261
+ # context.pick(:name)
262
+ #
263
+ # @param [ String | Symbol ] *fields Field(s) to pick.
264
+ #
265
+ # @return [ Object, Array<Object> ] The picked values.
266
+ def pick(*fields)
267
+ if doc = documents.first
268
+ pluck_from_doc(doc, *fields)
269
+ end
270
+ end
271
+
272
+ # Tally the field values in memory.
273
+ #
274
+ # @example Get the counts of values in memory.
275
+ # context.tally(:name)
276
+ #
277
+ # @param [ String | Symbol ] field Field to tally.
278
+ #
279
+ # @return [ Hash ] The hash of counts.
280
+ def tally(field)
281
+ return documents.each_with_object({}) do |d, acc|
282
+ v = retrieve_value_at_path(d, field)
283
+ acc[v] ||= 0
284
+ acc[v] += 1
285
+ end
200
286
  end
201
287
 
202
288
  # Skips the provided number of documents.
@@ -206,7 +292,7 @@ module Mongoid
206
292
  #
207
293
  # @param [ Integer ] value The number of documents to skip.
208
294
  #
209
- # @return [ Mongo ] The context.
295
+ # @return [ Memory ] The context.
210
296
  def skip(value)
211
297
  self.skipping = value
212
298
  self
@@ -220,7 +306,7 @@ module Mongoid
220
306
  # @param [ Hash ] values The sorting values as field/direction(1/-1)
221
307
  # pairs.
222
308
  #
223
- # @return [ Mongo ] The context.
309
+ # @return [ Memory ] The context.
224
310
  def sort(values)
225
311
  in_place_sort(values) and self
226
312
  end
@@ -232,7 +318,7 @@ module Mongoid
232
318
  #
233
319
  # @param [ Hash ] attributes The new attributes for the document.
234
320
  #
235
- # @return [ nil, false ] False if no attributes were provided.
321
+ # @return [ nil | false ] False if no attributes were provided.
236
322
  def update(attributes = nil)
237
323
  update_documents(attributes, [ first ])
238
324
  end
@@ -244,7 +330,7 @@ module Mongoid
244
330
  #
245
331
  # @param [ Hash ] attributes The new attributes for each document.
246
332
  #
247
- # @return [ nil, false ] False if no attributes were provided.
333
+ # @return [ nil | false ] False if no attributes were provided.
248
334
  def update_all(attributes = nil)
249
335
  update_documents(attributes, entries)
250
336
  end
@@ -414,6 +500,79 @@ module Mongoid
414
500
  def _session
415
501
  @criteria.send(:_session)
416
502
  end
503
+
504
+ # Retrieve the value for the current document at the given field path.
505
+ #
506
+ # For example, if I have the following models:
507
+ #
508
+ # User has_many Accounts
509
+ # address is a hash on Account
510
+ #
511
+ # u = User.new(accounts: [ Account.new(address: { street: "W 50th" }) ])
512
+ # retrieve_value_at_path(u, "user.accounts.address.street")
513
+ # # => [ "W 50th" ]
514
+ #
515
+ # Note that the result is in an array since accounts is an array. If it
516
+ # was nested in two arrays the result would be in a 2D array.
517
+ #
518
+ # @param [ Object ] document The object to traverse the field path.
519
+ # @param [ String ] field_path The dotted string that represents the path
520
+ # to the value.
521
+ #
522
+ # @return [ Object | nil ] The value at the given field path or nil if it
523
+ # doesn't exist.
524
+ def retrieve_value_at_path(document, field_path)
525
+ return if field_path.blank? || !document
526
+ segment, remaining = field_path.to_s.split('.', 2)
527
+
528
+ curr = if document.is_a?(Document)
529
+ # Retrieves field for segment to check localization. Only does one
530
+ # iteration since there's no dots
531
+ res = if remaining
532
+ field = document.class.traverse_association_tree(segment)
533
+ # If this is a localized field, and there are remaining, get the
534
+ # _translations hash so that we can get the specified translation in
535
+ # the remaining
536
+ if field&.localized?
537
+ document.send("#{segment}_translations")
538
+ end
539
+ end
540
+ meth = klass.aliased_associations[segment] || segment
541
+ res.nil? ? document.try(meth) : res
542
+ elsif document.is_a?(Hash)
543
+ # TODO: Remove the indifferent access when implementing MONGOID-5410.
544
+ document.key?(segment.to_s) ?
545
+ document[segment.to_s] :
546
+ document[segment.to_sym]
547
+ else
548
+ nil
549
+ end
550
+
551
+ return curr unless remaining
552
+
553
+ if curr.is_a?(Array)
554
+ # compact is used for consistency with server behavior.
555
+ curr.map { |d| retrieve_value_at_path(d, remaining) }.compact
556
+ else
557
+ retrieve_value_at_path(curr, remaining)
558
+ end
559
+ end
560
+
561
+ # Pluck the field values from the given document.
562
+ #
563
+ # @param [ Document ] doc The document to pluck from.
564
+ # @param [ String | Symbol ] *fields Field(s) to pluck.
565
+ #
566
+ # @return [ Object, Array<Object> ] The plucked values.
567
+ def pluck_from_doc(doc, *fields)
568
+ if fields.length == 1
569
+ retrieve_value_at_path(doc, fields.first)
570
+ else
571
+ fields.map do |field|
572
+ retrieve_value_at_path(doc, field)
573
+ end
574
+ end
575
+ end
417
576
  end
418
577
  end
419
578
  end