mongoid 7.4.0 → 8.0.1

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 (315) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/README.md +3 -3
  4. data/lib/config/locales/en.yml +51 -28
  5. data/lib/mongoid/association/accessors.rb +32 -3
  6. data/lib/mongoid/association/bindable.rb +48 -0
  7. data/lib/mongoid/association/builders.rb +4 -2
  8. data/lib/mongoid/association/eager_loadable.rb +29 -7
  9. data/lib/mongoid/association/embedded/batchable.rb +48 -8
  10. data/lib/mongoid/association/embedded/embedded_in/binding.rb +24 -2
  11. data/lib/mongoid/association/embedded/embedded_in.rb +2 -1
  12. data/lib/mongoid/association/embedded/embeds_many/binding.rb +1 -0
  13. data/lib/mongoid/association/embedded/embeds_many/buildable.rb +1 -1
  14. data/lib/mongoid/association/embedded/embeds_many/proxy.rb +40 -18
  15. data/lib/mongoid/association/embedded/embeds_one/buildable.rb +18 -4
  16. data/lib/mongoid/association/embedded/embeds_one/proxy.rb +21 -2
  17. data/lib/mongoid/association/macros.rb +22 -1
  18. data/lib/mongoid/association/many.rb +5 -0
  19. data/lib/mongoid/association/nested/many.rb +2 -1
  20. data/lib/mongoid/association/proxy.rb +12 -0
  21. data/lib/mongoid/association/referenced/auto_save.rb +3 -2
  22. data/lib/mongoid/association/referenced/belongs_to/binding.rb +1 -0
  23. data/lib/mongoid/association/referenced/belongs_to/buildable.rb +1 -1
  24. data/lib/mongoid/association/referenced/belongs_to.rb +1 -1
  25. data/lib/mongoid/association/referenced/counter_cache.rb +8 -8
  26. data/lib/mongoid/association/referenced/has_and_belongs_to_many/proxy.rb +64 -11
  27. data/lib/mongoid/association/referenced/has_and_belongs_to_many.rb +4 -1
  28. data/lib/mongoid/association/referenced/has_many/enumerable.rb +10 -14
  29. data/lib/mongoid/association/referenced/has_many/proxy.rb +12 -9
  30. data/lib/mongoid/association/referenced/has_one/buildable.rb +1 -1
  31. data/lib/mongoid/association/referenced/has_one/proxy.rb +8 -11
  32. data/lib/mongoid/association/referenced/syncable.rb +2 -2
  33. data/lib/mongoid/association/relatable.rb +38 -4
  34. data/lib/mongoid/atomic/paths/embedded/many.rb +19 -0
  35. data/lib/mongoid/attributes/processing.rb +9 -2
  36. data/lib/mongoid/attributes.rb +30 -27
  37. data/lib/mongoid/changeable.rb +37 -2
  38. data/lib/mongoid/clients/options.rb +4 -0
  39. data/lib/mongoid/clients/sessions.rb +2 -14
  40. data/lib/mongoid/config/environment.rb +20 -4
  41. data/lib/mongoid/config.rb +25 -10
  42. data/lib/mongoid/contextual/aggregable/memory.rb +23 -15
  43. data/lib/mongoid/contextual/aggregable/mongo.rb +1 -1
  44. data/lib/mongoid/contextual/map_reduce.rb +2 -2
  45. data/lib/mongoid/contextual/memory.rb +176 -17
  46. data/lib/mongoid/contextual/mongo.rb +226 -206
  47. data/lib/mongoid/contextual/none.rb +66 -4
  48. data/lib/mongoid/copyable.rb +32 -8
  49. data/lib/mongoid/criteria/includable.rb +24 -20
  50. data/lib/mongoid/criteria/marshalable.rb +10 -2
  51. data/lib/mongoid/criteria/queryable/extensions/array.rb +2 -13
  52. data/lib/mongoid/criteria/queryable/extensions/big_decimal.rb +25 -4
  53. data/lib/mongoid/criteria/queryable/extensions/boolean.rb +1 -1
  54. data/lib/mongoid/criteria/queryable/extensions/date.rb +6 -1
  55. data/lib/mongoid/criteria/queryable/extensions/date_time.rb +6 -1
  56. data/lib/mongoid/criteria/queryable/extensions/hash.rb +0 -14
  57. data/lib/mongoid/criteria/queryable/extensions/numeric.rb +1 -1
  58. data/lib/mongoid/criteria/queryable/extensions/object.rb +2 -1
  59. data/lib/mongoid/criteria/queryable/extensions/range.rb +13 -5
  60. data/lib/mongoid/criteria/queryable/extensions/regexp.rb +1 -1
  61. data/lib/mongoid/criteria/queryable/extensions/symbol.rb +3 -1
  62. data/lib/mongoid/criteria/queryable/extensions/time.rb +6 -1
  63. data/lib/mongoid/criteria/queryable/extensions/time_with_zone.rb +6 -1
  64. data/lib/mongoid/criteria/queryable/mergeable.rb +21 -0
  65. data/lib/mongoid/criteria/queryable/optional.rb +3 -9
  66. data/lib/mongoid/criteria/queryable/options.rb +1 -1
  67. data/lib/mongoid/criteria/queryable/selectable.rb +28 -34
  68. data/lib/mongoid/criteria/queryable/selector.rb +89 -4
  69. data/lib/mongoid/criteria/queryable/smash.rb +39 -6
  70. data/lib/mongoid/criteria/queryable.rb +11 -6
  71. data/lib/mongoid/criteria.rb +1 -26
  72. data/lib/mongoid/deprecable.rb +36 -0
  73. data/lib/mongoid/deprecation.rb +25 -0
  74. data/lib/mongoid/document.rb +96 -32
  75. data/lib/mongoid/errors/document_not_found.rb +29 -8
  76. data/lib/mongoid/errors/invalid_dot_dollar_assignment.rb +23 -0
  77. data/lib/mongoid/errors/invalid_field.rb +5 -1
  78. data/lib/mongoid/errors/invalid_field_type.rb +26 -0
  79. data/lib/mongoid/errors/too_many_nested_attribute_records.rb +1 -1
  80. data/lib/mongoid/errors.rb +2 -2
  81. data/lib/mongoid/extensions/array.rb +8 -6
  82. data/lib/mongoid/extensions/big_decimal.rb +29 -10
  83. data/lib/mongoid/extensions/binary.rb +42 -0
  84. data/lib/mongoid/extensions/boolean.rb +8 -2
  85. data/lib/mongoid/extensions/date.rb +26 -20
  86. data/lib/mongoid/extensions/date_time.rb +1 -1
  87. data/lib/mongoid/extensions/float.rb +4 -5
  88. data/lib/mongoid/extensions/hash.rb +12 -5
  89. data/lib/mongoid/extensions/integer.rb +4 -5
  90. data/lib/mongoid/extensions/object.rb +2 -0
  91. data/lib/mongoid/extensions/range.rb +41 -10
  92. data/lib/mongoid/extensions/regexp.rb +11 -4
  93. data/lib/mongoid/extensions/set.rb +11 -4
  94. data/lib/mongoid/extensions/string.rb +2 -13
  95. data/lib/mongoid/extensions/symbol.rb +3 -14
  96. data/lib/mongoid/extensions/time.rb +27 -16
  97. data/lib/mongoid/extensions/time_with_zone.rb +1 -2
  98. data/lib/mongoid/extensions.rb +1 -0
  99. data/lib/mongoid/factory.rb +42 -7
  100. data/lib/mongoid/fields/foreign_key.rb +7 -0
  101. data/lib/mongoid/fields/validators/macro.rb +3 -9
  102. data/lib/mongoid/fields.rb +194 -28
  103. data/lib/mongoid/findable.rb +27 -7
  104. data/lib/mongoid/indexable/specification.rb +1 -1
  105. data/lib/mongoid/indexable/validators/options.rb +4 -1
  106. data/lib/mongoid/interceptable.rb +69 -9
  107. data/lib/mongoid/persistable/creatable.rb +14 -5
  108. data/lib/mongoid/persistable/updatable.rb +12 -5
  109. data/lib/mongoid/persistable/upsertable.rb +1 -1
  110. data/lib/mongoid/persistence_context.rb +19 -2
  111. data/lib/mongoid/query_cache.rb +6 -258
  112. data/lib/mongoid/railties/controller_runtime.rb +1 -1
  113. data/lib/mongoid/reloadable.rb +7 -3
  114. data/lib/mongoid/selectable.rb +1 -2
  115. data/lib/mongoid/stateful.rb +27 -1
  116. data/lib/mongoid/timestamps/created.rb +1 -1
  117. data/lib/mongoid/timestamps/updated.rb +1 -1
  118. data/lib/mongoid/touchable.rb +2 -3
  119. data/lib/mongoid/traversable.rb +5 -1
  120. data/lib/mongoid/validatable/uniqueness.rb +2 -1
  121. data/lib/mongoid/version.rb +1 -1
  122. data/lib/mongoid/warnings.rb +28 -0
  123. data/lib/mongoid.rb +2 -0
  124. data/lib/rails/generators/mongoid/config/templates/mongoid.yml +11 -5
  125. data/spec/config/mongoid.yml +16 -0
  126. data/spec/config/mongoid_with_schema_map_uuid.yml +27 -0
  127. data/spec/integration/app_spec.rb +28 -26
  128. data/spec/integration/associations/belongs_to_spec.rb +18 -0
  129. data/spec/integration/associations/embedded_dirty_spec.rb +28 -0
  130. data/spec/integration/associations/embedded_spec.rb +15 -0
  131. data/spec/integration/associations/embeds_many_spec.rb +15 -2
  132. data/spec/integration/associations/embeds_one_spec.rb +18 -0
  133. data/spec/integration/associations/foreign_key_spec.rb +9 -0
  134. data/spec/integration/associations/has_and_belongs_to_many_spec.rb +21 -0
  135. data/spec/integration/associations/has_one_spec.rb +97 -1
  136. data/spec/integration/associations/scope_option_spec.rb +1 -1
  137. data/spec/integration/callbacks_models.rb +95 -1
  138. data/spec/integration/callbacks_spec.rb +226 -4
  139. data/spec/integration/criteria/range_spec.rb +95 -1
  140. data/spec/integration/discriminator_key_spec.rb +115 -76
  141. data/spec/integration/dots_and_dollars_spec.rb +277 -0
  142. data/spec/integration/matcher_examples_spec.rb +20 -13
  143. data/spec/integration/matcher_operator_data/type_decimal.yml +3 -2
  144. data/spec/integration/matcher_operator_spec.rb +3 -5
  145. data/spec/integration/persistence/range_field_spec.rb +350 -0
  146. data/spec/lite_spec_helper.rb +1 -1
  147. data/spec/mongoid/association/counter_cache_spec.rb +1 -1
  148. data/spec/mongoid/association/depending_spec.rb +9 -9
  149. data/spec/mongoid/association/eager_spec.rb +2 -1
  150. data/spec/mongoid/association/embedded/embedded_in/binding_spec.rb +2 -1
  151. data/spec/mongoid/association/embedded/embedded_in/buildable_spec.rb +54 -0
  152. data/spec/mongoid/association/embedded/embedded_in/proxy_spec.rb +69 -9
  153. data/spec/mongoid/association/embedded/embeds_many/buildable_spec.rb +112 -0
  154. data/spec/mongoid/association/embedded/embeds_many/proxy_spec.rb +219 -8
  155. data/spec/mongoid/association/embedded/embeds_many_models.rb +157 -0
  156. data/spec/mongoid/association/embedded/embeds_many_query_spec.rb +12 -0
  157. data/spec/mongoid/association/embedded/embeds_many_spec.rb +68 -0
  158. data/spec/mongoid/association/embedded/embeds_one/buildable_spec.rb +25 -0
  159. data/spec/mongoid/association/embedded/embeds_one_models.rb +19 -0
  160. data/spec/mongoid/association/embedded/embeds_one_spec.rb +28 -0
  161. data/spec/mongoid/association/referenced/belongs_to/binding_spec.rb +2 -1
  162. data/spec/mongoid/association/referenced/belongs_to/buildable_spec.rb +54 -0
  163. data/spec/mongoid/association/referenced/belongs_to/proxy_spec.rb +15 -0
  164. data/spec/mongoid/association/referenced/belongs_to_models.rb +11 -0
  165. data/spec/mongoid/association/referenced/belongs_to_spec.rb +2 -2
  166. data/spec/mongoid/association/referenced/has_and_belongs_to_many/proxy_spec.rb +67 -4
  167. data/spec/mongoid/association/referenced/has_and_belongs_to_many_models.rb +25 -0
  168. data/spec/mongoid/association/referenced/has_and_belongs_to_many_spec.rb +35 -2
  169. data/spec/mongoid/association/referenced/has_many/buildable_spec.rb +109 -0
  170. data/spec/mongoid/association/referenced/has_many/enumerable_spec.rb +8 -8
  171. data/spec/mongoid/association/referenced/has_many/proxy_spec.rb +82 -13
  172. data/spec/mongoid/association/referenced/has_many_models.rb +3 -1
  173. data/spec/mongoid/association/referenced/has_many_spec.rb +25 -0
  174. data/spec/mongoid/association/referenced/has_one/buildable_spec.rb +2 -2
  175. data/spec/mongoid/association/referenced/has_one/proxy_spec.rb +107 -1
  176. data/spec/mongoid/association/referenced/has_one_models.rb +16 -0
  177. data/spec/mongoid/association/syncable_spec.rb +14 -0
  178. data/spec/mongoid/atomic/paths_spec.rb +0 -14
  179. data/spec/mongoid/atomic_spec.rb +22 -0
  180. data/spec/mongoid/attributes/nested_spec.rb +80 -11
  181. data/spec/mongoid/attributes/nested_spec_models.rb +48 -0
  182. data/spec/mongoid/attributes/projector_spec.rb +1 -5
  183. data/spec/mongoid/attributes_spec.rb +524 -27
  184. data/spec/mongoid/changeable_spec.rb +130 -13
  185. data/spec/mongoid/clients/factory_spec.rb +34 -42
  186. data/spec/mongoid/clients/options_spec.rb +1 -0
  187. data/spec/mongoid/clients/sessions_spec.rb +0 -38
  188. data/spec/mongoid/clients_spec.rb +32 -2
  189. data/spec/mongoid/config/environment_spec.rb +39 -1
  190. data/spec/mongoid/config_spec.rb +104 -13
  191. data/spec/mongoid/contextual/aggregable/memory_spec.rb +396 -158
  192. data/spec/mongoid/contextual/aggregable/memory_table.yml +88 -0
  193. data/spec/mongoid/contextual/aggregable/memory_table_spec.rb +62 -0
  194. data/spec/mongoid/contextual/map_reduce_spec.rb +2 -16
  195. data/spec/mongoid/contextual/memory_spec.rb +1337 -69
  196. data/spec/mongoid/contextual/mongo_spec.rb +1105 -172
  197. data/spec/mongoid/contextual/none_spec.rb +38 -0
  198. data/spec/mongoid/copyable_spec.rb +451 -1
  199. data/spec/mongoid/criteria/findable_spec.rb +86 -210
  200. data/spec/mongoid/criteria/includable_spec.rb +1492 -0
  201. data/spec/mongoid/criteria/includable_spec_models.rb +54 -0
  202. data/spec/mongoid/criteria/marshalable_spec.rb +18 -1
  203. data/spec/mongoid/criteria/queryable/extensions/array_spec.rb +7 -19
  204. data/spec/mongoid/criteria/queryable/extensions/big_decimal_spec.rb +134 -26
  205. data/spec/mongoid/criteria/queryable/extensions/date_spec.rb +11 -0
  206. data/spec/mongoid/criteria/queryable/extensions/date_time_spec.rb +11 -0
  207. data/spec/mongoid/criteria/queryable/extensions/hash_spec.rb +0 -15
  208. data/spec/mongoid/criteria/queryable/extensions/numeric_spec.rb +73 -7
  209. data/spec/mongoid/criteria/queryable/extensions/time_spec.rb +11 -0
  210. data/spec/mongoid/criteria/queryable/extensions/time_with_zone_spec.rb +11 -0
  211. data/spec/mongoid/criteria/queryable/optional_spec.rb +0 -484
  212. data/spec/mongoid/criteria/queryable/selectable_logical_spec.rb +50 -0
  213. data/spec/mongoid/criteria/queryable/selectable_spec.rb +289 -124
  214. data/spec/mongoid/criteria/queryable/selector_spec.rb +14 -2
  215. data/spec/mongoid/criteria_spec.rb +474 -1198
  216. data/spec/mongoid/document_fields_spec.rb +173 -24
  217. data/spec/mongoid/document_spec.rb +32 -41
  218. data/spec/mongoid/errors/document_not_found_spec.rb +76 -0
  219. data/spec/mongoid/errors/invalid_field_spec.rb +1 -1
  220. data/spec/mongoid/errors/invalid_field_type_spec.rb +55 -0
  221. data/spec/mongoid/errors/mongoid_error_spec.rb +3 -1
  222. data/spec/mongoid/errors/no_environment_spec.rb +3 -3
  223. data/spec/mongoid/errors/too_many_nested_attribute_records_spec.rb +1 -1
  224. data/spec/mongoid/extensions/array_spec.rb +16 -2
  225. data/spec/mongoid/extensions/big_decimal_spec.rb +697 -212
  226. data/spec/mongoid/extensions/binary_spec.rb +44 -9
  227. data/spec/mongoid/extensions/boolean_spec.rb +68 -82
  228. data/spec/mongoid/extensions/date_class_mongoize_spec.rb +7 -3
  229. data/spec/mongoid/extensions/date_spec.rb +71 -1
  230. data/spec/mongoid/extensions/date_time_spec.rb +15 -9
  231. data/spec/mongoid/extensions/float_spec.rb +48 -76
  232. data/spec/mongoid/extensions/hash_spec.rb +30 -0
  233. data/spec/mongoid/extensions/integer_spec.rb +45 -66
  234. data/spec/mongoid/extensions/range_spec.rb +255 -54
  235. data/spec/mongoid/extensions/regexp_spec.rb +58 -33
  236. data/spec/mongoid/extensions/set_spec.rb +106 -0
  237. data/spec/mongoid/extensions/string_spec.rb +53 -25
  238. data/spec/mongoid/extensions/symbol_spec.rb +18 -25
  239. data/spec/mongoid/extensions/time_spec.rb +634 -66
  240. data/spec/mongoid/extensions/time_with_zone_spec.rb +17 -31
  241. data/spec/mongoid/factory_spec.rb +61 -1
  242. data/spec/mongoid/fields_spec.rb +321 -50
  243. data/spec/mongoid/findable_spec.rb +80 -15
  244. data/spec/mongoid/indexable/specification_spec.rb +2 -2
  245. data/spec/mongoid/indexable_spec.rb +16 -19
  246. data/spec/mongoid/interceptable_spec.rb +584 -5
  247. data/spec/mongoid/interceptable_spec_models.rb +235 -4
  248. data/spec/mongoid/matcher/extract_attribute_spec.rb +1 -5
  249. data/spec/mongoid/mongoizable_spec.rb +285 -0
  250. data/spec/mongoid/persistable/creatable_spec.rb +2 -2
  251. data/spec/mongoid/persistable/deletable_spec.rb +2 -2
  252. data/spec/mongoid/persistable/destroyable_spec.rb +2 -2
  253. data/spec/mongoid/persistable/upsertable_spec.rb +14 -0
  254. data/spec/mongoid/persistence_context_spec.rb +50 -1
  255. data/spec/mongoid/query_cache_middleware_spec.rb +0 -18
  256. data/spec/mongoid/query_cache_spec.rb +0 -154
  257. data/spec/mongoid/reloadable_spec.rb +35 -2
  258. data/spec/mongoid/scopable_spec.rb +21 -1
  259. data/spec/mongoid/shardable_spec.rb +14 -0
  260. data/spec/mongoid/stateful_spec.rb +28 -0
  261. data/spec/mongoid/timestamps_spec.rb +390 -0
  262. data/spec/mongoid/timestamps_spec_models.rb +67 -0
  263. data/spec/mongoid/touchable_spec.rb +116 -0
  264. data/spec/mongoid/touchable_spec_models.rb +12 -8
  265. data/spec/mongoid/traversable_spec.rb +4 -11
  266. data/spec/mongoid/validatable/presence_spec.rb +1 -1
  267. data/spec/mongoid/validatable/uniqueness_spec.rb +60 -31
  268. data/spec/mongoid/warnings_spec.rb +35 -0
  269. data/spec/rails/controller_extension/controller_runtime_spec.rb +2 -2
  270. data/spec/rails/mongoid_spec.rb +4 -16
  271. data/spec/shared/lib/mrss/constraints.rb +8 -16
  272. data/spec/shared/lib/mrss/docker_runner.rb +23 -3
  273. data/spec/shared/lib/mrss/eg_config_utils.rb +51 -0
  274. data/spec/shared/lib/mrss/lite_constraints.rb +32 -1
  275. data/spec/shared/share/Dockerfile.erb +34 -48
  276. data/spec/shared/shlib/config.sh +27 -0
  277. data/spec/shared/shlib/server.sh +32 -19
  278. data/spec/shared/shlib/set_env.sh +37 -0
  279. data/spec/support/constraints.rb +24 -0
  280. data/spec/support/macros.rb +39 -0
  281. data/spec/support/models/augmentation.rb +12 -0
  282. data/spec/support/models/band.rb +3 -0
  283. data/spec/support/models/catalog.rb +24 -0
  284. data/spec/support/models/circus.rb +3 -0
  285. data/spec/support/models/code.rb +2 -0
  286. data/spec/support/models/fanatic.rb +8 -0
  287. data/spec/support/models/implant.rb +9 -0
  288. data/spec/support/models/label.rb +2 -0
  289. data/spec/support/models/membership.rb +1 -0
  290. data/spec/support/models/passport.rb +9 -0
  291. data/spec/support/models/person.rb +1 -0
  292. data/spec/support/models/player.rb +2 -0
  293. data/spec/support/models/powerup.rb +12 -0
  294. data/spec/support/models/registry.rb +1 -0
  295. data/spec/support/models/school.rb +14 -0
  296. data/spec/support/models/shield.rb +18 -0
  297. data/spec/support/models/student.rb +14 -0
  298. data/spec/support/models/weapon.rb +12 -0
  299. data/spec/support/schema_maps/schema_map_aws.json +17 -0
  300. data/spec/support/schema_maps/schema_map_aws_key_alt_names.json +12 -0
  301. data/spec/support/schema_maps/schema_map_azure.json +17 -0
  302. data/spec/support/schema_maps/schema_map_azure_key_alt_names.json +12 -0
  303. data/spec/support/schema_maps/schema_map_gcp.json +17 -0
  304. data/spec/support/schema_maps/schema_map_gcp_key_alt_names.json +12 -0
  305. data/spec/support/schema_maps/schema_map_kmip.json +17 -0
  306. data/spec/support/schema_maps/schema_map_kmip_key_alt_names.json +12 -0
  307. data/spec/support/schema_maps/schema_map_local.json +18 -0
  308. data/spec/support/schema_maps/schema_map_local_key_alt_names.json +12 -0
  309. data/spec/support/spec_config.rb +4 -0
  310. data.tar.gz.sig +0 -0
  311. metadata +76 -13
  312. metadata.gz.sig +0 -0
  313. data/lib/mongoid/errors/eager_load.rb +0 -23
  314. data/lib/mongoid/errors/invalid_value.rb +0 -17
  315. data/spec/mongoid/errors/eager_load_spec.rb +0 -31
