mongoid 7.5.4 → 8.1.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (442) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +3 -3
  3. data/README.md +6 -6
  4. data/Rakefile +44 -46
  5. data/lib/config/locales/en.yml +92 -43
  6. data/lib/mongoid/association/accessors.rb +44 -11
  7. data/lib/mongoid/association/bindable.rb +50 -2
  8. data/lib/mongoid/association/builders.rb +5 -3
  9. data/lib/mongoid/association/constrainable.rb +0 -1
  10. data/lib/mongoid/association/eager_loadable.rb +29 -7
  11. data/lib/mongoid/association/embedded/batchable.rb +34 -11
  12. data/lib/mongoid/association/embedded/cyclic.rb +1 -1
  13. data/lib/mongoid/association/embedded/embedded_in/binding.rb +24 -2
  14. data/lib/mongoid/association/embedded/embedded_in/buildable.rb +2 -2
  15. data/lib/mongoid/association/embedded/embedded_in/proxy.rb +4 -3
  16. data/lib/mongoid/association/embedded/embedded_in.rb +3 -2
  17. data/lib/mongoid/association/embedded/embeds_many/binding.rb +1 -0
  18. data/lib/mongoid/association/embedded/embeds_many/buildable.rb +4 -3
  19. data/lib/mongoid/association/embedded/embeds_many/proxy.rb +85 -46
  20. data/lib/mongoid/association/embedded/embeds_many.rb +2 -2
  21. data/lib/mongoid/association/embedded/embeds_one/buildable.rb +19 -5
  22. data/lib/mongoid/association/embedded/embeds_one/proxy.rb +24 -5
  23. data/lib/mongoid/association/embedded/embeds_one.rb +3 -3
  24. data/lib/mongoid/association/macros.rb +8 -1
  25. data/lib/mongoid/association/many.rb +11 -7
  26. data/lib/mongoid/association/nested/many.rb +5 -4
  27. data/lib/mongoid/association/nested/nested_buildable.rb +4 -4
  28. data/lib/mongoid/association/nested/one.rb +45 -7
  29. data/lib/mongoid/association/one.rb +2 -2
  30. data/lib/mongoid/association/options.rb +9 -9
  31. data/lib/mongoid/association/proxy.rb +15 -4
  32. data/lib/mongoid/association/referenced/auto_save.rb +4 -3
  33. data/lib/mongoid/association/referenced/belongs_to/binding.rb +1 -0
  34. data/lib/mongoid/association/referenced/belongs_to/buildable.rb +1 -1
  35. data/lib/mongoid/association/referenced/belongs_to/proxy.rb +5 -6
  36. data/lib/mongoid/association/referenced/belongs_to.rb +2 -2
  37. data/lib/mongoid/association/referenced/counter_cache.rb +10 -10
  38. data/lib/mongoid/association/referenced/eager.rb +2 -2
  39. data/lib/mongoid/association/referenced/has_and_belongs_to_many/proxy.rb +70 -13
  40. data/lib/mongoid/association/referenced/has_and_belongs_to_many.rb +6 -3
  41. data/lib/mongoid/association/referenced/has_many/enumerable.rb +22 -30
  42. data/lib/mongoid/association/referenced/has_many/proxy.rb +40 -21
  43. data/lib/mongoid/association/referenced/has_many.rb +3 -3
  44. data/lib/mongoid/association/referenced/has_one/buildable.rb +1 -1
  45. data/lib/mongoid/association/referenced/has_one/nested_builder.rb +5 -5
  46. data/lib/mongoid/association/referenced/has_one/proxy.rb +9 -12
  47. data/lib/mongoid/association/referenced/has_one.rb +3 -3
  48. data/lib/mongoid/association/referenced/syncable.rb +4 -4
  49. data/lib/mongoid/association/reflections.rb +4 -4
  50. data/lib/mongoid/association/relatable.rb +44 -10
  51. data/lib/mongoid/association.rb +5 -5
  52. data/lib/mongoid/atomic/modifiers.rb +2 -2
  53. data/lib/mongoid/atomic.rb +16 -7
  54. data/lib/mongoid/attributes/dynamic.rb +4 -4
  55. data/lib/mongoid/attributes/nested.rb +6 -6
  56. data/lib/mongoid/attributes/processing.rb +37 -6
  57. data/lib/mongoid/attributes/projector.rb +2 -2
  58. data/lib/mongoid/attributes/readonly.rb +3 -3
  59. data/lib/mongoid/attributes.rb +51 -42
  60. data/lib/mongoid/changeable.rb +147 -14
  61. data/lib/mongoid/clients/options.rb +5 -1
  62. data/lib/mongoid/clients/sessions.rb +2 -14
  63. data/lib/mongoid/clients/storage_options.rb +2 -5
  64. data/lib/mongoid/clients/validators/storage.rb +3 -15
  65. data/lib/mongoid/collection_configurable.rb +58 -0
  66. data/lib/mongoid/composable.rb +2 -0
  67. data/lib/mongoid/config/defaults.rb +60 -0
  68. data/lib/mongoid/config/options.rb +3 -0
  69. data/lib/mongoid/config/validators/async_query_executor.rb +24 -0
  70. data/lib/mongoid/config/validators/client.rb +6 -6
  71. data/lib/mongoid/config/validators.rb +1 -0
  72. data/lib/mongoid/config.rb +153 -18
  73. data/lib/mongoid/contextual/aggregable/memory.rb +24 -16
  74. data/lib/mongoid/contextual/aggregable/mongo.rb +5 -5
  75. data/lib/mongoid/contextual/aggregable/none.rb +1 -1
  76. data/lib/mongoid/contextual/atomic.rb +1 -1
  77. data/lib/mongoid/contextual/geo_near.rb +7 -7
  78. data/lib/mongoid/contextual/map_reduce.rb +2 -2
  79. data/lib/mongoid/contextual/memory.rb +285 -58
  80. data/lib/mongoid/contextual/mongo/documents_loader.rb +177 -0
  81. data/lib/mongoid/contextual/mongo.rb +540 -346
  82. data/lib/mongoid/contextual/none.rb +193 -20
  83. data/lib/mongoid/contextual/queryable.rb +1 -1
  84. data/lib/mongoid/contextual.rb +14 -2
  85. data/lib/mongoid/copyable.rb +32 -8
  86. data/lib/mongoid/criteria/findable.rb +8 -5
  87. data/lib/mongoid/criteria/includable.rb +27 -22
  88. data/lib/mongoid/criteria/marshalable.rb +10 -2
  89. data/lib/mongoid/criteria/permission.rb +1 -1
  90. data/lib/mongoid/criteria/queryable/aggregable.rb +2 -2
  91. data/lib/mongoid/criteria/queryable/extensions/array.rb +3 -16
  92. data/lib/mongoid/criteria/queryable/extensions/big_decimal.rb +25 -4
  93. data/lib/mongoid/criteria/queryable/extensions/boolean.rb +2 -2
  94. data/lib/mongoid/criteria/queryable/extensions/date.rb +6 -1
  95. data/lib/mongoid/criteria/queryable/extensions/date_time.rb +6 -1
  96. data/lib/mongoid/criteria/queryable/extensions/hash.rb +1 -17
  97. data/lib/mongoid/criteria/queryable/extensions/numeric.rb +15 -9
  98. data/lib/mongoid/criteria/queryable/extensions/object.rb +2 -1
  99. data/lib/mongoid/criteria/queryable/extensions/range.rb +13 -5
  100. data/lib/mongoid/criteria/queryable/extensions/regexp.rb +3 -3
  101. data/lib/mongoid/criteria/queryable/extensions/set.rb +1 -1
  102. data/lib/mongoid/criteria/queryable/extensions/string.rb +4 -14
  103. data/lib/mongoid/criteria/queryable/extensions/symbol.rb +4 -12
  104. data/lib/mongoid/criteria/queryable/extensions/time.rb +6 -1
  105. data/lib/mongoid/criteria/queryable/extensions/time_with_zone.rb +6 -1
  106. data/lib/mongoid/criteria/queryable/key.rb +4 -4
  107. data/lib/mongoid/criteria/queryable/mergeable.rb +1 -1
  108. data/lib/mongoid/criteria/queryable/optional.rb +11 -17
  109. data/lib/mongoid/criteria/queryable/options.rb +2 -2
  110. data/lib/mongoid/criteria/queryable/pipeline.rb +1 -1
  111. data/lib/mongoid/criteria/queryable/selectable.rb +47 -38
  112. data/lib/mongoid/criteria/queryable/selector.rb +92 -7
  113. data/lib/mongoid/criteria/queryable/smash.rb +40 -7
  114. data/lib/mongoid/criteria/queryable.rb +12 -7
  115. data/lib/mongoid/criteria/scopable.rb +2 -2
  116. data/lib/mongoid/criteria/translator.rb +45 -0
  117. data/lib/mongoid/criteria.rb +20 -40
  118. data/lib/mongoid/deprecable.rb +37 -0
  119. data/lib/mongoid/deprecation.rb +25 -0
  120. data/lib/mongoid/document.rb +127 -35
  121. data/lib/mongoid/equality.rb +8 -8
  122. data/lib/mongoid/errors/create_collection_failure.rb +33 -0
  123. data/lib/mongoid/errors/document_not_found.rb +10 -6
  124. data/lib/mongoid/errors/drop_collection_failure.rb +27 -0
  125. data/lib/mongoid/errors/immutable_attribute.rb +26 -0
  126. data/lib/mongoid/errors/invalid_async_query_executor.rb +25 -0
  127. data/lib/mongoid/errors/invalid_config_option.rb +1 -1
  128. data/lib/mongoid/errors/invalid_dependent_strategy.rb +1 -1
  129. data/lib/mongoid/errors/invalid_dot_dollar_assignment.rb +23 -0
  130. data/lib/mongoid/errors/invalid_field.rb +6 -2
  131. data/lib/mongoid/errors/invalid_field_type.rb +26 -0
  132. data/lib/mongoid/errors/invalid_global_executor_concurrency.rb +22 -0
  133. data/lib/mongoid/errors/invalid_relation.rb +1 -1
  134. data/lib/mongoid/errors/invalid_relation_option.rb +1 -1
  135. data/lib/mongoid/errors/invalid_session_use.rb +1 -1
  136. data/lib/mongoid/errors/invalid_storage_options.rb +1 -1
  137. data/lib/mongoid/errors/invalid_storage_parent.rb +2 -0
  138. data/lib/mongoid/errors/mongoid_error.rb +3 -3
  139. data/lib/mongoid/errors/nested_attributes_metadata_not_found.rb +1 -1
  140. data/lib/mongoid/errors/no_client_database.rb +1 -1
  141. data/lib/mongoid/errors/no_client_hosts.rb +1 -1
  142. data/lib/mongoid/errors/readonly_attribute.rb +1 -1
  143. data/lib/mongoid/errors/too_many_nested_attribute_records.rb +1 -1
  144. data/lib/mongoid/errors/unknown_attribute.rb +1 -1
  145. data/lib/mongoid/errors.rb +6 -3
  146. data/lib/mongoid/extensions/array.rb +9 -7
  147. data/lib/mongoid/extensions/big_decimal.rb +33 -10
  148. data/lib/mongoid/extensions/binary.rb +42 -0
  149. data/lib/mongoid/extensions/boolean.rb +8 -2
  150. data/lib/mongoid/extensions/date.rb +26 -20
  151. data/lib/mongoid/extensions/date_time.rb +1 -1
  152. data/lib/mongoid/extensions/false_class.rb +1 -1
  153. data/lib/mongoid/extensions/float.rb +7 -4
  154. data/lib/mongoid/extensions/hash.rb +38 -9
  155. data/lib/mongoid/extensions/integer.rb +7 -4
  156. data/lib/mongoid/extensions/module.rb +1 -1
  157. data/lib/mongoid/extensions/object.rb +10 -8
  158. data/lib/mongoid/extensions/range.rb +41 -10
  159. data/lib/mongoid/extensions/regexp.rb +11 -4
  160. data/lib/mongoid/extensions/set.rb +11 -4
  161. data/lib/mongoid/extensions/string.rb +11 -22
  162. data/lib/mongoid/extensions/symbol.rb +4 -15
  163. data/lib/mongoid/extensions/time.rb +29 -16
  164. data/lib/mongoid/extensions/time_with_zone.rb +1 -2
  165. data/lib/mongoid/extensions/true_class.rb +1 -1
  166. data/lib/mongoid/extensions.rb +1 -0
  167. data/lib/mongoid/factory.rb +55 -7
  168. data/lib/mongoid/fields/foreign_key.rb +11 -4
  169. data/lib/mongoid/fields/localized.rb +19 -4
  170. data/lib/mongoid/fields/standard.rb +17 -7
  171. data/lib/mongoid/fields/validators/macro.rb +3 -9
  172. data/lib/mongoid/fields.rb +142 -28
  173. data/lib/mongoid/findable.rb +54 -24
  174. data/lib/mongoid/indexable/specification.rb +2 -2
  175. data/lib/mongoid/indexable/validators/options.rb +6 -2
  176. data/lib/mongoid/interceptable.rb +186 -16
  177. data/lib/mongoid/matchable.rb +1 -1
  178. data/lib/mongoid/matcher/eq_impl.rb +1 -1
  179. data/lib/mongoid/matcher/type.rb +1 -1
  180. data/lib/mongoid/matcher.rb +33 -13
  181. data/lib/mongoid/persistable/creatable.rb +19 -9
  182. data/lib/mongoid/persistable/deletable.rb +2 -2
  183. data/lib/mongoid/persistable/destroyable.rb +1 -1
  184. data/lib/mongoid/persistable/savable.rb +14 -2
  185. data/lib/mongoid/persistable/unsettable.rb +2 -2
  186. data/lib/mongoid/persistable/updatable.rb +69 -12
  187. data/lib/mongoid/persistable/upsertable.rb +21 -2
  188. data/lib/mongoid/persistable.rb +6 -3
  189. data/lib/mongoid/persistence_context.rb +6 -4
  190. data/lib/mongoid/query_cache.rb +13 -261
  191. data/lib/mongoid/railties/controller_runtime.rb +1 -1
  192. data/lib/mongoid/railties/database.rake +7 -2
  193. data/lib/mongoid/reloadable.rb +10 -8
  194. data/lib/mongoid/scopable.rb +15 -13
  195. data/lib/mongoid/selectable.rb +1 -2
  196. data/lib/mongoid/serializable.rb +10 -6
  197. data/lib/mongoid/stateful.rb +57 -10
  198. data/lib/mongoid/tasks/database.rake +12 -0
  199. data/lib/mongoid/tasks/database.rb +20 -2
  200. data/lib/mongoid/threaded/lifecycle.rb +5 -5
  201. data/lib/mongoid/threaded.rb +42 -12
  202. data/lib/mongoid/timestamps/created.rb +1 -1
  203. data/lib/mongoid/timestamps/updated.rb +2 -2
  204. data/lib/mongoid/touchable.rb +3 -4
  205. data/lib/mongoid/traversable.rb +5 -4
  206. data/lib/mongoid/utils.rb +22 -0
  207. data/lib/mongoid/validatable/associated.rb +96 -18
  208. data/lib/mongoid/validatable/localizable.rb +1 -1
  209. data/lib/mongoid/validatable/macros.rb +5 -7
  210. data/lib/mongoid/validatable/presence.rb +2 -2
  211. data/lib/mongoid/validatable/uniqueness.rb +9 -8
  212. data/lib/mongoid/validatable.rb +17 -6
  213. data/lib/mongoid/version.rb +1 -1
  214. data/lib/mongoid/warnings.rb +19 -4
  215. data/lib/mongoid.rb +17 -3
  216. data/spec/config/mongoid.yml +16 -0
  217. data/spec/integration/app_spec.rb +13 -16
  218. data/spec/integration/associations/belongs_to_spec.rb +18 -0
  219. data/spec/integration/associations/embedded_spec.rb +15 -0
  220. data/spec/integration/associations/embeds_many_spec.rb +15 -2
  221. data/spec/integration/associations/embeds_one_spec.rb +18 -0
  222. data/spec/integration/associations/foreign_key_spec.rb +9 -0
  223. data/spec/integration/associations/has_and_belongs_to_many_spec.rb +61 -0
  224. data/spec/integration/associations/has_one_spec.rb +97 -1
  225. data/spec/integration/associations/scope_option_spec.rb +1 -1
  226. data/spec/integration/callbacks_models.rb +132 -1
  227. data/spec/integration/callbacks_spec.rb +381 -4
  228. data/spec/integration/criteria/range_spec.rb +95 -1
  229. data/spec/integration/discriminator_key_spec.rb +118 -80
  230. data/spec/integration/dots_and_dollars_spec.rb +277 -0
  231. data/spec/integration/i18n_fallbacks_spec.rb +3 -32
  232. data/spec/integration/matcher_examples_spec.rb +20 -13
  233. data/spec/integration/matcher_operator_data/type_decimal.yml +3 -2
  234. data/spec/integration/matcher_operator_spec.rb +3 -5
  235. data/spec/integration/persistence/range_field_spec.rb +350 -0
  236. data/spec/mongoid/association/counter_cache_spec.rb +1 -1
  237. data/spec/mongoid/association/depending_spec.rb +9 -9
  238. data/spec/mongoid/association/eager_spec.rb +2 -1
  239. data/spec/mongoid/association/embedded/embedded_in/binding_spec.rb +2 -1
  240. data/spec/mongoid/association/embedded/embedded_in/buildable_spec.rb +54 -0
  241. data/spec/mongoid/association/embedded/embedded_in/proxy_spec.rb +96 -9
  242. data/spec/mongoid/association/embedded/embeds_many/buildable_spec.rb +112 -0
  243. data/spec/mongoid/association/embedded/embeds_many/proxy_spec.rb +290 -65
  244. data/spec/mongoid/association/embedded/embeds_many_models.rb +37 -0
  245. data/spec/mongoid/association/embedded/embeds_many_query_spec.rb +16 -0
  246. data/spec/mongoid/association/embedded/embeds_many_spec.rb +68 -0
  247. data/spec/mongoid/association/embedded/embeds_one/buildable_spec.rb +25 -0
  248. data/spec/mongoid/association/embedded/embeds_one/proxy_spec.rb +15 -2
  249. data/spec/mongoid/association/embedded/embeds_one_models.rb +19 -0
  250. data/spec/mongoid/association/embedded/embeds_one_spec.rb +28 -0
  251. data/spec/mongoid/association/referenced/belongs_to/binding_spec.rb +2 -1
  252. data/spec/mongoid/association/referenced/belongs_to/buildable_spec.rb +54 -0
  253. data/spec/mongoid/association/referenced/belongs_to/proxy_spec.rb +15 -0
  254. data/spec/mongoid/association/referenced/belongs_to_models.rb +11 -0
  255. data/spec/mongoid/association/referenced/belongs_to_spec.rb +4 -20
  256. data/spec/mongoid/association/referenced/has_and_belongs_to_many/proxy_spec.rb +186 -229
  257. data/spec/mongoid/association/referenced/has_and_belongs_to_many_models.rb +25 -0
  258. data/spec/mongoid/association/referenced/has_and_belongs_to_many_spec.rb +35 -2
  259. data/spec/mongoid/association/referenced/has_many/buildable_spec.rb +109 -0
  260. data/spec/mongoid/association/referenced/has_many/enumerable_spec.rb +2 -56
  261. data/spec/mongoid/association/referenced/has_many/proxy_spec.rb +215 -177
  262. data/spec/mongoid/association/referenced/has_many_models.rb +3 -1
  263. data/spec/mongoid/association/referenced/has_many_spec.rb +25 -0
  264. data/spec/mongoid/association/referenced/has_one/buildable_spec.rb +2 -2
  265. data/spec/mongoid/association/referenced/has_one/proxy_spec.rb +107 -1
  266. data/spec/mongoid/association/referenced/has_one_models.rb +16 -0
  267. data/spec/mongoid/association/syncable_spec.rb +15 -1
  268. data/spec/mongoid/atomic/paths_spec.rb +0 -14
  269. data/spec/mongoid/attributes/nested_spec.rb +80 -11
  270. data/spec/mongoid/attributes/nested_spec_models.rb +48 -0
  271. data/spec/mongoid/attributes/projector_spec.rb +1 -5
  272. data/spec/mongoid/attributes_spec.rb +526 -33
  273. data/spec/mongoid/changeable_spec.rb +429 -37
  274. data/spec/mongoid/clients/factory_spec.rb +23 -30
  275. data/spec/mongoid/clients/sessions_spec.rb +0 -38
  276. data/spec/mongoid/clients_spec.rb +149 -15
  277. data/spec/mongoid/collection_configurable_spec.rb +158 -0
  278. data/spec/mongoid/config/defaults_spec.rb +160 -0
  279. data/spec/mongoid/config_spec.rb +214 -31
  280. data/spec/mongoid/contextual/aggregable/memory_spec.rb +396 -158
  281. data/spec/mongoid/contextual/aggregable/memory_table.yml +88 -0
  282. data/spec/mongoid/contextual/aggregable/memory_table_spec.rb +62 -0
  283. data/spec/mongoid/contextual/map_reduce_spec.rb +2 -16
  284. data/spec/mongoid/contextual/memory_spec.rb +850 -88
  285. data/spec/mongoid/contextual/mongo/documents_loader_spec.rb +187 -0
  286. data/spec/mongoid/contextual/mongo_spec.rb +2256 -1005
  287. data/spec/mongoid/contextual/none_spec.rb +60 -21
  288. data/spec/mongoid/copyable_spec.rb +453 -11
  289. data/spec/mongoid/criteria/findable_spec.rb +86 -210
  290. data/spec/mongoid/criteria/includable_spec.rb +1492 -0
  291. data/spec/mongoid/criteria/includable_spec_models.rb +54 -0
  292. data/spec/mongoid/criteria/marshalable_spec.rb +18 -1
  293. data/spec/mongoid/criteria/queryable/extensions/array_spec.rb +7 -19
  294. data/spec/mongoid/criteria/queryable/extensions/big_decimal_spec.rb +134 -26
  295. data/spec/mongoid/criteria/queryable/extensions/date_spec.rb +11 -0
  296. data/spec/mongoid/criteria/queryable/extensions/date_time_spec.rb +11 -0
  297. data/spec/mongoid/criteria/queryable/extensions/hash_spec.rb +0 -15
  298. data/spec/mongoid/criteria/queryable/extensions/numeric_spec.rb +73 -7
  299. data/spec/mongoid/criteria/queryable/extensions/string_spec.rb +4 -69
  300. data/spec/mongoid/criteria/queryable/extensions/symbol_spec.rb +0 -59
  301. data/spec/mongoid/criteria/queryable/extensions/time_spec.rb +11 -0
  302. data/spec/mongoid/criteria/queryable/extensions/time_with_zone_spec.rb +11 -0
  303. data/spec/mongoid/criteria/queryable/optional_spec.rb +15 -484
  304. data/spec/mongoid/criteria/queryable/options_spec.rb +1 -1
  305. data/spec/mongoid/criteria/queryable/selectable_logical_spec.rb +469 -0
  306. data/spec/mongoid/criteria/queryable/selectable_spec.rb +78 -86
  307. data/spec/mongoid/criteria/queryable/selector_spec.rb +15 -3
  308. data/spec/mongoid/criteria/translator_spec.rb +132 -0
  309. data/spec/mongoid/criteria_projection_spec.rb +1 -5
  310. data/spec/mongoid/criteria_spec.rb +469 -1205
  311. data/spec/mongoid/document_fields_spec.rb +173 -24
  312. data/spec/mongoid/document_spec.rb +32 -41
  313. data/spec/mongoid/errors/document_not_found_spec.rb +29 -2
  314. data/spec/mongoid/errors/invalid_field_spec.rb +1 -1
  315. data/spec/mongoid/errors/invalid_field_type_spec.rb +55 -0
  316. data/spec/mongoid/errors/mongoid_error_spec.rb +3 -1
  317. data/spec/mongoid/errors/no_environment_spec.rb +3 -3
  318. data/spec/mongoid/errors/readonly_document_spec.rb +2 -2
  319. data/spec/mongoid/errors/too_many_nested_attribute_records_spec.rb +1 -1
  320. data/spec/mongoid/extensions/array_spec.rb +16 -2
  321. data/spec/mongoid/extensions/big_decimal_spec.rb +712 -212
  322. data/spec/mongoid/extensions/binary_spec.rb +44 -9
  323. data/spec/mongoid/extensions/boolean_spec.rb +68 -82
  324. data/spec/mongoid/extensions/date_class_mongoize_spec.rb +7 -3
  325. data/spec/mongoid/extensions/date_spec.rb +71 -1
  326. data/spec/mongoid/extensions/date_time_spec.rb +15 -9
  327. data/spec/mongoid/extensions/float_spec.rb +53 -74
  328. data/spec/mongoid/extensions/hash_spec.rb +33 -3
  329. data/spec/mongoid/extensions/integer_spec.rb +50 -64
  330. data/spec/mongoid/extensions/range_spec.rb +255 -54
  331. data/spec/mongoid/extensions/regexp_spec.rb +58 -33
  332. data/spec/mongoid/extensions/set_spec.rb +106 -0
  333. data/spec/mongoid/extensions/string_spec.rb +53 -25
  334. data/spec/mongoid/extensions/symbol_spec.rb +18 -25
  335. data/spec/mongoid/extensions/time_spec.rb +639 -106
  336. data/spec/mongoid/extensions/time_with_zone_spec.rb +24 -83
  337. data/spec/mongoid/factory_spec.rb +61 -1
  338. data/spec/mongoid/fields/localized_spec.rb +80 -37
  339. data/spec/mongoid/fields_spec.rb +503 -87
  340. data/spec/mongoid/findable_spec.rb +450 -58
  341. data/spec/mongoid/indexable/specification_spec.rb +2 -2
  342. data/spec/mongoid/indexable_spec.rb +55 -30
  343. data/spec/mongoid/interceptable_spec.rb +824 -22
  344. data/spec/mongoid/interceptable_spec_models.rb +235 -4
  345. data/spec/mongoid/matcher/extract_attribute_spec.rb +1 -5
  346. data/spec/mongoid/mongoizable_spec.rb +285 -0
  347. data/spec/mongoid/persistable/creatable_spec.rb +2 -2
  348. data/spec/mongoid/persistable/deletable_spec.rb +28 -8
  349. data/spec/mongoid/persistable/destroyable_spec.rb +28 -8
  350. data/spec/mongoid/persistable/incrementable_spec.rb +37 -0
  351. data/spec/mongoid/persistable/logical_spec.rb +37 -0
  352. data/spec/mongoid/persistable/poppable_spec.rb +36 -0
  353. data/spec/mongoid/persistable/pullable_spec.rb +72 -0
  354. data/spec/mongoid/persistable/pushable_spec.rb +72 -0
  355. data/spec/mongoid/persistable/renamable_spec.rb +36 -0
  356. data/spec/mongoid/persistable/savable_spec.rb +96 -0
  357. data/spec/mongoid/persistable/settable_spec.rb +37 -0
  358. data/spec/mongoid/persistable/unsettable_spec.rb +36 -0
  359. data/spec/mongoid/persistable/updatable_spec.rb +20 -28
  360. data/spec/mongoid/persistable/upsertable_spec.rb +89 -1
  361. data/spec/mongoid/persistence_context_spec.rb +31 -57
  362. data/spec/mongoid/query_cache_middleware_spec.rb +0 -18
  363. data/spec/mongoid/query_cache_spec.rb +56 -215
  364. data/spec/mongoid/reloadable_spec.rb +83 -6
  365. data/spec/mongoid/scopable_spec.rb +91 -1
  366. data/spec/mongoid/serializable_spec.rb +25 -39
  367. data/spec/mongoid/shardable_spec.rb +4 -4
  368. data/spec/mongoid/stateful_spec.rb +150 -8
  369. data/spec/mongoid/tasks/database_rake_spec.rb +74 -0
  370. data/spec/mongoid/tasks/database_spec.rb +127 -0
  371. data/spec/mongoid/timestamps_spec.rb +392 -4
  372. data/spec/mongoid/timestamps_spec_models.rb +67 -0
  373. data/spec/mongoid/touchable_spec.rb +390 -2
  374. data/spec/mongoid/touchable_spec_models.rb +14 -8
  375. data/spec/mongoid/traversable_spec.rb +13 -35
  376. data/spec/mongoid/validatable/associated_spec.rb +13 -30
  377. data/spec/mongoid/validatable/presence_spec.rb +1 -1
  378. data/spec/mongoid/validatable/uniqueness_spec.rb +58 -31
  379. data/spec/mongoid/warnings_spec.rb +35 -0
  380. data/spec/mongoid_spec.rb +34 -16
  381. data/spec/rails/controller_extension/controller_runtime_spec.rb +2 -2
  382. data/spec/rails/mongoid_spec.rb +4 -16
  383. data/spec/spec_helper.rb +5 -0
  384. data/spec/support/constraints.rb +24 -0
  385. data/spec/support/immutable_ids.rb +118 -0
  386. data/spec/support/macros.rb +78 -0
  387. data/spec/support/models/artist.rb +0 -1
  388. data/spec/support/models/augmentation.rb +12 -0
  389. data/spec/support/models/band.rb +5 -0
  390. data/spec/support/models/book.rb +1 -0
  391. data/spec/support/models/building.rb +2 -0
  392. data/spec/support/models/catalog.rb +24 -0
  393. data/spec/support/models/circus.rb +3 -0
  394. data/spec/support/models/cover.rb +10 -0
  395. data/spec/support/models/fanatic.rb +8 -0
  396. data/spec/support/models/implant.rb +9 -0
  397. data/spec/support/models/label.rb +2 -0
  398. data/spec/support/models/lat_lng.rb +6 -0
  399. data/spec/support/models/name.rb +10 -0
  400. data/spec/support/models/passport.rb +9 -0
  401. data/spec/support/models/person.rb +2 -0
  402. data/spec/support/models/player.rb +2 -0
  403. data/spec/support/models/powerup.rb +12 -0
  404. data/spec/support/models/product.rb +1 -0
  405. data/spec/support/models/purse.rb +9 -0
  406. data/spec/support/models/registry.rb +1 -0
  407. data/spec/support/models/school.rb +14 -0
  408. data/spec/support/models/shield.rb +18 -0
  409. data/spec/support/models/student.rb +14 -0
  410. data/spec/support/models/weapon.rb +12 -0
  411. metadata +101 -96
  412. checksums.yaml.gz.sig +0 -0
  413. data/lib/mongoid/errors/eager_load.rb +0 -23
  414. data/lib/mongoid/errors/invalid_value.rb +0 -17
  415. data/spec/mongoid/criteria/queryable/extensions/bignum_spec.rb +0 -60
  416. data/spec/mongoid/criteria/queryable/extensions/fixnum_spec.rb +0 -60
  417. data/spec/mongoid/errors/eager_load_spec.rb +0 -31
  418. data/spec/shared/LICENSE +0 -20
  419. data/spec/shared/bin/get-mongodb-download-url +0 -17
  420. data/spec/shared/bin/s3-copy +0 -45
  421. data/spec/shared/bin/s3-upload +0 -69
  422. data/spec/shared/lib/mrss/child_process_helper.rb +0 -80
  423. data/spec/shared/lib/mrss/cluster_config.rb +0 -231
  424. data/spec/shared/lib/mrss/constraints.rb +0 -378
  425. data/spec/shared/lib/mrss/docker_runner.rb +0 -291
  426. data/spec/shared/lib/mrss/eg_config_utils.rb +0 -51
  427. data/spec/shared/lib/mrss/event_subscriber.rb +0 -210
  428. data/spec/shared/lib/mrss/lite_constraints.rb +0 -238
  429. data/spec/shared/lib/mrss/server_version_registry.rb +0 -120
  430. data/spec/shared/lib/mrss/session_registry.rb +0 -69
  431. data/spec/shared/lib/mrss/session_registry_legacy.rb +0 -60
  432. data/spec/shared/lib/mrss/spec_organizer.rb +0 -179
  433. data/spec/shared/lib/mrss/utils.rb +0 -15
  434. data/spec/shared/share/Dockerfile.erb +0 -325
  435. data/spec/shared/share/haproxy-1.conf +0 -16
  436. data/spec/shared/share/haproxy-2.conf +0 -17
  437. data/spec/shared/shlib/config.sh +0 -27
  438. data/spec/shared/shlib/distro.sh +0 -74
  439. data/spec/shared/shlib/server.sh +0 -392
  440. data/spec/shared/shlib/set_env.sh +0 -169
  441. data.tar.gz.sig +0 -0
  442. metadata.gz.sig +0 -3
