mongoid 7.6.1 → 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 (314) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +2 -0
  3. data/README.md +3 -3
  4. data/Rakefile +21 -85
  5. data/lib/config/locales/en.yml +46 -30
  6. data/lib/mongoid/association/accessors.rb +32 -3
  7. data/lib/mongoid/association/bindable.rb +48 -0
  8. data/lib/mongoid/association/builders.rb +4 -2
  9. data/lib/mongoid/association/eager_loadable.rb +29 -7
  10. data/lib/mongoid/association/embedded/batchable.rb +28 -5
  11. data/lib/mongoid/association/embedded/embedded_in/binding.rb +24 -2
  12. data/lib/mongoid/association/embedded/embedded_in.rb +2 -1
  13. data/lib/mongoid/association/embedded/embeds_many/binding.rb +1 -0
  14. data/lib/mongoid/association/embedded/embeds_many/buildable.rb +1 -1
  15. data/lib/mongoid/association/embedded/embeds_many/proxy.rb +40 -18
  16. data/lib/mongoid/association/embedded/embeds_one/buildable.rb +18 -4
  17. data/lib/mongoid/association/embedded/embeds_one/proxy.rb +21 -2
  18. data/lib/mongoid/association/macros.rb +2 -1
  19. data/lib/mongoid/association/many.rb +5 -0
  20. data/lib/mongoid/association/nested/many.rb +2 -1
  21. data/lib/mongoid/association/proxy.rb +12 -0
  22. data/lib/mongoid/association/referenced/auto_save.rb +3 -2
  23. data/lib/mongoid/association/referenced/belongs_to/binding.rb +1 -0
  24. data/lib/mongoid/association/referenced/belongs_to/buildable.rb +1 -1
  25. data/lib/mongoid/association/referenced/belongs_to.rb +1 -1
  26. data/lib/mongoid/association/referenced/counter_cache.rb +8 -8
  27. data/lib/mongoid/association/referenced/has_and_belongs_to_many/proxy.rb +64 -11
  28. data/lib/mongoid/association/referenced/has_and_belongs_to_many.rb +4 -1
  29. data/lib/mongoid/association/referenced/has_many/enumerable.rb +10 -18
  30. data/lib/mongoid/association/referenced/has_many/proxy.rb +12 -9
  31. data/lib/mongoid/association/referenced/has_one/buildable.rb +1 -1
  32. data/lib/mongoid/association/referenced/has_one/proxy.rb +8 -11
  33. data/lib/mongoid/association/referenced/syncable.rb +2 -2
  34. data/lib/mongoid/association/relatable.rb +38 -4
  35. data/lib/mongoid/attributes/processing.rb +9 -2
  36. data/lib/mongoid/attributes.rb +30 -27
  37. data/lib/mongoid/cacheable.rb +2 -2
  38. data/lib/mongoid/changeable.rb +37 -2
  39. data/lib/mongoid/clients/factory.rb +0 -4
  40. data/lib/mongoid/clients/options.rb +4 -0
  41. data/lib/mongoid/clients/sessions.rb +2 -14
  42. data/lib/mongoid/config.rb +15 -11
  43. data/lib/mongoid/contextual/aggregable/memory.rb +23 -15
  44. data/lib/mongoid/contextual/aggregable/mongo.rb +1 -1
  45. data/lib/mongoid/contextual/map_reduce.rb +2 -2
  46. data/lib/mongoid/contextual/memory.rb +55 -28
  47. data/lib/mongoid/contextual/mongo.rb +173 -287
  48. data/lib/mongoid/contextual/none.rb +33 -15
  49. data/lib/mongoid/copyable.rb +32 -8
  50. data/lib/mongoid/criteria/includable.rb +24 -20
  51. data/lib/mongoid/criteria/marshalable.rb +10 -2
  52. data/lib/mongoid/criteria/queryable/extensions/array.rb +2 -15
  53. data/lib/mongoid/criteria/queryable/extensions/big_decimal.rb +25 -4
  54. data/lib/mongoid/criteria/queryable/extensions/boolean.rb +1 -1
  55. data/lib/mongoid/criteria/queryable/extensions/date.rb +6 -1
  56. data/lib/mongoid/criteria/queryable/extensions/date_time.rb +6 -1
  57. data/lib/mongoid/criteria/queryable/extensions/hash.rb +0 -16
  58. data/lib/mongoid/criteria/queryable/extensions/numeric.rb +1 -1
  59. data/lib/mongoid/criteria/queryable/extensions/object.rb +2 -1
  60. data/lib/mongoid/criteria/queryable/extensions/range.rb +13 -5
  61. data/lib/mongoid/criteria/queryable/extensions/regexp.rb +1 -1
  62. data/lib/mongoid/criteria/queryable/extensions/symbol.rb +3 -1
  63. data/lib/mongoid/criteria/queryable/extensions/time.rb +6 -1
  64. data/lib/mongoid/criteria/queryable/extensions/time_with_zone.rb +6 -1
  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 +2 -24
  68. data/lib/mongoid/criteria/queryable/selector.rb +90 -5
  69. data/lib/mongoid/criteria/queryable/smash.rb +39 -6
  70. data/lib/mongoid/criteria/queryable/storable.rb +1 -1
  71. data/lib/mongoid/criteria/queryable.rb +11 -6
  72. data/lib/mongoid/criteria.rb +1 -28
  73. data/lib/mongoid/deprecable.rb +36 -0
  74. data/lib/mongoid/deprecation.rb +25 -0
  75. data/lib/mongoid/document.rb +88 -33
  76. data/lib/mongoid/equality.rb +4 -4
  77. data/lib/mongoid/errors/document_not_found.rb +6 -2
  78. data/lib/mongoid/errors/invalid_dot_dollar_assignment.rb +23 -0
  79. data/lib/mongoid/errors/invalid_field.rb +5 -1
  80. data/lib/mongoid/errors/invalid_field_type.rb +26 -0
  81. data/lib/mongoid/errors/too_many_nested_attribute_records.rb +1 -1
  82. data/lib/mongoid/errors.rb +2 -2
  83. data/lib/mongoid/extensions/array.rb +8 -6
  84. data/lib/mongoid/extensions/big_decimal.rb +29 -10
  85. data/lib/mongoid/extensions/binary.rb +42 -0
  86. data/lib/mongoid/extensions/boolean.rb +8 -2
  87. data/lib/mongoid/extensions/date.rb +26 -20
  88. data/lib/mongoid/extensions/date_time.rb +1 -1
  89. data/lib/mongoid/extensions/float.rb +4 -5
  90. data/lib/mongoid/extensions/hash.rb +13 -32
  91. data/lib/mongoid/extensions/integer.rb +4 -5
  92. data/lib/mongoid/extensions/object.rb +2 -0
  93. data/lib/mongoid/extensions/range.rb +41 -10
  94. data/lib/mongoid/extensions/regexp.rb +11 -4
  95. data/lib/mongoid/extensions/set.rb +11 -4
  96. data/lib/mongoid/extensions/string.rb +2 -13
  97. data/lib/mongoid/extensions/symbol.rb +3 -14
  98. data/lib/mongoid/extensions/time.rb +27 -16
  99. data/lib/mongoid/extensions/time_with_zone.rb +1 -2
  100. data/lib/mongoid/extensions.rb +1 -0
  101. data/lib/mongoid/factory.rb +42 -7
  102. data/lib/mongoid/fields/foreign_key.rb +7 -0
  103. data/lib/mongoid/fields/validators/macro.rb +3 -9
  104. data/lib/mongoid/fields.rb +49 -7
  105. data/lib/mongoid/findable.rb +21 -16
  106. data/lib/mongoid/indexable/specification.rb +1 -1
  107. data/lib/mongoid/indexable/validators/options.rb +4 -1
  108. data/lib/mongoid/interceptable.rb +69 -9
  109. data/lib/mongoid/persistable/creatable.rb +14 -5
  110. data/lib/mongoid/persistable/updatable.rb +12 -5
  111. data/lib/mongoid/persistence_context.rb +8 -42
  112. data/lib/mongoid/query_cache.rb +6 -258
  113. data/lib/mongoid/railties/controller_runtime.rb +1 -1
  114. data/lib/mongoid/reloadable.rb +7 -3
  115. data/lib/mongoid/scopable.rb +9 -11
  116. data/lib/mongoid/selectable.rb +1 -2
  117. data/lib/mongoid/shardable.rb +11 -35
  118. data/lib/mongoid/stateful.rb +27 -1
  119. data/lib/mongoid/timestamps/created.rb +1 -1
  120. data/lib/mongoid/timestamps/updated.rb +1 -1
  121. data/lib/mongoid/touchable.rb +2 -3
  122. data/lib/mongoid/traversable.rb +1 -0
  123. data/lib/mongoid/validatable/uniqueness.rb +2 -1
  124. data/lib/mongoid/version.rb +1 -5
  125. data/lib/mongoid/warnings.rb +3 -4
  126. data/lib/mongoid.rb +1 -0
  127. data/spec/config/mongoid.yml +16 -0
  128. data/spec/integration/app_spec.rb +8 -12
  129. data/spec/integration/associations/belongs_to_spec.rb +18 -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/i18n_fallbacks_spec.rb +1 -15
  143. data/spec/integration/matcher_examples_spec.rb +20 -13
  144. data/spec/integration/matcher_operator_data/type_decimal.yml +3 -2
  145. data/spec/integration/matcher_operator_spec.rb +3 -5
  146. data/spec/integration/persistence/range_field_spec.rb +350 -0
  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 +198 -8
  155. data/spec/mongoid/association/embedded/embeds_many_models.rb +36 -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 +38 -5
  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 +2 -56
  171. data/spec/mongoid/association/referenced/has_many/proxy_spec.rb +62 -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/attributes/nested_spec.rb +80 -11
  180. data/spec/mongoid/attributes/nested_spec_models.rb +48 -0
  181. data/spec/mongoid/attributes/projector_spec.rb +1 -5
  182. data/spec/mongoid/attributes_spec.rb +480 -27
  183. data/spec/mongoid/cacheable_spec.rb +3 -3
  184. data/spec/mongoid/changeable_spec.rb +130 -13
  185. data/spec/mongoid/clients/factory_spec.rb +22 -60
  186. data/spec/mongoid/clients/sessions_spec.rb +0 -38
  187. data/spec/mongoid/clients_spec.rb +2 -2
  188. data/spec/mongoid/config_spec.rb +52 -15
  189. data/spec/mongoid/contextual/aggregable/memory_spec.rb +396 -158
  190. data/spec/mongoid/contextual/aggregable/memory_table.yml +88 -0
  191. data/spec/mongoid/contextual/aggregable/memory_table_spec.rb +62 -0
  192. data/spec/mongoid/contextual/map_reduce_spec.rb +2 -16
  193. data/spec/mongoid/contextual/memory_spec.rb +521 -14
  194. data/spec/mongoid/contextual/mongo_spec.rb +566 -426
  195. data/spec/mongoid/contextual/none_spec.rb +11 -19
  196. data/spec/mongoid/copyable_spec.rb +451 -2
  197. data/spec/mongoid/criteria/findable_spec.rb +86 -210
  198. data/spec/mongoid/criteria/includable_spec.rb +1492 -0
  199. data/spec/mongoid/criteria/includable_spec_models.rb +54 -0
  200. data/spec/mongoid/criteria/marshalable_spec.rb +18 -1
  201. data/spec/mongoid/criteria/queryable/extensions/array_spec.rb +7 -19
  202. data/spec/mongoid/criteria/queryable/extensions/big_decimal_spec.rb +134 -26
  203. data/spec/mongoid/criteria/queryable/extensions/bignum_spec.rb +1 -2
  204. data/spec/mongoid/criteria/queryable/extensions/date_spec.rb +11 -0
  205. data/spec/mongoid/criteria/queryable/extensions/date_time_spec.rb +11 -0
  206. data/spec/mongoid/criteria/queryable/extensions/fixnum_spec.rb +1 -2
  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 +77 -85
  214. data/spec/mongoid/criteria/queryable/selector_spec.rb +16 -77
  215. data/spec/mongoid/criteria/queryable/storable_spec.rb +0 -72
  216. data/spec/mongoid/criteria_spec.rb +469 -1201
  217. data/spec/mongoid/document_fields_spec.rb +173 -24
  218. data/spec/mongoid/document_spec.rb +32 -41
  219. data/spec/mongoid/equality_spec.rb +12 -12
  220. data/spec/mongoid/errors/document_not_found_spec.rb +29 -2
  221. data/spec/mongoid/errors/invalid_field_spec.rb +1 -1
  222. data/spec/mongoid/errors/invalid_field_type_spec.rb +55 -0
  223. data/spec/mongoid/errors/mongoid_error_spec.rb +3 -1
  224. data/spec/mongoid/errors/no_environment_spec.rb +3 -3
  225. data/spec/mongoid/errors/too_many_nested_attribute_records_spec.rb +1 -1
  226. data/spec/mongoid/extensions/array_spec.rb +16 -2
  227. data/spec/mongoid/extensions/big_decimal_spec.rb +697 -212
  228. data/spec/mongoid/extensions/binary_spec.rb +44 -9
  229. data/spec/mongoid/extensions/boolean_spec.rb +68 -82
  230. data/spec/mongoid/extensions/date_class_mongoize_spec.rb +7 -3
  231. data/spec/mongoid/extensions/date_spec.rb +71 -1
  232. data/spec/mongoid/extensions/date_time_spec.rb +15 -9
  233. data/spec/mongoid/extensions/float_spec.rb +48 -76
  234. data/spec/mongoid/extensions/hash_spec.rb +30 -236
  235. data/spec/mongoid/extensions/integer_spec.rb +45 -66
  236. data/spec/mongoid/extensions/range_spec.rb +255 -54
  237. data/spec/mongoid/extensions/regexp_spec.rb +58 -33
  238. data/spec/mongoid/extensions/set_spec.rb +106 -0
  239. data/spec/mongoid/extensions/string_spec.rb +53 -25
  240. data/spec/mongoid/extensions/symbol_spec.rb +18 -25
  241. data/spec/mongoid/extensions/time_spec.rb +634 -66
  242. data/spec/mongoid/extensions/time_with_zone_spec.rb +17 -31
  243. data/spec/mongoid/factory_spec.rb +61 -1
  244. data/spec/mongoid/fields_spec.rb +321 -50
  245. data/spec/mongoid/findable_spec.rb +64 -29
  246. data/spec/mongoid/indexable/specification_spec.rb +2 -2
  247. data/spec/mongoid/indexable_spec.rb +16 -19
  248. data/spec/mongoid/interceptable_spec.rb +584 -5
  249. data/spec/mongoid/interceptable_spec_models.rb +235 -4
  250. data/spec/mongoid/matcher/extract_attribute_spec.rb +1 -5
  251. data/spec/mongoid/mongoizable_spec.rb +285 -0
  252. data/spec/mongoid/persistable/creatable_spec.rb +2 -2
  253. data/spec/mongoid/persistable/deletable_spec.rb +2 -2
  254. data/spec/mongoid/persistable/destroyable_spec.rb +2 -2
  255. data/spec/mongoid/persistable/upsertable_spec.rb +14 -0
  256. data/spec/mongoid/persistence_context_spec.rb +24 -0
  257. data/spec/mongoid/query_cache_middleware_spec.rb +0 -18
  258. data/spec/mongoid/query_cache_spec.rb +1 -156
  259. data/spec/mongoid/reloadable_spec.rb +35 -2
  260. data/spec/mongoid/scopable_spec.rb +36 -34
  261. data/spec/mongoid/serializable_spec.rb +14 -7
  262. data/spec/mongoid/shardable_models.rb +0 -14
  263. data/spec/mongoid/shardable_spec.rb +61 -153
  264. data/spec/mongoid/stateful_spec.rb +28 -0
  265. data/spec/mongoid/timestamps_spec.rb +390 -0
  266. data/spec/mongoid/timestamps_spec_models.rb +67 -0
  267. data/spec/mongoid/touchable_spec.rb +116 -0
  268. data/spec/mongoid/touchable_spec_models.rb +12 -8
  269. data/spec/mongoid/traversable_spec.rb +4 -11
  270. data/spec/mongoid/validatable/presence_spec.rb +1 -1
  271. data/spec/mongoid/validatable/uniqueness_spec.rb +60 -31
  272. data/spec/mongoid/warnings_spec.rb +35 -0
  273. data/spec/mongoid_spec.rb +1 -7
  274. data/spec/rails/controller_extension/controller_runtime_spec.rb +2 -2
  275. data/spec/rails/mongoid_spec.rb +4 -16
  276. data/spec/shared/lib/mrss/docker_runner.rb +1 -8
  277. data/spec/shared/lib/mrss/event_subscriber.rb +5 -15
  278. data/spec/shared/lib/mrss/lite_constraints.rb +2 -10
  279. data/spec/shared/lib/mrss/server_version_registry.rb +24 -17
  280. data/spec/shared/lib/mrss/spec_organizer.rb +3 -32
  281. data/spec/shared/lib/mrss/utils.rb +6 -28
  282. data/spec/shared/share/Dockerfile.erb +107 -33
  283. data/spec/shared/shlib/distro.sh +0 -10
  284. data/spec/shared/shlib/server.sh +33 -64
  285. data/spec/shared/shlib/set_env.sh +71 -12
  286. data/spec/support/constraints.rb +24 -0
  287. data/spec/support/expectations.rb +17 -20
  288. data/spec/support/macros.rb +30 -0
  289. data/spec/support/models/augmentation.rb +12 -0
  290. data/spec/support/models/band.rb +3 -0
  291. data/spec/support/models/catalog.rb +24 -0
  292. data/spec/support/models/circus.rb +3 -0
  293. data/spec/support/models/fanatic.rb +8 -0
  294. data/spec/support/models/implant.rb +9 -0
  295. data/spec/support/models/label.rb +2 -0
  296. data/spec/support/models/passport.rb +9 -0
  297. data/spec/support/models/person.rb +1 -0
  298. data/spec/support/models/player.rb +2 -0
  299. data/spec/support/models/powerup.rb +12 -0
  300. data/spec/support/models/registry.rb +1 -0
  301. data/spec/support/models/school.rb +14 -0
  302. data/spec/support/models/shield.rb +18 -0
  303. data/spec/support/models/student.rb +14 -0
  304. data/spec/support/models/weapon.rb +12 -0
  305. data.tar.gz.sig +0 -0
  306. metadata +695 -641
  307. metadata.gz.sig +0 -0
  308. data/lib/mongoid/errors/eager_load.rb +0 -23
  309. data/lib/mongoid/errors/invalid_value.rb +0 -17
  310. data/spec/mongoid/errors/eager_load_spec.rb +0 -31
  311. data/spec/shared/CANDIDATE.md +0 -28
  312. data/spec/shared/lib/mrss/release/candidate.rb +0 -281
  313. data/spec/shared/lib/mrss/release/product_data.rb +0 -144
  314. data/spec/shared/lib/tasks/candidate.rake +0 -64
