mongoid 7.5.0 → 8.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (286) 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 +46 -30
  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 +2 -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 -18
  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.rb +20 -10
  41. data/lib/mongoid/contextual/aggregable/memory.rb +23 -15
  42. data/lib/mongoid/contextual/aggregable/mongo.rb +1 -1
  43. data/lib/mongoid/contextual/map_reduce.rb +2 -2
  44. data/lib/mongoid/contextual/memory.rb +55 -28
  45. data/lib/mongoid/contextual/mongo.rb +173 -245
  46. data/lib/mongoid/contextual/none.rb +33 -15
  47. data/lib/mongoid/copyable.rb +32 -8
  48. data/lib/mongoid/criteria/includable.rb +24 -20
  49. data/lib/mongoid/criteria/marshalable.rb +10 -2
  50. data/lib/mongoid/criteria/queryable/extensions/array.rb +2 -15
  51. data/lib/mongoid/criteria/queryable/extensions/big_decimal.rb +25 -4
  52. data/lib/mongoid/criteria/queryable/extensions/boolean.rb +1 -1
  53. data/lib/mongoid/criteria/queryable/extensions/date.rb +6 -1
  54. data/lib/mongoid/criteria/queryable/extensions/date_time.rb +6 -1
  55. data/lib/mongoid/criteria/queryable/extensions/hash.rb +0 -16
  56. data/lib/mongoid/criteria/queryable/extensions/numeric.rb +1 -1
  57. data/lib/mongoid/criteria/queryable/extensions/object.rb +2 -1
  58. data/lib/mongoid/criteria/queryable/extensions/range.rb +13 -5
  59. data/lib/mongoid/criteria/queryable/extensions/regexp.rb +1 -1
  60. data/lib/mongoid/criteria/queryable/extensions/symbol.rb +3 -1
  61. data/lib/mongoid/criteria/queryable/extensions/time.rb +6 -1
  62. data/lib/mongoid/criteria/queryable/extensions/time_with_zone.rb +6 -1
  63. data/lib/mongoid/criteria/queryable/optional.rb +3 -9
  64. data/lib/mongoid/criteria/queryable/options.rb +1 -1
  65. data/lib/mongoid/criteria/queryable/selectable.rb +2 -24
  66. data/lib/mongoid/criteria/queryable/selector.rb +89 -4
  67. data/lib/mongoid/criteria/queryable/smash.rb +39 -6
  68. data/lib/mongoid/criteria/queryable.rb +11 -6
  69. data/lib/mongoid/criteria.rb +1 -28
  70. data/lib/mongoid/deprecable.rb +36 -0
  71. data/lib/mongoid/deprecation.rb +25 -0
  72. data/lib/mongoid/document.rb +96 -34
  73. data/lib/mongoid/errors/document_not_found.rb +6 -2
  74. data/lib/mongoid/errors/invalid_dot_dollar_assignment.rb +23 -0
  75. data/lib/mongoid/errors/invalid_field.rb +5 -1
  76. data/lib/mongoid/errors/invalid_field_type.rb +26 -0
  77. data/lib/mongoid/errors/too_many_nested_attribute_records.rb +1 -1
  78. data/lib/mongoid/errors.rb +2 -2
  79. data/lib/mongoid/extensions/array.rb +8 -6
  80. data/lib/mongoid/extensions/big_decimal.rb +29 -10
  81. data/lib/mongoid/extensions/binary.rb +42 -0
  82. data/lib/mongoid/extensions/boolean.rb +8 -2
  83. data/lib/mongoid/extensions/date.rb +26 -20
  84. data/lib/mongoid/extensions/date_time.rb +1 -1
  85. data/lib/mongoid/extensions/float.rb +4 -5
  86. data/lib/mongoid/extensions/hash.rb +12 -5
  87. data/lib/mongoid/extensions/integer.rb +4 -5
  88. data/lib/mongoid/extensions/object.rb +2 -0
  89. data/lib/mongoid/extensions/range.rb +41 -10
  90. data/lib/mongoid/extensions/regexp.rb +11 -4
  91. data/lib/mongoid/extensions/set.rb +11 -4
  92. data/lib/mongoid/extensions/string.rb +2 -13
  93. data/lib/mongoid/extensions/symbol.rb +3 -14
  94. data/lib/mongoid/extensions/time.rb +27 -16
  95. data/lib/mongoid/extensions/time_with_zone.rb +1 -2
  96. data/lib/mongoid/extensions.rb +1 -0
  97. data/lib/mongoid/factory.rb +42 -7
  98. data/lib/mongoid/fields/foreign_key.rb +7 -0
  99. data/lib/mongoid/fields/validators/macro.rb +3 -9
  100. data/lib/mongoid/fields.rb +49 -7
  101. data/lib/mongoid/findable.rb +21 -16
  102. data/lib/mongoid/indexable/specification.rb +1 -1
  103. data/lib/mongoid/indexable/validators/options.rb +4 -1
  104. data/lib/mongoid/interceptable.rb +69 -9
  105. data/lib/mongoid/persistable/creatable.rb +14 -5
  106. data/lib/mongoid/persistable/updatable.rb +12 -5
  107. data/lib/mongoid/persistence_context.rb +19 -2
  108. data/lib/mongoid/query_cache.rb +6 -258
  109. data/lib/mongoid/railties/controller_runtime.rb +1 -1
  110. data/lib/mongoid/reloadable.rb +7 -3
  111. data/lib/mongoid/selectable.rb +1 -2
  112. data/lib/mongoid/stateful.rb +27 -1
  113. data/lib/mongoid/timestamps/created.rb +1 -1
  114. data/lib/mongoid/timestamps/updated.rb +1 -1
  115. data/lib/mongoid/touchable.rb +2 -3
  116. data/lib/mongoid/traversable.rb +1 -0
  117. data/lib/mongoid/validatable/uniqueness.rb +2 -1
  118. data/lib/mongoid/version.rb +1 -1
  119. data/lib/mongoid/warnings.rb +3 -4
  120. data/lib/mongoid.rb +1 -0
  121. data/spec/config/mongoid.yml +16 -0
  122. data/spec/integration/app_spec.rb +8 -12
  123. data/spec/integration/associations/belongs_to_spec.rb +18 -0
  124. data/spec/integration/associations/embedded_spec.rb +15 -0
  125. data/spec/integration/associations/embeds_many_spec.rb +15 -2
  126. data/spec/integration/associations/embeds_one_spec.rb +18 -0
  127. data/spec/integration/associations/foreign_key_spec.rb +9 -0
  128. data/spec/integration/associations/has_and_belongs_to_many_spec.rb +21 -0
  129. data/spec/integration/associations/has_one_spec.rb +97 -1
  130. data/spec/integration/associations/scope_option_spec.rb +1 -1
  131. data/spec/integration/callbacks_models.rb +95 -1
  132. data/spec/integration/callbacks_spec.rb +226 -4
  133. data/spec/integration/criteria/range_spec.rb +95 -1
  134. data/spec/integration/discriminator_key_spec.rb +115 -76
  135. data/spec/integration/dots_and_dollars_spec.rb +277 -0
  136. data/spec/integration/i18n_fallbacks_spec.rb +1 -15
  137. data/spec/integration/matcher_examples_spec.rb +20 -13
  138. data/spec/integration/matcher_operator_data/type_decimal.yml +3 -2
  139. data/spec/integration/matcher_operator_spec.rb +3 -5
  140. data/spec/integration/persistence/range_field_spec.rb +350 -0
  141. data/spec/mongoid/association/counter_cache_spec.rb +1 -1
  142. data/spec/mongoid/association/depending_spec.rb +9 -9
  143. data/spec/mongoid/association/eager_spec.rb +2 -1
  144. data/spec/mongoid/association/embedded/embedded_in/binding_spec.rb +2 -1
  145. data/spec/mongoid/association/embedded/embedded_in/buildable_spec.rb +54 -0
  146. data/spec/mongoid/association/embedded/embedded_in/proxy_spec.rb +69 -9
  147. data/spec/mongoid/association/embedded/embeds_many/buildable_spec.rb +112 -0
  148. data/spec/mongoid/association/embedded/embeds_many/proxy_spec.rb +219 -8
  149. data/spec/mongoid/association/embedded/embeds_many_models.rb +157 -0
  150. data/spec/mongoid/association/embedded/embeds_many_query_spec.rb +12 -0
  151. data/spec/mongoid/association/embedded/embeds_many_spec.rb +68 -0
  152. data/spec/mongoid/association/embedded/embeds_one/buildable_spec.rb +25 -0
  153. data/spec/mongoid/association/embedded/embeds_one_models.rb +19 -0
  154. data/spec/mongoid/association/embedded/embeds_one_spec.rb +28 -0
  155. data/spec/mongoid/association/referenced/belongs_to/binding_spec.rb +2 -1
  156. data/spec/mongoid/association/referenced/belongs_to/buildable_spec.rb +54 -0
  157. data/spec/mongoid/association/referenced/belongs_to/proxy_spec.rb +15 -0
  158. data/spec/mongoid/association/referenced/belongs_to_models.rb +11 -0
  159. data/spec/mongoid/association/referenced/belongs_to_spec.rb +2 -2
  160. data/spec/mongoid/association/referenced/has_and_belongs_to_many/proxy_spec.rb +67 -4
  161. data/spec/mongoid/association/referenced/has_and_belongs_to_many_models.rb +25 -0
  162. data/spec/mongoid/association/referenced/has_and_belongs_to_many_spec.rb +35 -2
  163. data/spec/mongoid/association/referenced/has_many/buildable_spec.rb +109 -0
  164. data/spec/mongoid/association/referenced/has_many/enumerable_spec.rb +2 -56
  165. data/spec/mongoid/association/referenced/has_many/proxy_spec.rb +82 -13
  166. data/spec/mongoid/association/referenced/has_many_models.rb +3 -1
  167. data/spec/mongoid/association/referenced/has_many_spec.rb +25 -0
  168. data/spec/mongoid/association/referenced/has_one/buildable_spec.rb +2 -2
  169. data/spec/mongoid/association/referenced/has_one/proxy_spec.rb +107 -1
  170. data/spec/mongoid/association/referenced/has_one_models.rb +16 -0
  171. data/spec/mongoid/association/syncable_spec.rb +14 -0
  172. data/spec/mongoid/atomic/paths_spec.rb +0 -14
  173. data/spec/mongoid/attributes/nested_spec.rb +80 -11
  174. data/spec/mongoid/attributes/nested_spec_models.rb +48 -0
  175. data/spec/mongoid/attributes/projector_spec.rb +1 -5
  176. data/spec/mongoid/attributes_spec.rb +524 -27
  177. data/spec/mongoid/changeable_spec.rb +130 -13
  178. data/spec/mongoid/clients/factory_spec.rb +23 -30
  179. data/spec/mongoid/clients/sessions_spec.rb +0 -38
  180. data/spec/mongoid/clients_spec.rb +32 -2
  181. data/spec/mongoid/config_spec.rb +58 -13
  182. data/spec/mongoid/contextual/aggregable/memory_spec.rb +396 -158
  183. data/spec/mongoid/contextual/aggregable/memory_table.yml +88 -0
  184. data/spec/mongoid/contextual/aggregable/memory_table_spec.rb +62 -0
  185. data/spec/mongoid/contextual/map_reduce_spec.rb +2 -16
  186. data/spec/mongoid/contextual/memory_spec.rb +521 -14
  187. data/spec/mongoid/contextual/mongo_spec.rb +564 -394
  188. data/spec/mongoid/contextual/none_spec.rb +11 -19
  189. data/spec/mongoid/copyable_spec.rb +451 -1
  190. data/spec/mongoid/criteria/findable_spec.rb +86 -210
  191. data/spec/mongoid/criteria/includable_spec.rb +1492 -0
  192. data/spec/mongoid/criteria/includable_spec_models.rb +54 -0
  193. data/spec/mongoid/criteria/marshalable_spec.rb +18 -1
  194. data/spec/mongoid/criteria/queryable/extensions/array_spec.rb +7 -19
  195. data/spec/mongoid/criteria/queryable/extensions/big_decimal_spec.rb +134 -26
  196. data/spec/mongoid/criteria/queryable/extensions/date_spec.rb +11 -0
  197. data/spec/mongoid/criteria/queryable/extensions/date_time_spec.rb +11 -0
  198. data/spec/mongoid/criteria/queryable/extensions/hash_spec.rb +0 -15
  199. data/spec/mongoid/criteria/queryable/extensions/numeric_spec.rb +73 -7
  200. data/spec/mongoid/criteria/queryable/extensions/time_spec.rb +11 -0
  201. data/spec/mongoid/criteria/queryable/extensions/time_with_zone_spec.rb +11 -0
  202. data/spec/mongoid/criteria/queryable/optional_spec.rb +0 -484
  203. data/spec/mongoid/criteria/queryable/selectable_logical_spec.rb +50 -0
  204. data/spec/mongoid/criteria/queryable/selectable_spec.rb +77 -85
  205. data/spec/mongoid/criteria/queryable/selector_spec.rb +14 -2
  206. data/spec/mongoid/criteria_spec.rb +469 -1201
  207. data/spec/mongoid/document_fields_spec.rb +173 -24
  208. data/spec/mongoid/document_spec.rb +32 -41
  209. data/spec/mongoid/errors/document_not_found_spec.rb +29 -2
  210. data/spec/mongoid/errors/invalid_field_spec.rb +1 -1
  211. data/spec/mongoid/errors/invalid_field_type_spec.rb +55 -0
  212. data/spec/mongoid/errors/mongoid_error_spec.rb +3 -1
  213. data/spec/mongoid/errors/no_environment_spec.rb +3 -3
  214. data/spec/mongoid/errors/too_many_nested_attribute_records_spec.rb +1 -1
  215. data/spec/mongoid/extensions/array_spec.rb +16 -2
  216. data/spec/mongoid/extensions/big_decimal_spec.rb +697 -212
  217. data/spec/mongoid/extensions/binary_spec.rb +44 -9
  218. data/spec/mongoid/extensions/boolean_spec.rb +68 -82
  219. data/spec/mongoid/extensions/date_class_mongoize_spec.rb +7 -3
  220. data/spec/mongoid/extensions/date_spec.rb +71 -1
  221. data/spec/mongoid/extensions/date_time_spec.rb +15 -9
  222. data/spec/mongoid/extensions/float_spec.rb +48 -76
  223. data/spec/mongoid/extensions/hash_spec.rb +30 -0
  224. data/spec/mongoid/extensions/integer_spec.rb +45 -66
  225. data/spec/mongoid/extensions/range_spec.rb +255 -54
  226. data/spec/mongoid/extensions/regexp_spec.rb +58 -33
  227. data/spec/mongoid/extensions/set_spec.rb +106 -0
  228. data/spec/mongoid/extensions/string_spec.rb +53 -25
  229. data/spec/mongoid/extensions/symbol_spec.rb +18 -25
  230. data/spec/mongoid/extensions/time_spec.rb +634 -66
  231. data/spec/mongoid/extensions/time_with_zone_spec.rb +17 -31
  232. data/spec/mongoid/factory_spec.rb +61 -1
  233. data/spec/mongoid/fields_spec.rb +321 -50
  234. data/spec/mongoid/findable_spec.rb +64 -29
  235. data/spec/mongoid/indexable/specification_spec.rb +2 -2
  236. data/spec/mongoid/indexable_spec.rb +16 -19
  237. data/spec/mongoid/interceptable_spec.rb +584 -5
  238. data/spec/mongoid/interceptable_spec_models.rb +235 -4
  239. data/spec/mongoid/matcher/extract_attribute_spec.rb +1 -5
  240. data/spec/mongoid/mongoizable_spec.rb +285 -0
  241. data/spec/mongoid/persistable/creatable_spec.rb +2 -2
  242. data/spec/mongoid/persistable/deletable_spec.rb +2 -2
  243. data/spec/mongoid/persistable/destroyable_spec.rb +2 -2
  244. data/spec/mongoid/persistable/upsertable_spec.rb +14 -0
  245. data/spec/mongoid/persistence_context_spec.rb +50 -1
  246. data/spec/mongoid/query_cache_middleware_spec.rb +0 -18
  247. data/spec/mongoid/query_cache_spec.rb +0 -154
  248. data/spec/mongoid/reloadable_spec.rb +35 -2
  249. data/spec/mongoid/scopable_spec.rb +21 -1
  250. data/spec/mongoid/shardable_spec.rb +14 -0
  251. data/spec/mongoid/stateful_spec.rb +28 -0
  252. data/spec/mongoid/timestamps_spec.rb +390 -0
  253. data/spec/mongoid/timestamps_spec_models.rb +67 -0
  254. data/spec/mongoid/touchable_spec.rb +116 -0
  255. data/spec/mongoid/touchable_spec_models.rb +12 -8
  256. data/spec/mongoid/traversable_spec.rb +4 -11
  257. data/spec/mongoid/validatable/presence_spec.rb +1 -1
  258. data/spec/mongoid/validatable/uniqueness_spec.rb +60 -31
  259. data/spec/mongoid/warnings_spec.rb +35 -0
  260. data/spec/rails/controller_extension/controller_runtime_spec.rb +2 -2
  261. data/spec/rails/mongoid_spec.rb +4 -16
  262. data/spec/shared/lib/mrss/event_subscriber.rb +5 -15
  263. data/spec/support/constraints.rb +24 -0
  264. data/spec/support/macros.rb +30 -0
  265. data/spec/support/models/augmentation.rb +12 -0
  266. data/spec/support/models/band.rb +3 -0
  267. data/spec/support/models/catalog.rb +24 -0
  268. data/spec/support/models/circus.rb +3 -0
  269. data/spec/support/models/fanatic.rb +8 -0
  270. data/spec/support/models/implant.rb +9 -0
  271. data/spec/support/models/label.rb +2 -0
  272. data/spec/support/models/passport.rb +9 -0
  273. data/spec/support/models/person.rb +1 -0
  274. data/spec/support/models/player.rb +2 -0
  275. data/spec/support/models/powerup.rb +12 -0
  276. data/spec/support/models/registry.rb +1 -0
  277. data/spec/support/models/school.rb +14 -0
  278. data/spec/support/models/shield.rb +18 -0
  279. data/spec/support/models/student.rb +14 -0
  280. data/spec/support/models/weapon.rb +12 -0
  281. data.tar.gz.sig +0 -0
  282. metadata +48 -12
  283. metadata.gz.sig +0 -0
  284. data/lib/mongoid/errors/eager_load.rb +0 -23
  285. data/lib/mongoid/errors/invalid_value.rb +0 -17
  286. 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)