@@ -6,7 +6,15 @@ module Mongoid
6
6
  # document can transition through.
7
7
  module Stateful
8
8
 
9
- attr_writer :destroyed, :flagged_for_destroy, :new_record
9
+ attr_writer :destroyed, :flagged_for_destroy, :previously_new_record
10
+
11
+ def new_record=(new_value)
12
+ @new_record ||= false
13
+ if @new_record && !new_value
14
+ @previously_new_record = true
15
+ end
16
+ @new_record = new_value
17
+ end
10
18
 
11
19
  # Returns true if the +Document+ has not been persisted to the database,
12
20
  # false if it has. This is determined by the variable @new_record
@@ -15,29 +23,47 @@ module Mongoid
15
23
  # @example Is the document new?
16
24
  # person.new_record?
17
25
  #
18
- # @return [ true, false ] True if new, false if not.
26
+ # @return [ true | false ] True if new, false if not.
19
27
  def new_record?
20
28
  @new_record ||= false
21
29
  end
22
30
 
31
+ # Returns true if this document was just created -- that is, prior to the last
32
+ # save, the object didn't exist in the database and new_record? would have
33
+ # returned true.
34
+ #
35
+ # @return [ true | false ] True if was just created, false if not.
36
+ def previously_new_record?
37
+ @previously_new_record ||= false
38
+ end
39
+
23
40
  # Checks if the document has been saved to the database. Returns false