@@ -14,19 +14,13 @@ module Mongoid
14
14
  self
15
15
  end
16
16
 
17
- # Constant for epoch - used when passing invalid times.
18
- #
19
- # @deprecated No longer used as a return value from #mongoize passed
20
- # an invalid time string.
21
- EPOCH = ::Time.utc(1970, 1, 1, 0, 0, 0)
22
-
23
17
  # Turn the object from the ruby type we deal with to a Mongo friendly
24
18
  # type.
25
19
  #
26
20
  # @example Mongoize the object.
27
21
  # time.mongoize
28
22
  #
29
- # @return [ Time ] The object mongoized.
23
+ # @return [ Time | nil ] The object mongoized or nil.
30
24
  def mongoize
31
25
  ::Time.mongoize(self)
32
26
  end
@@ -51,14 +45,28 @@ module Mongoid
51
45
  #
52
46
  # @param [ Time ] object The time from Mongo.
53
47
  #
54
- # @return [ Time ] The object as a date.
48
+ # @return [ Time | nil ] The object as a time.
55
49
  def demongoize(object)
56
- return nil if object.blank?
57
- object = object.getlocal unless Mongoid::Config.use_utc?
50
+ return if object.blank?
51
+ time = if object.acts_like?(:time)
52
+ Mongoid::Config.use_utc? ? object : object.getlocal
53
+ elsif object.acts_like?(:date)
54
+ ::Date.demongoize(object).to_time
55
+ elsif object.is_a?(String)
56
+ begin
57
+ object.__mongoize_time__
58
+ rescue ArgumentError
59
+ nil
60
+ end
61
+ end
62
+
63
+ return if time.nil?
64
+
58
65
  if Mongoid::Config.use_activesupport_time_zone?