@@ -75,46 +75,55 @@ module Mongoid
75
75
  # Return stored times as UTC.
76
76
  option :use_utc, default: false
77
77
 
78
+ # Store BigDecimals as Decimal128s instead of strings in the db.
79
+ option :map_big_decimal_to_decimal128, default: true
80
+
78
81
  # Update embedded documents correctly when setting it, unsetting it
79
82
  # and resetting it. See MONGOID-5206 and MONGOID-5240 for more details.
80
- option :broken_updates, default: true
83
+ option :broken_updates, default: false
81
84
 
82
85
  # Maintain legacy behavior of === on Mongoid documents, which returns
83
86
  # true in a number of cases where Ruby's === implementation would
84
87
  # return false.
85
- option :legacy_triple_equals, default: true
88
+ option :legacy_triple_equals, default: false
86
89
 
87
90
  # When exiting a nested `with_scope' block, set the current scope to
88
91
  # nil instead of the parent scope for backwards compatibility.
89
- option :broken_scoping, default: true
92
+ option :broken_scoping, default: false
90
93
 
91
94
  # Maintain broken behavior of sum over empty result sets for backwards
92
95
  # compatibility.
93
- option :broken_aggregables, default: true
96
+ option :broken_aggregables, default: false
94
97
 
95
98
  # Ignore aliased fields in embedded documents when performing pluck and