24
41
  # if the document has been destroyed.
25
42
  #
26
43
  # @example Is the document persisted?
27
44
  # person.persisted?
28
45
  #
29
- # @return [ true, false ] True if persisted, false if not.
46
+ # @return [ true | false ] True if persisted, false if not.
30
47
  def persisted?
31
48
  !new_record? && !destroyed?
32
49
  end
33
50
 
51
+ # Checks if the document was previously saved to the database
52
+ # but now it has been deleted.
53
+ #
54
+ # @return [ true | false ] True if was persisted but now destroyed,
55
+ # otherwise false.
56
+ def previously_persisted?
57
+ !new_record? && destroyed?
58
+ end
59
+
34
60
  # Returns whether or not the document has been flagged for deletion, but
35
61
  # not destroyed yet. Used for atomic pulls of child documents.
36
62
  #
37
63
  # @example Is the document flagged?
38
64
  # document.flagged_for_destroy?
39
65
  #
40
- # @return [ true, false ] If the document is flagged.
66
+ # @return [ true | false ] If the document is flagged.
41
67
  def flagged_for_destroy?
42
68
  @flagged_for_destroy ||= false
43
69
  end
@@ -51,7 +77,7 @@ module Mongoid
51
77
  # @example Is the document destroyed?
52
78
  # person.destroyed?