59
- object = object.in_time_zone(Mongoid.time_zone)
66
+ time.in_time_zone(Mongoid.time_zone)
67
+ else
68
+ time
60
69
  end
61
- object
62
70
  end
63
71
 
64
72
  # Turn the object from the ruby type we deal with to a Mongo friendly
@@ -69,11 +77,16 @@ module Mongoid
69
77
  #
70
78
  # @param [ Object ] object The object to mongoize.
71
79
  #
72
- # @return [ Time ] The object mongoized.
80
+ # @return [ Time | nil ] The object mongoized or nil.
73
81
  def mongoize(object)
74
- return nil if object.blank?
82
+ return if object.blank?
75
83
  begin
76
84
  time = object.__mongoize_time__
85
+ rescue ArgumentError
86
+ return
87
+ end
88
+
89
+ if time.acts_like?(:time)
77
90
  if object.respond_to?(:sec_fraction)
78
91
  ::Time.at(time.to_i, object.sec_fraction * 10**6).utc
79
92
  elsif time.respond_to?(:subsec)
@@ -81,8 +94,6 @@ module Mongoid
81
94
  else
82
95
  ::Time.at(time.to_i, time.usec).utc
83
96
  end
84
- rescue ArgumentError
85
- nil
86
97
  end
87
98
  end