@@ -242,7 +242,7 @@ module Mongoid
242
242
  #
243
243
  # @return [ String ] The foreign key check.
244
244
  def foreign_key_check
245
- @foreign_key_check ||= "#{foreign_key}_changed?" if (stores_foreign_key? && foreign_key)
245
+ @foreign_key_check ||= "#{foreign_key}_previously_changed?" if (stores_foreign_key? && foreign_key)
246
246
  end
247
247
 
248
248
  # Create an association proxy object using the owner and target.
@@ -299,6 +299,35 @@ module Mongoid
299
299
  end
300
300
  end
301
301
 
302
+ # @return [ Array<String> ] The associations above this one in the inclusion tree.
303
+ attr_accessor :parent_inclusions
304
+
305
+ def parent_inclusions
306
+ @parent_inclusions ||= []
307
+ end
308
+
309
+ # Is this association an embeds_many or has_many association?
310
+ #
311
+ # @return [ true | false ] true if it is a *_many association, false if not.
312
+ def many?
313
+ [Referenced::HasMany, Embedded::EmbedsMany].any? { |a| self.is_a?(a) }
314
+ end
315
+
316
+ # Is this association an embeds_one or has_one association?
317
+ #
318
+ # @return [ true | false ] true if it is a *_one association, false if not.
319
+ def one?
320
+ [Referenced::HasOne, Embedded::EmbedsOne].any? { |a| self.is_a?(a) }
321
+ end
322
+
323
+ # Is this association an embedded_in or belongs_to association?
324
+ #
325
+ # @return [ true | false ] true if it is an embedded_in or belongs_to
326
+ # association, false if not.
327
+ def in_to?
328
+ [Referenced::BelongsTo, Embedded::EmbeddedIn].any? { |a| self.is_a?(a) }
329
+ end
330
+
302
331
  private