96
99
  # distinct operations, for backwards compatibility.
97
- option :broken_alias_handling, default: true
100
+ option :broken_alias_handling, default: false
98
101
 
99
102
  # Maintain broken `and' behavior when using the same operator on the same
100
103
  # field multiple times for backwards compatibility.
101
- option :broken_and, default: true
104
+ option :broken_and, default: false
102
105
 
103
106
  # Use millisecond precision when comparing Time objects with the _matches?
104
107
  # function.
105
- option :compare_time_by_ms, default: false
108
+ option :compare_time_by_ms, default: true
106
109
 
107
110
  # Use bson-ruby's implementation of as_json for BSON::ObjectId instead of
108
111
  # the one monkey-patched into Mongoid.
109
- option :object_id_as_json_oid, default: true
112
+ option :object_id_as_json_oid, default: false
110
113
 
111
114
  # Maintain legacy behavior of pluck and distinct, which does not
112
115
  # demongoize the values on returning them.
113
- option :legacy_pluck_distinct, default: true
116
+ option :legacy_pluck_distinct, default: false
114
117
 
115
118
  # Combine chained operators, which use the same field and operator,
116
119
  # using and's instead of overwriting them.
117
- option :overwrite_chained_operators, default: true
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
118
127
 
119
128
  # Has Mongoid been configured? This is checking that at least a valid
120
129
  # client config exists.
@@ -207,6 +216,7 @@ module Mongoid
207
216
  configuration = settings.with_indifferent_access
208
217
  self.options = configuration[:options]
209
218
  self.clients = configuration[:clients]
219
+ Mongo.options = configuration[:driver_options] || {}
210
220
  set_log_levels
211
221
  end
212
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