88
99
  end
@@ -49,8 +49,7 @@ module Mongoid
49
49
  #
50
50
  # @return [ TimeWithZone ] The object as a date.
51
51
  def demongoize(object)
52
- return nil if object.blank?
53
- ::Time.demongoize(object).in_time_zone
52
+ ::Time.demongoize(object).try(:in_time_zone)
54
53
  end
55
54
 
56
55
  # Turn the object from the ruby type we deal with to a Mongo friendly
@@ -34,6 +34,7 @@ end
34
34
 
35
35
  require "mongoid/extensions/array"
36
36
  require "mongoid/extensions/big_decimal"
37
+ require "mongoid/extensions/binary"
37
38
  require "mongoid/extensions/boolean"
38
39
  require "mongoid/extensions/date"
39
40
  require "mongoid/extensions/date_time"
@@ -6,9 +6,6 @@ module Mongoid
6
6
  module Factory
7
7
  extend self
8
8
 
9
- # @deprecated
10
- TYPE = "_type".freeze
11
-
12
9
  # Builds a new +Document+ from the supplied attributes.
13
10
  #
14
11
  # This method either instantiates klass or a descendant of klass if the attributes include
@@ -23,16 +20,32 @@ module Mongoid
23
20
  #
24
21
  # @param [ Class ] klass The class to instantiate from if _type is not present.