303
332
 
304
333
  # Gets the model classes with inverse associations of this model. This is used to determine
@@ -404,10 +433,15 @@ module Mongoid
404
433
  def namespace_hierarchy(mod)
405
434
  parent = Object
406
435
  hier = [parent]
407
- mod.name.split('::').each do |part|
408
- parent = parent.const_get(part)
409
- hier << parent
436
+
437
+ # name is not present on anonymous modules
438
+ if mod.name
439
+ mod.name.split('::').each do |part|
440
+ parent = parent.const_get(part)
441
+ hier << parent
442
+ end
410
443
  end
444
+
411
445
  hier.reverse
412
446
  end
413
447
 
@@ -34,6 +34,25 @@ module Mongoid
34
34
  locator = document.new_record? ? "" : ".#{document._index}"
35
35
  "#{pos}#{"." unless pos.blank?}#{document._association.store_as}#{locator}"
36
36
  end
37
+
38
+ class << self
39
+
40
+ # Get the position of where the document would go for the given
41
+ # association. The use case for this function is when trying to
42
+ # persist an empty list for an embedded association. All of the
43
+ # existing functions for getting the position to store a document
44
+ # require passing in a document to store, which we don't have when
45
+ # trying to store the empty list.
46
+ #
47
+ # @param [ Document ] parent The parent document to store in.
48
+ # @param [ Association ] association The association.
49
+ #
50
+ # @return [ String ] The position string.
51
+ def position_without_document(parent, association)
52
+ pos = parent.atomic_position
53
+ "#{pos}#{"." unless pos.blank?}#{association.store_as}"
54
+ end
55
+ end
37
56
  end