53
79
  #
54
- # @return [ true, false ] True if destroyed, false if not.
80
+ # @return [ true | false ] True if destroyed, false if not.
55
81
  def destroyed?
56
82
  @destroyed ||= false
57
83
  end
@@ -61,7 +87,7 @@ module Mongoid
61
87
  # @example Is this pushable?
62
88
  # person.pushable?
63
89
  #
64
- # @return [ true, false ] Is the document new and embedded?
90
+ # @return [ true | false ] Is the document new and embedded?
65
91
  def pushable?
66
92
  new_record? &&
67
93
  embedded_many? &&
@@ -69,14 +95,35 @@ module Mongoid
69
95
  !_parent.delayed_atomic_sets[atomic_path]
70
96
  end
71
97
 
98
+ # Flags the document as readonly. Will cause a ReadonlyDocument error to be
99
+ # raised if the document is attempted to be saved, updated or destroyed.
100
+ #
101
+ # @example Flag the document as readonly.
102
+ # document.readonly!
103
+ #
104
+ # @return [ true | false ] true if the document was successfully marked
105
+ # readonly, false otherwise.
106
+ def readonly!
107
+ if Mongoid.legacy_readonly
108
+ Mongoid::Warnings.warn_legacy_readonly
109
+ false
110
+ else
111
+ @readonly = true
112
+ end
113
+ end
114
+
72
115
  # Is the document readonly?