25
22
  # @param [ Hash ] attributes The document attributes.
23
+ # @param [ true | false ] execute_callbacks Flag specifies whether callbacks
24
+ # should be run.
26
25
  #
27
26
  # @return [ Document ] The instantiated document.
28
27
  def build(klass, attributes = nil)
28
+ execute_build(klass, attributes, execute_callbacks: true)
29
+ end
30
+
31
+ # Execute the build.
32
+ #
33
+ # @param [ Class ] klass The class to instantiate from if _type is not present.
34
+ # @param [ Hash ] attributes The document attributes.
35
+ # @param [ true | false ] execute_callbacks Flag specifies whether callbacks
36
+ # should be run.
37
+ #
38
+ # @return [ Document ] The instantiated document.
39
+ #
40
+ # @api private
41
+ def execute_build(klass, attributes = nil, execute_callbacks: true)
29
42
  attributes ||= {}
30
43
  dvalue = attributes[klass.discriminator_key] || attributes[klass.discriminator_key.to_sym]
31
44
  type = klass.get_discriminator_mapping(dvalue)
32
45
  if type
33
- type.new(attributes)
46
+ type.construct_document(attributes, execute_callbacks: execute_callbacks)
34
47
  else
35
- klass.new(attributes)
48
+ klass.construct_document(attributes, execute_callbacks: execute_callbacks)
36
49
  end
37
50
  end
38
51
 
@@ -63,12 +76,34 @@ module Mongoid
63
76
  #
64
77
  # @return [ Document ] The instantiated document.
65
78
  def from_db(klass, attributes = nil, criteria = nil, selected_fields = nil)
79
+ execute_from_db(klass, attributes, criteria, selected_fields, execute_callbacks: true)
80
+ end
81
+
82
+ # Execute from_db.
83
+ #
84
+ # @param [ Class ] klass The class to instantiate from if _type is not present.
85
+ # @param [ Hash ] attributes The document attributes.
86
+ # @param [ Criteria ] criteria Optional criteria object.
87
+ # @param [ Hash ] selected_fields Fields which were retrieved via
88
+ # #only. If selected_fields are specified, fields not listed in it
89
+ # will not be accessible in the returned document.
90
+ # @param [ true | false ] execute_callbacks Whether this method should
91
+ # invoke the callbacks. If true, the callbacks will be invoked normally.
92
+ # If false, the callbacks will be stored in the +pending_callbacks+ list
93
+ # and caller is responsible for invoking +run_pending_callbacks+ at a
94
+ # later time. Use this option to defer callback execution until the
95
+ # entire object graph containing embedded associations is constructed.
96
+ #
97
+ # @return [ Document ] The instantiated document.
98
+ #
99
+ # @api private
100
+ def execute_from_db(klass, attributes = nil, criteria = nil, selected_fields = nil, execute_callbacks: true)
66
101
  if criteria
67
102
  selected_fields ||= criteria.options[:fields]
68
103
  end
69
104
  type = (attributes || {})[klass.discriminator_key]
70
105
  if type.blank?
71
- obj = klass.instantiate(attributes, selected_fields)
106
+ obj = klass.instantiate_document(attributes, selected_fields, execute_callbacks: execute_callbacks)
72
107
  if criteria && criteria.association && criteria.parent_document
73
108
  obj.set_relation(criteria.association.inverse, criteria.parent_document)
74
109
  end
@@ -92,7 +127,7 @@ module Mongoid
92
127
  raise Errors::UnknownModel.new(camelized, type)
93
128
  end
94
129
 
95
- constantized.instantiate(attributes, selected_fields)
130
+ constantized.instantiate_document(attributes, selected_fields, execute_callbacks: execute_callbacks)
96
131
  end
97
132
  end
98
133
  end
@@ -60,6 +60,8 @@ module Mongoid
60
60
  if object_id_field? || object.is_a?(Document)
61
61
  if association.polymorphic?
62
62
  association.convert_to_foreign_key(object)
63
+ elsif object.is_a?(Document) && object.respond_to?(association.primary_key)
64
+ primary_key_field.evolve(object.send(association.primary_key))
63
65
  else
64
66
  object.__evolve_object_id__
65
67
  end