38
57
  end
39
58
  end
@@ -43,11 +43,18 @@ module Mongoid
43
43
  # @return [ true, false ] True if pending, false if not.
44
44
  def pending_attribute?(key, value)
45
45
  name = key.to_s
46
- if relations.has_key?(name)
46
+
47
+ aliased = if aliased_associations.key?(name)
48
+ aliased_associations[name]
49
+ else
50
+ name
51
+ end
52
+
53
+ if relations.has_key?(aliased)
47
54
  pending_relations[name] = value
48
55
  return true
49
56
  end
50
- if nested_attributes.has_key?(name)
57
+ if nested_attributes.has_key?(aliased)
51
58
  pending_nested[name] = value
52
59
  return true
53
60
  end
@@ -86,10 +86,26 @@ module Mongoid
86
86
  def read_attribute(name)
87
87
  field = fields[name.to_s]
88
88
  raw = read_raw_attribute(name)
89
- field ? field.demongoize(raw) : raw
89
+ process_raw_attribute(name.to_s, raw, field)
90
90
  end
91
91
  alias :[] :read_attribute
92
92
 
93
+
94
+ # Process the raw attribute values just read from the documents attributes.
95
+ #
96
+ # @param [ String ] name The name of the attribute to get.
97
+ # @param [ Object ] raw The raw attribute value.
98
+ # @param [ Field | nil ] field The field to use for demongoization or nil.
99
+ #
100
+ # @return [ Object ] The value of the attribute.
101
+ #
102
+ # @api private
103
+ def process_raw_attribute(name, raw, field)
104
+ value = field ? field.demongoize(raw) : raw
105
+ attribute_will_change!(name) if value.resizable?
106
+ value
107
+ end
108
+
93
109
  # Read a value from the attributes before type cast. If the value has not