73
116
  #
74
117
  # @example Is the document readonly?
75
118
  # document.readonly?
76
119
  #
77
- # @return [ true, false ] If the document is readonly.
120
+ # @return [ true | false ] If the document is readonly.
78
121
  def readonly?
79
- __selected_fields != nil
122
+ if Mongoid.legacy_readonly
123
+ __selected_fields != nil
124
+ else
125
+ @readonly ||= false
126
+ end
80
127
  end
81
128
 
82
129
  # Determine if the document can be set.
@@ -84,7 +131,7 @@ module Mongoid
84
131
  # @example Is this settable?
85
132
  # person.settable?
86
133
  #
87
- # @return [ true, false ] Is this document a new embeds one?
134
+ # @return [ true | false ] Is this document a new embeds one?
88
135
  def settable?
89
136
  new_record? && embedded_one? && _parent.persisted?
90
137
  end
@@ -94,7 +141,7 @@ module Mongoid
94
141
  # @example Is the document updateable?
95
142
  # person.updateable?
96
143
  #
97
- # @return [ true, false ] If the document is changed and persisted.
144
+ # @return [ true | false ] If the document is changed and persisted.
98
145
  def updateable?
99
146
  persisted? && changed?
100
147
  end
@@ -5,6 +5,11 @@ namespace :db do
5
5
  task :load_models do