@@ -142,6 +144,11 @@ module Mongoid
142
144
  @related_id_field ||= association.klass.fields["_id"]
143
145
  end
144
146
 
147
+ def primary_key_field
148
+ @primary_key_field ||= association.klass.fields[association.primary_key]
149
+ end
150
+
151
+
145
152
  # This is used when default values need to be serialized. Most of the
146
153
  # time just return the object.
147
154
  #
@@ -8,9 +8,6 @@ module Mongoid
8
8
  module Macro
9
9
  extend self
10
10
 
11
- # The warning message to give when a field is of type Symbol.
12
- FIELD_TYPE_IS_SYMBOL = 'The BSON symbol type is deprecated; use String instead'.freeze
13
-
14
11
  OPTIONS = [
15
12
  :as,
16
13
  :default,
@@ -69,7 +66,7 @@ module Mongoid
69
66
  def validate_field_name(klass, name)
70
67
  [name, "#{name}?".to_sym, "#{name}=".to_sym].each do |n|
71
68
  if Mongoid.destructive_fields.include?(n)
72
- raise Errors::InvalidField.new(klass, n)
69
+ raise Errors::InvalidField.new(klass, name, n)
73
70
  end
74
71
  end
75
72
  end
@@ -91,7 +88,7 @@ module Mongoid
91
88
  def validate_name_uniqueness(klass, name, options)
92
89
  if !options[:overwrite] && klass.fields.keys.include?(name.to_s)
93
90
  if Mongoid.duplicate_fields_exception
94
- raise Errors::InvalidField.new(klass, name)
91
+ raise Errors::InvalidField.new(klass, name, name)
95
92
  else
96
93
  Mongoid.logger.warn("Overwriting existing field #{name} in class #{klass.name}.") if Mongoid.logger
97
94
  end
@@ -117,10 +114,7 @@ module Mongoid
117
114
  end
118
115
 
119
116
  if option == :type && options[option] == Symbol
120
- @field_type_is_symbol_warned ||= begin
121
- Mongoid.logger.warn(FIELD_TYPE_IS_SYMBOL)
122
- true
123
- end
117
+ Mongoid::Warnings.warn_symbol_type_deprecated
124
118
  end
125
119
  end
126
120
  end
@@ -42,6 +42,11 @@ module Mongoid
42
42
  # @api private
43
43
  IDS = [ :_id, '_id', ].freeze
44
44
 
45
+ # BSON classes that are not supported as field types
46
+ #
47
+ # @api private
48
+ INVALID_BSON_CLASSES = [ BSON::Decimal128, BSON::Int32, BSON::Int64 ].freeze
49
+
45
50
  module ClassMethods
46
51
  # Returns the list of id fields for this model class, as both strings
47
52
  # and symbols.
@@ -156,6 +161,7 @@ module Mongoid
156
161
  #
157
162
  # @return [ Array<String ] The names of the proc defaults.
158
163
  def apply_post_processed_defaults
164
+ pending_callbacks.delete(:apply_post_processed_defaults)
159
165
  post_processed_defaults.each do |name|
160
166
  apply_default(name)
161
167
  end
@@ -184,6 +190,7 @@ module Mongoid
184
190
  # @example Apply all the defaults.
185
191
  # model.apply_defaults
186
192
  def apply_defaults
193
+ pending_callbacks.delete(:apply_defaults)
187
194
  apply_pre_processed_defaults
188
195
  apply_post_processed_defaults
189
196
  end
@@ -239,6 +246,32 @@ module Mongoid
239
246
  self.class.using_object_ids?
240
247
  end
241
248
 
249
+ # Does this field start with a dollar sign ($) or contain a dot/period (.)?
250
+ #
251
+ # @api private
252
+ #
253
+ # @param [ String ] name The field name.
254
+ #
255
+ # @return [ true, false ] If this field is dotted or dollared.
256
+ def dot_dollar_field?(name)
257
+ n = aliased_fields[name] || name
258
+ fields.key?(n) && (n.include?('.') || n.start_with?('$'))
259
+ end
260
+
261
+ # Validate whether or not the field starts with a dollar sign ($) or
262
+ # contains a dot/period (.).
263
+ #
264
+ # @api private
265
+ #
266
+ # @raise [ InvalidDotDollarAssignment ] If contains dots or starts with a dollar.
267
+ #
268
+ # @param [ String ] name The field name.
269
+ def validate_writable_field_name!(name)
270
+ if dot_dollar_field?(name)
271
+ raise Errors::InvalidDotDollarAssignment.new(self.class, name)
272
+ end
273
+ end
274
+
242
275
  class << self
243
276
 
244
277
  # Stores the provided block to be run when the option name specified is
@@ -603,9 +636,7 @@ module Mongoid
603
636
  if lazy_settable?(field, raw)
604
637
  write_attribute(name, field.eval_default(self))
605
638
  else
606
- value = field.demongoize(raw)
607
- attribute_will_change!(name) if value.resizable?
608
- value
639
+ process_raw_attribute(name.to_s, raw, field)
609
640
  end
610
641
  end
611
642
  end
@@ -697,10 +728,8 @@ module Mongoid
697
728
  generated_methods.module_eval do
698
729
  re_define_method("#{meth}_translations=") do |value|
699
730
  attribute_will_change!(name)
700
- if value
701
- value.update_values do |_value|
702
- field.type.mongoize(_value)
703
- end
731
+ value&.transform_values! do |_value|
732
+ field.type.mongoize(_value)
704
733
  end
705
734
  attributes[name] = value
706
735
  end
@@ -737,6 +766,19 @@ module Mongoid
737
766
  opts = options.merge(klass: self)
738
767
  type_mapping = TYPE_MAPPINGS[options[:type]]
739
768
  opts[:type] = type_mapping || unmapped_type(options)
769
+ if !opts[:type].is_a?(Class)
770
+ raise Errors::InvalidFieldType.new(self, name, options[:type])
771
+ else
772
+ if INVALID_BSON_CLASSES.include?(opts[:type])
773
+ warn_message = "Using #{opts[:type]} as the field type is not supported. "
774
+ if opts[:type] == BSON::Decimal128
775
+ warn_message += "In BSON <= 4, the BSON::Decimal128 type will work as expected for both storing and querying, but will return a BigDecimal on query in BSON 5+."
776
+ else
777
+ warn_message += "Saving values of this type to the database will work as expected, however, querying them will return a value of the native Ruby Integer type."
778
+ end
779
+ Mongoid.logger.warn(warn_message)
780
+ end
781
+ end
740
782
  return Fields::Localized.new(name, opts) if options[:localize]
741
783
  return Fields::ForeignKey.new(name, opts) if options[:identity]
742
784
  Fields::Standard.new(name, opts)
@@ -38,6 +38,7 @@ module Mongoid
38
38
  :max,
39
39
  :min,
40
40
  :none,
41
+ :pick,
41
42
  :pluck,
42
43
  :read,
43
44
  :sum,
@@ -121,6 +122,13 @@ module Mongoid
121
122
  # strings will be transparently converted to +BSON::ObjectId+ instances
122
123
  # during query construction.
123
124
  #
125
+ # If this method is given a block, it delegates to +Enumerable#find+ and
126
+ # returns the first document of those found by the current Crieria object
127
+ # for which the block returns a truthy value. If both a block and ids are
128
+ # given, the block is ignored and the documents for the given ids are
129
+ # returned. If a block and a Proc are given, the method delegates to
130
+ # +Enumerable#find+ and uses the proc as the default.
131
+ #
124
132
  # The +find+ method takes into account the default scope defined on the
125
133
  # model class, if any.
126
134
  #
@@ -131,8 +139,13 @@ module Mongoid
131
139
  #
132
140
  # @raise Errors::DocumentNotFound If not all documents are found and
133
141
  # the +raise_not_found_error+ Mongoid configuration option is truthy.
134
- def find(*args)
135
- with_default_scope.find(*args)
142
+ def find(*args, &block)
143
+ empty_or_proc = args.empty? || (args.length == 1 && args.first.is_a?(Proc))
144
+ if block_given? && empty_or_proc
145
+ with_default_scope.find(*args, &block)
146
+ else
147
+ with_default_scope.find(*args)
148
+ end
136
149
  end
137
150
 
138
151
  # Find the first +Document+ given the conditions.
@@ -182,15 +195,11 @@ module Mongoid
182
195
  # @example Find the first document.
183
196
  # Person.first
184
197
  #
185
- # @param [ Integer | Hash ] limit_or_opts The number of documents to
186
- # return, or a hash of options.
187
- #
188
- # @option limit_or_opts [ :none ] :id_sort This option is deprecated.
189
- # Don't apply a sort on _id if no other sort is defined on the criteria.
198
+ # @param [ Integer ] limit The number of documents to return.
190
199
  #
191
200
  # @return [ Document ] The first matching document.
192
- def first(limit_or_opts = nil)
193
- with_default_scope.first(limit_or_opts)
201
+ def first(limit = nil)
202
+ with_default_scope.first(limit)
194
203
  end
195
204
  alias :one :first
196
205
 
@@ -199,15 +208,11 @@ module Mongoid
199
208
  # @example Find the last document.
200
209
  # Person.last
201
210
  #
202
- # @param [ Integer | Hash ] limit_or_opts The number of documents to
203
- # return, or a hash of options.
204
- #
205
- # @option limit_or_opts [ :none ] :id_sort This option is deprecated.
206
- # Don't apply a sort on _id if no other sort is defined on the criteria.
211
+ # @param [ Integer ] limit The number of documents to return.
207
212
  #
208
213
  # @return [ Document ] The last matching document.
209
- def last(limit_or_opts = nil)
210
- with_default_scope.last(limit_or_opts)
214
+ def last(limit = nil)
215
+ with_default_scope.last(limit)
211
216
  end
212
217
  end
213
218
  end
@@ -86,7 +86,7 @@ module Mongoid
86
86
  # @api private
87
87
  #
88
88
  # @example Normalize the index options.
89
- # specification.normalize_options(drop_dups: true)
89
+ # specification.normalize_options(unique: true)
90
90
  #
91
91
  # @param [ Hash ] opts The index options.
92
92
  #
@@ -13,7 +13,6 @@ module Mongoid
13
13
  :database,
14
14
  :default_language,
15
15
  :language_override,
16
- :drop_dups,
17
16
  :name,
18
17
  :sparse,
19
18
  :unique,
@@ -98,6 +97,10 @@ module Mongoid
98
97
  unless VALID_TYPES.include?(value)
99
98
  raise Errors::InvalidIndex.new(klass, spec, options)
100
99
  end
100
+
101
+ if value == "geoHaystack"
102
+ Mongoid::Warnings.warn_geo_haystack_deprecated
103
+ end
101
104
  end
102
105
  end
103
106
  end
@@ -27,7 +27,7 @@ module Mongoid
27
27
  :before_save,
28
28
  :before_update,
29
29
  :before_upsert,
30
- :before_validation
30
+ :before_validation,
31
31
  ].freeze