94
110
  # yet been assigned then this will return the attribute's existing value
95
111
  # using read_raw_attribute.
@@ -121,6 +137,7 @@ module Mongoid
121
137
  # @raise [ Errors::ReadonlyAttribute ] If the field cannot be removed due
122
138
  # to being flagged as reaodnly.
123
139
  def remove_attribute(name)
140
+ validate_writable_field_name!(name.to_s)
124
141
  as_writable_attribute!(name) do |access|
125
142
  _assigning do
126
143
  attribute_will_change!(access)
@@ -143,6 +160,8 @@ module Mongoid
143
160
  # @param [ String, Symbol ] name The name of the attribute to update.
144
161
  # @param [ Object ] value The value to set for the attribute.
145
162
  def write_attribute(name, value)
163
+ validate_writable_field_name!(name.to_s)
164
+
146
165
  field_name = database_field_name(name)
147
166
 
148
167
  if attribute_missing?(field_name)
@@ -151,7 +170,6 @@ module Mongoid
151
170
 
152
171
  if attribute_writable?(field_name)
153
172
  _assigning do
154
- validate_attribute_value(field_name, value)
155
173
  localized = fields[field_name].try(:localized?)
156
174
  attributes_before_type_cast[name.to_s] = value
157
175
  typed_value = typed_value_for(field_name, value)