6
6
  end
7
7
 
8
+ desc "Create collections for Mongoid models"
9
+ task :create_collections => [:environment, :load_models] do
10
+ ::Mongoid::Tasks::Database.create_collections
11
+ end
12
+
8
13
  desc "Create indexes specified in Mongoid models"
9
14
  task :create_indexes => [:environment, :load_models] do
10
15
  ::Mongoid::Tasks::Database.create_indexes
@@ -34,5 +39,12 @@ namespace :db do
34
39
  task :purge => :environment do
35
40
  ::Mongoid.purge!
36
41
  end
42
+
43
+ namespace :create_collections do
44
+ desc "Drop and create collections for Mongoid models"
45
+ task :force => [:environment, :load_models] do
46
+ ::Mongoid::Tasks::Database.create_collections(force: true)
47
+ end
48
+ end
37
49
  end
38
50
  end
@@ -5,6 +5,26 @@ module Mongoid
5
5
  module Database
6
6
  extend self
7
7
 
8
+ # Create collections for each model given the provided globs and the class is
9
+ # not embedded.
10
+ #
11
+ # @param [ Array<Mongoid::Document> ] models. Array of document classes for
12
+ # which collections should be created. Defaulted to all document classes
13
+ # in the application.
14
+ # @param [ true | false ] force If true, the method will drop existing
15
+ # collections before creating new ones. If false, the method will create
16
+ # only new collection (that do not exist in the database).
17
+ def create_collections(models = ::Mongoid.models, force: false)
18
+ models.each do |model|
19
+ if !model.embedded? || model.cyclic?
20
+ model.create_collection(force: force)
21
+ logger.info("MONGOID: Created collection for #{model}:")
22
+ else
23
+ logger.info("MONGOID: collection options ignored on: #{model}, please define in the root model.")
24
+ end
25
+ end
26
+ end
27
+
8
28
  # Create indexes for each model given the provided globs and the class is
9
29
  # not embedded.
10
30
  #
@@ -36,7 +56,6 @@ module Mongoid
36
56
  # Mongoid::Tasks::Database.undefined_indexes
37
57
  #
38
58
  # @return [ Array<Hash> ] The list of undefined indexes by model.
39
- #
40
59
  def undefined_indexes(models = ::Mongoid.models)
41
60
  undefined_by_model = {}
42
61
 
@@ -90,7 +109,6 @@ module Mongoid
90
109
  # Mongoid::Tasks::Database.remove_indexes
91
110
  #
92
111
  # @return [ Array<Class> ] The un-indexed models.
93
- #
94
112
  def remove_indexes(models = ::Mongoid.models)
95
113
  models.each do |model|
96
114
  next if model.embedded?
@@ -37,7 +37,7 @@ module Mongoid
37
37
  # @example Is the current thread in assigning mode?
38
38
  # proxy._assigning?
39
39
  #
40
- # @return [ true, false ] If the thread is assigning.
40
+ # @return [ true | false ] If the thread is assigning.
41
41
  def _assigning?
42
42
  Threaded.executing?(ASSIGN)
43
43
  end
@@ -62,7 +62,7 @@ module Mongoid
62
62
  # @example Is the current thread in binding mode?
63
63
  # proxy.binding?
64
64
  #
65
- # @return [ true, false ] If the thread is binding.
65
+ # @return [ true | false ] If the thread is binding.
66
66
  def _binding?
67
67
  Threaded.executing?(BIND)
68
68
  end
@@ -87,7 +87,7 @@ module Mongoid
87
87
  # @example Is the current thread in building mode?
88
88
  # proxy._building?
89
89
  #
90
- # @return [ true, false ] If the thread is building.
90
+ # @return [ true | false ] If the thread is building.
91
91
  def _building?
92
92
  Threaded.executing?(BUILD)
93
93
  end
@@ -97,7 +97,7 @@ module Mongoid
97
97
  # @example Is the current thread in creating mode?
98
98
  # proxy.creating?
99
99
  #
100
- # @return [ true, false ] If the thread is creating.
100
+ # @return [ true | false ] If the thread is creating.
101
101
  def _creating?
102
102
  Threaded.executing?(CREATE)
103
103
  end
@@ -122,7 +122,7 @@ module Mongoid
122
122
  # @example Is the current thread in loading mode?
123
123
  # proxy._loading?
124
124
  #
125
- # @return [ true, false ] If the thread is loading.
125
+ # @return [ true | false ] If the thread is loading.
126
126
  def _loading?
127
127
  Threaded.executing?(LOAD)
128
128
  end
@@ -26,6 +26,10 @@ module Mongoid
26
26
  hash[key] = "[mongoid]:#{key}-stack"
27
27
  end
28
28
 
29
+ # The key storing the default value for whether or not callbacks are
30
+ # executed on documents.
31
+ EXECUTE_CALLBACKS = '[mongoid]:execute-callbacks'
32
+
29
33
  extend self
30
34
 
31
35
  # Begin entry into a named thread local stack.
@@ -45,7 +49,7 @@ module Mongoid
45
49
  # @example Get the global database override.
46
50
  # Threaded.database_override
47
51
  #
48
- # @return [ String, Symbol ] The override.
52
+ # @return [ String | Symbol ] The override.
49
53
  def database_override
50
54
  Thread.current[DATABASE_OVERRIDE_KEY]
51
55
  end
@@ -55,9 +59,9 @@ module Mongoid
55
59
  # @example Set the global database override.
56
60
  # Threaded.database_override = :testing
57
61
  #
58
- # @param [ String, Symbol ] name The global override name.
62
+ # @param [ String | Symbol ] name The global override name.
59
63
  #
60
- # @return [ String, Symbol ] The override.
64
+ # @return [ String | Symbol ] The override.
61
65
  def database_override=(name)
62
66
  Thread.current[DATABASE_OVERRIDE_KEY] = name
63
67
  end
@@ -167,7 +171,7 @@ module Mongoid
167
171
  # @example Get the global client override.
168
172
  # Threaded.client_override
169
173
  #
170
- # @return [ String, Symbol ] The override.
174
+ # @return [ String | Symbol ] The override.
171
175
  def client_override
172
176
  Thread.current[CLIENT_OVERRIDE_KEY]
173
177
  end
@@ -177,9 +181,9 @@ module Mongoid
177
181
  # @example Set the global client override.
178
182
  # Threaded.client_override = :testing
179
183
  #
180
- # @param [ String, Symbol ] name The global override name.
184
+ # @param [ String | Symbol ] name The global override name.
181
185
  #
182
- # @return [ String, Symbol ] The override.
186
+ # @return [ String | Symbol ] The override.
183
187
  def client_override=(name)