32
32
 
33
33
  included do
@@ -37,6 +37,12 @@ module Mongoid
37
37
  define_model_callbacks :build, :find, :initialize, :touch, only: :after
38
38
  define_model_callbacks :create, :destroy, :save, :update, :upsert
39
39
 
40
+ # This callback is used internally by Mongoid to save association
41
+ # targets for referenced associations after the parent model is persisted.
42
+ #
43
+ # @api private
44
+ define_model_callbacks :persist_parent
45
+
40
46
  attr_accessor :before_callback_halted
41
47
  end
42
48
 
@@ -109,22 +115,76 @@ module Mongoid
109
115
  # end
110
116
  #
111
117
  # @param [ Symbol ] kind The type of callback to execute.
112
- # @param [ Array ] args Any options.
113
- #
114
- # @return [ Document ] The document
115
- ruby2_keywords def run_callbacks(kind, *args, &block)
116
- cascadable_children(kind).each do |child|
117
- if child.run_callbacks(child_callback_type(kind, child), *args) == false
118
- return false
118
+ # @param [ true | false ] with_children Flag specifies whether callbacks of embedded document should be run.
119
+ def run_callbacks(kind, with_children: true, &block)
120
+ if with_children
121
+ cascadable_children(kind).each do |child|
122
+ if child.run_callbacks(child_callback_type(kind, child), with_children: with_children) == false
123
+ return false
124
+ end
119
125
  end