@@ -164,6 +182,11 @@ module Mongoid
164
182
  else
165
183
  attributes[field_name] = typed_value
166
184
  end
185
+
186
+ # when writing an attribute, also remove it from the unsets,
187
+ # so that removing then writing doesn't result in a removal.
188
+ delayed_atomic_unsets.delete(field_name)
189
+
167
190
  typed_value
168
191
  end
169
192
  else
@@ -266,7 +289,11 @@ module Mongoid
266
289
  end
267
290
 
268
291
  if hash_dot_syntax?(normalized)
269
- attributes.__nested__(normalized)
292
+ if fields.key?(normalized)
293
+ attributes[normalized]
294
+ else
295
+ attributes.__nested__(normalized)
296
+ end
270
297
  else
271
298
  attributes[normalized]
272
299
  end
@@ -325,30 +352,6 @@ module Mongoid
325
352
 
326
353
  private
327
354
 
328
- # Validates an attribute value as being assignable to the specified field.
329
- #
330
- # For now, only Hash and Array fields are validated, and the value is
331
- # being checked to be of an appropriate type (i.e. either Hash or Array,
332
- # respectively, or nil).
333
- #
334
- # This method takes the name of the field as stored in the document
335
- # in the database, not (necessarily) the Ruby method name used to read/write
336
- # the said field.
337
- #
338
- # @param [ String, Symbol ] field_name The name of the field.
339
- # @param [ Object ] value The value to be validated.
340
- def validate_attribute_value(field_name, value)
341
- return if value.nil?
342
- field = fields[field_name]
343
- return unless field
344
- validatable_types = [ Hash, Array ]
345
- if validatable_types.include?(field.type)
346
- unless value.is_a?(field.type)
347
- raise Mongoid::Errors::InvalidValue.new(field.type, value.class)
348
- end
349
- end
350
- end
351
-
352
355
  def lookup_attribute_presence(name, value)