184
188
  Thread.current[CLIENT_OVERRIDE_KEY] = name
185
189
  end
@@ -255,7 +259,7 @@ module Mongoid
255
259
  #
256
260
  # @param [ Document ] document The document to check.
257
261
  #
258
- # @return [ true, false ] If the document is autosaved.
262
+ # @return [ true | false ] If the document is autosaved.
259
263
  def autosaved?(document)
260
264
  autosaves_for(document.class).include?(document._id)
261
265
  end
@@ -267,7 +271,7 @@ module Mongoid
267
271
  #
268
272
  # @param [ Document ] document The document to check.
269
273
  #
270
- # @return [ true, false ] If the document is validated.
274
+ # @return [ true | false ] If the document is validated.
271
275
  def validated?(document)
272
276
  validations_for(document.class).include?(document._id)
273
277
  end
@@ -322,7 +326,7 @@ module Mongoid
322
326
  #
323
327
  # @param [ Mongo::Session ] session The session to save.
324
328
  def set_session(session)
325
- Thread.current[:session] = session
329
+ Thread.current["[mongoid]:session"] = session
326
330
  end
327
331
 
328
332
  # Get the cached session for this thread.
@@ -330,9 +334,9 @@ module Mongoid
330
334
  # @example Get the session for this thread.
331
335
  # Threaded.get_session
332
336
  #
333
- # @return [ Mongo::Session, nil ] The session cached on this thread or nil.
337
+ # @return [ Mongo::Session | nil ] The session cached on this thread or nil.
334
338
  def get_session
335
- Thread.current[:session]
339
+ Thread.current["[mongoid]:session"]
336
340
  end
337
341
 
338
342
  # Clear the cached session for this thread.
@@ -344,7 +348,33 @@ module Mongoid
344
348
  def clear_session
345
349
  session = get_session
346
350
  session.end_session if session
347
- Thread.current[:session] = nil
351
+ Thread.current["[mongoid]:session"] = nil
352
+ end
353
+
354
+ # Queries whether document callbacks should be executed by default for the
355
+ # current thread.
356
+ #
357
+ # Unless otherwise indicated (by #execute_callbacks=), this will return
358
+ # true.
359
+ #
360
+ # @return [ true | false ] Whether or not document callbacks should be
361
+ # executed by default.
362
+ def execute_callbacks?
363
+ if Thread.current.key?(EXECUTE_CALLBACKS)
364
+ Thread.current[EXECUTE_CALLBACKS]
365
+ else
366
+ true
367
+ end
368
+ end
369
+
370
+ # Indicates whether document callbacks should be invoked by default for
371
+ # the current thread. Individual documents may further override the
372
+ # callback behavior, but this will be used for the default behavior.
373
+ #
374
+ # @param flag [ true | false ] Whether or not document callbacks should be
375
+ # executed by default.
376
+ def execute_callbacks=(flag)
377
+ Thread.current[EXECUTE_CALLBACKS] = flag
348
378
  end
349
379
  end
350
380
  end
@@ -23,7 +23,7 @@ module Mongoid
23
23
  # person.set_created_at
24
24
  def set_created_at
25
25
  if !timeless? && !created_at
26
- time = Time.now.utc
26
+ time = Time.configured.now
27
27
  self.updated_at = time if is_a?(Updated) && !updated_at_changed?
28
28
  self.created_at = time
29
29
  end
@@ -24,7 +24,7 @@ module Mongoid
24
24
  # person.set_updated_at
25
25
  def set_updated_at
26
26
  if able_to_set_updated_at?
27
- self.updated_at = Time.now.utc unless updated_at_changed?
27
+ self.updated_at = Time.configured.now unless updated_at_changed?
28
28
  end
29
29
 
30
30
  clear_timeless_option
@@ -35,7 +35,7 @@ module Mongoid
35
35
  # @example Can the timestamp be set?
36
36
  # document.able_to_set_updated_at?
37
37
  #
38
- # @return [ true, false ] If the timestamp can be set.
38
+ # @return [ true | false ] If the timestamp can be set.
39
39
  def able_to_set_updated_at?
40
40
  !frozen? && !timeless? && (new_record? || changed?)
41
41
  end
@@ -19,13 +19,13 @@ module Mongoid
19
19
  #
20
20
  # @param [ Symbol ] field The name of an additional field to update.
21
21
  #
22
- # @return [ true/false ] false if record is new_record otherwise true.
22
+ # @return [ true/false ] false if document is new_record otherwise true.
23
23
  def touch(field = nil)
24
24
  return false if _root.new_record?
25
- current = Time.now
25
+ current = Time.configured.now
26
26
  field = database_field_name(field)
27
27
  write_attribute(:updated_at, current) if respond_to?("updated_at=")
28
- write_attribute(field, current) if field
28
+ write_attribute(field, current) if field.present?
29
29
 
30
30
  # If the document being touched is embedded, touch its parents
31
31
  # all the way through the composition hierarchy to the root object,
@@ -60,7 +60,6 @@ module Mongoid
60
60
 
61
61
  # Callbacks are invoked on the composition root first and on the
62
62
  # leaf-most embedded document last.
63
- # TODO add tests, see MONGOID-5015.
64
63
  run_callbacks(:touch)
65
64
  true
66
65
  end
@@ -203,7 +203,7 @@ module Mongoid
203
203
  # @example Check if the document is a subclass
204
204
  # Square.new.hereditary?
205
205
  #
206
- # @return [ true, false ] True if hereditary, false if not.
206
+ # @return [ true | false ] True if hereditary, false if not.
207
207
  def hereditary?
208
208
  self.class.hereditary?
209
209
  end
@@ -233,10 +233,11 @@ module Mongoid
233
233
  def remove_child(child)
234
234
  name = child.association_name
235
235
  if child.embedded_one?
236
+ self.attributes.delete(child._association.store_as)
236
237
  remove_ivar(name)
237
238
  else
238
239
  relation = send(name)
239
- relation.send(:delete_one, child)
240
+ relation._remove(child)
240
241
  end
241
242
  end
242
243
 
@@ -282,7 +283,7 @@ module Mongoid
282
283
  # @example Is the document the root?
283
284
  # document._root?
284
285
  #
285
- # @return [ true, false ] If the document is the root.
286
+ # @return [ true | false ] If the document is the root.
286
287
  def _root?
287
288
  _parent ? false : true
288
289
  end
@@ -294,7 +295,7 @@ module Mongoid
294
295
  # @example Check if the document is a subclass.
295
296
  # Square.hereditary?
296
297
  #
297
- # @return [ true, false ] True if hereditary, false if not.
298
+ # @return [ true | false ] True if hereditary, false if not.
298
299
  def hereditary?
299
300
  !!(Mongoid::Document > superclass)
300
301
  end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mongoid
4
+
5
+ # @api private
6
+ module Utils
7
+
8
+ # This function should be used if you need to measure time.
9
+ # @example Calculate elapsed time.
10
+ # starting = Utils.monotonic_time
11
+ # # do something time consuming
12
+ # ending = Utils.monotonic_time
13
+ # puts "It took #{(ending - starting).to_i} seconds"
14
+ #
15
+ # @see https://blog.dnsimple.com/2018/03/elapsed-time-with-ruby-the-right-way/
16
+ #
17
+ # @return [Float] seconds according to monotonic clock
18
+ module_function def monotonic_time
19
+ Process.clock_gettime(Process::CLOCK_MONOTONIC)
20
+ end
21
+ end
22
+ end
@@ -15,32 +15,110 @@ module Mongoid
15
15
  #