120
126
  end
121
127
  if callback_executable?(kind)
122
- super(kind, *args, &block)
128
+ super(kind, &block)
123
129
  else
124
130
  true
125
131
  end
126
132
  end
127
133
 
134
+ # Run the callbacks for embedded documents.
135
+ #
136
+ # @param [ Symbol ] kind The type of callback to execute.
137
+ # @param [ Array<Document> ] children Children to exeute callbacks on. If
138
+ # nil, callbacks will be executed on all cascadable children of
139
+ # the document.
140
+ #
141
+ # @api private
142
+ def _mongoid_run_child_callbacks(kind, children: nil, &block)
143
+ child, *tail = (children || cascadable_children(kind))
144
+ if child.nil?
145
+ return block&.call
146
+ elsif tail.empty?
147
+ return child.run_callbacks(child_callback_type(kind, child), &block)
148
+ else
149
+ return child.run_callbacks(child_callback_type(kind, child)) do
150
+ _mongoid_run_child_callbacks(kind, children: tail, &block)
151
+ end
152
+ end
153
+ end
154
+
155
+ # This is used to store callbacks to be executed later. A good use case for
156
+ # this is delaying the after_find and after_initialize callbacks until the
157
+ # associations are set on the document. This can also be used to delay
158
+ # applying the defaults on a document.
159
+ #
160
+ # @return [ Array<Symbol> ] an array of symbols that represent the pending callbacks.
161
+ #
162
+ # @api private
163
+ def pending_callbacks
164
+ @pending_callbacks ||= [].to_set
165
+ end
166
+
167
+ # @api private
168
+ def pending_callbacks=(value)
169
+ @pending_callbacks = value
170
+ end
171
+
172
+ # Run the pending callbacks. If the callback is :apply_defaults, we will apply
173
+ # the defaults for this document. Otherwise, the callback is passed to the
174
+ # run_callbacks function.
175
+ #
176
+ # @api private
177
+ def run_pending_callbacks
178
+ pending_callbacks.each do |cb|
179
+ if [:apply_defaults, :apply_post_processed_defaults].include?(cb)
180
+ send(cb)
181
+ else
182
+ self.run_callbacks(cb, with_children: false)
183
+ end
184
+ end
185
+ pending_callbacks.clear
186
+ end
187
+
128
188
  private
129
189
 
130
190
  # We need to hook into this for autosave, since we don't want it firing if
@@ -102,13 +102,22 @@ module Mongoid
102
102
  def prepare_insert(options = {})
103
103
  return self if performing_validations?(options) &&
104
104
  invalid?(options[:context] || :create)
105
- result = run_callbacks(:save) do
106
- run_callbacks(:create) do
107
- yield(self)
108
- post_process_insert
105
+ run_callbacks(:save, with_children: false) do
106
+ run_callbacks(:create, with_children: false) do
107
+ run_callbacks(:persist_parent, with_children: false) do
108
+ _mongoid_run_child_callbacks(:save) do
109
+ _mongoid_run_child_callbacks(:create) do
110
+ result = yield(self)
111
+ if !result.is_a?(Document) || result.errors.empty?
112
+ post_process_insert
113
+ post_process_persist(result, options)
114
+ end
115
+ end
116
+ end
117
+ end
109
118
  end
110
119
  end
111
- post_process_persist(result, options) and self
120
+ self
112
121
  end
113
122
 
114
123
  module ClassMethods
@@ -96,13 +96,20 @@ module Mongoid
96
96
  return false if performing_validations?(options) &&
97
97
  invalid?(options[:context] || :update)
98
98
  process_flagged_destroys
99
- result = run_callbacks(:save) do
100
- run_callbacks(:update) do
101
- yield(self)
102
- true
99
+ run_callbacks(:save, with_children: false) do
100
+ run_callbacks(:update, with_children: false) do
101
+ run_callbacks(:persist_parent, with_children: false) do
102
+ _mongoid_run_child_callbacks(:save) do
103
+ _mongoid_run_child_callbacks(:update) do
104
+ result = yield(self)
105
+ self.previously_new_record = false
106
+ post_process_persist(result, options)
107
+ true
108
+ end
109
+ end
110
+ end
103
111
  end
104
112
  end
105
- post_process_persist(result, options) and result
106
113
  end
107
114
 
108
115
  # Update the document in the database.