353
356
  if localized_fields.has_key?(name) && value
354
357
  value = localized_fields[name].send(:lookup, value)
@@ -62,13 +62,14 @@ module Mongoid
62
62
 
63
63
  # Call this method after save, so the changes can be properly switched.
64
64
  #
65
- # This will unset the memoized children array, set new record to
65
+ # This will unset the memoized children array, set new record flag to
66
66
  # false, set the document as validated, and move the dirty changes.
67
67
  #
68
68
  # @example Move the changes to previous.
69
69
  # person.move_changes
70
70
  def move_changes
71
71
  @previous_changes = changes
72
+ @previous_attributes = attributes.dup
72
73
  Atomic::UPDATES.each do |update|
73
74
  send(update).clear
74
75
  end
@@ -81,6 +82,7 @@ module Mongoid
81
82
  # document.post_persist
82
83
  def post_persist
83
84
  reset_persisted_descendants
85
+ reset_attributes_before_type_cast
84
86
  move_changes
85
87
  end
86
88
 
@@ -133,6 +135,13 @@ module Mongoid
133
135
 
134
136
  private
135
137
 
138
+ # Get attributes of the document before the document was saved.
139
+ #
140
+ # @return [ Hash ] Previous attributes
141
+ def previous_attributes
142
+ @previous_attributes ||= {}
143
+ end
144
+
136
145
  # Get the old and new value for the provided attribute.
137
146
  #
138
147
  # @example Get the attribute change.
@@ -185,6 +194,25 @@ module Mongoid
185
194
  attribute_changed?(attr) ? changed_attributes[attr] : attributes[attr]
186
195
  end
187
196
 
197
+ # Get the previous attribute value that was changed
198
+ # before the document was saved.
199
+ #
200
+ # It the document has not been saved yet, or was just loaded from database,
201
+ # this method returns nil for all attributes.
202
+ #
203
+ # @param [ String ] attr The attribute name.
204
+ #
205
+ # @return [ Object | nil ] Attribute value before the document was saved,
206
+ # or nil if the document has not been saved yet.
207
+ def attribute_previously_was(attr)
208
+ attr = database_field_name(attr)
209
+ if previous_changes.key?(attr)
210
+ previous_changes[attr].first
211
+ else
212
+ previous_attributes[attr]
213
+ end
214
+ end
215
+
188
216
  # Flag an attribute as going to change.
189
217
  #
190
218
  # @example Flag the attribute.
@@ -221,6 +249,10 @@ module Mongoid
221
249
  end
222
250
  end
223
251
 
252
+ def reset_attributes_before_type_cast
253
+ @attributes_before_type_cast = @attributes.dup
254
+ end
255
+
224
256
  module ClassMethods
225
257
 
226
258
  private
@@ -291,7 +323,7 @@ module Mongoid
291
323
  end
292
324
  end
293
325
 
294
- # Creates the dirty change previous value accessor.
326
+ # Creates the dirty change previous value accessors.
295
327
  #
296
328
  # @example Create the accessor.
297
329
  # Model.create_dirty_previous_value_accessor("name", "alias")
@@ -303,6 +335,9 @@ module Mongoid
303
335
  re_define_method("#{meth}_was") do
304
336
  attribute_was(name)
305
337
  end
338
+ re_define_method("#{meth}_previously_was") do
339
+ attribute_previously_was(name)
340
+ end
306
341
  end
307
342
  end
308
343
 
@@ -45,6 +45,10 @@ module Mongoid
45
45
  PersistenceContext.new(self.class)
46
46
  end
47
47
 
48
+ def persistence_context?
49
+ !!(PersistenceContext.get(self) || PersistenceContext.get(self.class))
50
+ end
51
+
48
52
  private
49
53
 
50
54
  def set_persistence_context(options_or_context)
@@ -43,13 +43,7 @@ module Mongoid
43
43
  Threaded.set_session(session)
44
44
  yield(session)
45
45
  rescue Mongo::Error::InvalidSession => ex
46
- if
47
- # Driver 2.13.0+
48
- defined?(Mongo::Error::SessionsNotSupported) &&
49
- Mongo::Error::SessionsNotSupported === ex ||
50
- # Legacy drivers
51
- ex.message == Mongo::Session::SESSIONS_NOT_SUPPORTED
52
- then
46
+ if Mongo::Error::SessionsNotSupported === ex
53
47
  raise Mongoid::Errors::InvalidSessionUse.new(:sessions_not_supported)
54
48
  end
55
49
  raise Mongoid::Errors::InvalidSessionUse.new(:invalid_session_use)
@@ -100,13 +94,7 @@ module Mongoid
100
94
  Threaded.set_session(session)
101
95
  yield(session)
102
96
  rescue Mongo::Error::InvalidSession => ex
103
- if
104
- # Driver 2.13.0+
105
- defined?(Mongo::Error::SessionsNotSupported) &&
106
- Mongo::Error::SessionsNotSupported === ex ||
107
- # Legacy drivers
108
- ex.message == Mongo::Session::SESSIONS_NOT_SUPPORTED
109
- then
97
+ if Mongo::Error::SessionsNotSupported === ex
110
98
  raise Mongoid::Errors::InvalidSessionUse.new(:sessions_not_supported)
111
99
  end
112
100
  raise Mongoid::Errors::InvalidSessionUse.new(:invalid_session_use)
@@ -44,21 +44,37 @@ module Mongoid
44
44
  # override the current Mongoid environment.
45
45
  #