16
16
  # validates_associated :name, :addresses
17
17
  # end
18
- class AssociatedValidator < ActiveModel::EachValidator
18
+ class AssociatedValidator < ActiveModel::Validator
19
+ # Required by `validates_with` so that the validator
20
+ # gets added to the correct attributes.
21
+ def attributes
22
+ options[:attributes]
23
+ end
19
24
 
20
- # Validates that the associations provided are either all nil or all
21
- # valid. If neither is true then the appropriate errors will be added to
22
- # the parent document.
25
+ # Checks that the named associations of the given record
26
+ # (`attributes`) are valid. This does NOT load the associations
27
+ # from the database, and will only validate records that are dirty
28
+ # or unpersisted.
23
29
  #
24
- # @example Validate the association.
25
- # validator.validate_each(document, :name, name)
30
+ # If anything is not valid, appropriate errors will be added to
31
+ # the `document` parameter.
32
+ #
33
+ # @param [ Mongoid::Document ] document the document with the
34
+ # associations to validate.
35
+ def validate(document)
36
+ options[:attributes].each do |attr_name|
37
+ validate_association(document, attr_name)
38
+ end
39
+ end
40
+
41
+ private
42
+
43
+ # Validates that the given association provided is either nil,
44
+ # persisted and unchanged, or invalid. Otherwise, the appropriate errors
45
+ # will be added to the parent document.
26
46
  #
27
47
  # @param [ Document ] document The document to validate.
28
48
  # @param [ Symbol ] attribute The association to validate.
29
- # @param [ Object ] value The value of the association.
30
- def validate_each(document, attribute, value)
31
- begin
32
- document.begin_validate
33
- valid = Array.wrap(value).collect do |doc|
34
- if doc.nil? || doc.flagged_for_destroy?
35
- true
49
+ def validate_association(document, attribute)
50
+ # grab the proxy from the instance variable directly; we don't want
51
+ # any loading logic to run; we just want to see if it's already
52
+ # been loaded.
53
+ proxy = document.ivar(attribute)
54
+ return unless proxy
55
+
56
+ # if the variable exists, now we see if it is a proxy, or an actual
57
+ # document. It might be a literal document instead of a proxy if this
58
+ # document was created with a Document instance as a provided attribute,
59
+ # e.g. "Post.new(message: Message.new)".
60
+ target = proxy.respond_to?(:_target) ? proxy._target : proxy
61
+
62
+ # Now, fetch the list of documents from the target. Target may be a
63
+ # single value, or a list of values, and in the case of HasMany,
64
+ # might be a rather complex collection. We need to do this without
65
+ # triggering a load, so it's a bit of a delicate dance.
66
+ list = get_target_documents(target)
67
+
68
+ valid = document.validating do
69
+ # Now, treating the target as an array, look at each element
70
+ # and see if it is valid, but only if it has already been
71
+ # persisted, or changed, and hasn't been flagged for destroy.
72
+ list.all? do |value|
73
+ if value && !value.flagged_for_destroy? && (!value.persisted? || value.changed?)
74
+ value.validated? ? true : value.valid?
36
75
  else
37
- doc.validated? ? true : doc.valid?
76
+ true
38
77
  end
39
- end.all?
40
- ensure
41
- document.exit_validate
78
+ end
79
+ end
80
+
81
+ document.errors.add(attribute, :invalid) unless valid
82
+ end
83
+
84
+ private
85
+
86
+ # Examine the given target object and return an array of
87
+ # documents (possibly empty) that the target represents.
88
+ #
89
+ # @param [ Array | Mongoid::Document | Mongoid::Association::Proxy | HasMany::Enumerable ] target
90
+ # the target object to examine.
91
+ #
92
+ # @return [ Array<Mongoid::Document> ] the list of documents
93
+ def get_target_documents(target)
94
+ if target.respond_to?(:_loaded?)
95
+ get_target_documents_for_has_many(target)
96
+ else
97
+ get_target_documents_for_other(target)
42
98
  end
43
- document.errors.add(attribute, :invalid, **options) unless valid
99
+ end
100
+
101
+ # Returns the list of all currently in-memory values held by
102
+ # the target. The target will not be loaded.
103
+ #
104
+ # @param [ HasMany::Enumerable ] target the target that will
105
+ # be examined for in-memory documents.
106
+ #
107
+ # @return [ Array<Mongoid::Document> ] the in-memory documents
108
+ # held by the target.
109
+ def get_target_documents_for_has_many(target)
110
+ [ *target._loaded.values, *target._added.values ]
111
+ end
112
+
113
+ # Returns the target as an array. If the target represents a single
114
+ # value, it is wrapped in an array.
115
+ #
116
+ # @param [ Array | Mongoid::Document | Mongoid::Association::Proxy ] target
117
+ # the target to return.
118
+ #
119
+ # @return [ Array<Mongoid::Document> ] the target, as an array.
120
+ def get_target_documents_for_other(target)
121
+ Array.wrap(target)
44
122
  end
45
123
  end
46
124
  end
@@ -12,7 +12,7 @@ module Mongoid
12
12
  # validator.validate_each(model, :name, "value")
13
13
  #
14
14
  # @param [ Document ] document The document.
15
- # @param [ Symbol, String ] attribute The attribute to validate.
15
+ # @param [ Symbol | String ] attribute The attribute to validate.
16
16
  # @param [ Object ] value The attribute value.
17
17
  def validate_each(document, attribute, value)
18
18
  field = document.fields[document.database_field_name(attribute)]
@@ -18,8 +18,7 @@ module Mongoid
18
18
  # validates_associated :name, :addresses
19
19
  # end
20
20
  #
21
- # @param [ Array ] args The arguments to pass to the validator.
22
- #
21
+ # @param [ Object... ] *args The arguments to pass to the validator.
23
22
  def validates_associated(*args)
24
23
  validates_with(AssociatedValidator, _merge_attributes(args))
25
24
  end
@@ -36,8 +35,7 @@ module Mongoid
36
35
  # validates_uniqueness_of :title
37
36
  # end
38
37
  #
39
- # @param [ Array ] args The arguments to pass to the validator.
40
- #
38
+ # @param [ Object... ] *args The arguments to pass to the validator.
41
39
  def validates_uniqueness_of(*args)
42
40
  validates_with(UniquenessValidator, _merge_attributes(args))
43
41
  end
@@ -52,7 +50,7 @@ module Mongoid
52
50
  # validates_format_of :title, with: /\A[a-z0-9 \-_]*\z/i
53
51
  # end
54
52
  #
55
- # @param [ Array ] args The names of the fields to validate.
53
+ # @param [ Object... ] *args The names of the field(s) to validate.
56
54
  def validates_format_of(*args)
57
55
  validates_with(FormatValidator, _merge_attributes(args))
58
56
  end
@@ -67,7 +65,7 @@ module Mongoid
67
65
  # validates_length_of :title, minimum: 100
68
66
  # end
69
67
  #
70
- # @param [ Array ] args The names of the fields to validate.
68
+ # @param [ Object... ] *args The names of the field(s) to validate.
71
69
  def validates_length_of(*args)
72
70
  validates_with(LengthValidator, _merge_attributes(args))
73
71
  end
@@ -82,7 +80,7 @@ module Mongoid
82
80
  # validates_presence_of :title
83
81
  # end
84
82
  #
85
- # @param [ Array ] args The names of the fields to validate.
83
+ # @param [ Object... ] *args The names of the field(s) to validate.
86
84
  def validates_presence_of(*args)
87
85
  validates_with(PresenceValidator, _merge_attributes(args))
88
86
  end