46
46
  # @return [ Hash ] The settings.
47
+ #
47
48
  # @api private
48
49
  def load_yaml(path, environment = nil)
49
50
  env = environment ? environment.to_s : env_name
50
- contents = File.new(path).read
51
+
52
+ contents = File.read(path)
51
53
  if contents.empty?
52
54
  raise Mongoid::Errors::EmptyConfigFile.new(path)
53
55
  end
54
- data = if RUBY_VERSION.start_with?("2.5")
55
- YAML.safe_load(ERB.new(contents).result, [Symbol], [], true)
56
+
57
+ # These are the classes that can be used in a Mongoid
58
+ # configuration file in addition to standard YAML types.
59
+ permitted_classes = [
60
+ # Symbols occur as values for read preference, for example.
61
+ Symbol,
62
+ # BSON::Binary occur as keyId values for FLE (more precisely,
63
+ # the keyIds are UUIDs).
64
+ BSON::Binary,
65
+ ]
66
+
67
+ result = ERB.new(contents).result
68
+ data = if RUBY_VERSION < '2.6'
69
+ YAML.safe_load(result, permitted_classes, [], true)
56
70
  else
57
- YAML.safe_load(ERB.new(contents).result, permitted_classes: [Symbol], aliases: true)
71
+ YAML.safe_load(result, permitted_classes: permitted_classes, aliases: true)
58
72
  end
73
+
59
74
  unless data.is_a?(Hash)
60
75
  raise Mongoid::Errors::InvalidConfigFile.new(path)
61
76
  end
77
+
62
78
  data[env]
63
79
  end
64
80
  end
@@ -23,7 +23,8 @@ module Mongoid
23
23
  # database name is not explicitly defined.
24
24
  option :app_name, default: nil
25
25
 
26
- # Create indexes in background by default.
26
+ # (Deprecated) In MongoDB 4.0 and earlier, set whether to create
27
+ # indexes in the background by default. (default: false)
27
28
  option :background_indexing, default: false
28
29
 
29
30
  # Mark belongs_to associations as required by default, so that saving a
@@ -74,42 +75,55 @@ module Mongoid
74
75
  # Return stored times as UTC.
75
76
  option :use_utc, default: false
76
77
 
78
+ # Store BigDecimals as Decimal128s instead of strings in the db.
79
+ option :map_big_decimal_to_decimal128, default: true
80
+
77
81
  # Update embedded documents correctly when setting it, unsetting it
78
82
  # and resetting it. See MONGOID-5206 and MONGOID-5240 for more details.
79
- option :broken_updates, default: true
83
+ option :broken_updates, default: false
80
84
 
81
85
  # Maintain legacy behavior of === on Mongoid documents, which returns
82
86
  # true in a number of cases where Ruby's === implementation would
83
87
  # return false.
84
- option :legacy_triple_equals, default: true
88
+ option :legacy_triple_equals, default: false
85
89
 
86
90
  # When exiting a nested `with_scope' block, set the current scope to
87
91
  # nil instead of the parent scope for backwards compatibility.
88
- option :broken_scoping, default: true
92
+ option :broken_scoping, default: false
89
93
 
90
94
  # Maintain broken behavior of sum over empty result sets for backwards
91
95
  # compatibility.
92
- option :broken_aggregables, default: true
96
+ option :broken_aggregables, default: false
93
97
 
94
98
  # Ignore aliased fields in embedded documents when performing pluck and
95
99
  # distinct operations, for backwards compatibility.
96
- option :broken_alias_handling, default: true
100
+ option :broken_alias_handling, default: false
97
101
 
98
102
  # Maintain broken `and' behavior when using the same operator on the same
99
103
  # field multiple times for backwards compatibility.
100
- option :broken_and, default: true
104
+ option :broken_and, default: false
101
105
 
102
106
  # Use millisecond precision when comparing Time objects with the _matches?
103
107
  # function.
104
- option :compare_time_by_ms, default: false
108
+ option :compare_time_by_ms, default: true
105
109
 
106
110
  # Use bson-ruby's implementation of as_json for BSON::ObjectId instead of
107
111
  # the one monkey-patched into Mongoid.
108
- option :object_id_as_json_oid, default: true
112
+ option :object_id_as_json_oid, default: false
109
113
 
110
114
  # Maintain legacy behavior of pluck and distinct, which does not
111
115
  # demongoize the values on returning them.
112
- option :legacy_pluck_distinct, default: true
116
+ option :legacy_pluck_distinct, default: false
117
+
118
+ # Combine chained operators, which use the same field and operator,
119
+ # using and's instead of overwriting them.
120
+ option :overwrite_chained_operators, default: false
121
+
122
+ # When this flag is true, the attributes method on a document will return
123
+ # a BSON::Document when that document is retrieved from the database, and
124
+ # a Hash otherwise. When this flag is false, the attributes method will
125
+ # always return a Hash.
126
+ option :legacy_attributes, default: false
113
127
 
114
128
  # Has Mongoid been configured? This is checking that at least a valid
115
129
  # client config exists.
@@ -202,6 +216,7 @@ module Mongoid
202
216
  configuration = settings.with_indifferent_access
203
217
  self.options = configuration[:options]
204
218
  self.clients = configuration[:clients]
219
+ Mongo.options = configuration[:driver_options] || {}
205
220
  set_log_levels
206
221
  end
207
222
 
@@ -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
@@ -26,7 +26,7 @@ module Mongoid
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 }
@@ -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