mongoid 7.5.3 → 8.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (295) 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 +28 -5
  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/attributes/processing.rb +9 -2
  35. data/lib/mongoid/attributes.rb +30 -27
  36. data/lib/mongoid/cacheable.rb +2 -2
  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 +15 -11
  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 -262
  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 +88 -33
  73. data/lib/mongoid/equality.rb +4 -4
  74. data/lib/mongoid/errors/document_not_found.rb +6 -2
  75. data/lib/mongoid/errors/invalid_dot_dollar_assignment.rb +23 -0
  76. data/lib/mongoid/errors/invalid_field.rb +5 -1
  77. data/lib/mongoid/errors/invalid_field_type.rb +26 -0
  78. data/lib/mongoid/errors/too_many_nested_attribute_records.rb +1 -1
  79. data/lib/mongoid/errors.rb +2 -2
  80. data/lib/mongoid/extensions/array.rb +8 -6
  81. data/lib/mongoid/extensions/big_decimal.rb +29 -10
  82. data/lib/mongoid/extensions/binary.rb +42 -0
  83. data/lib/mongoid/extensions/boolean.rb +8 -2
  84. data/lib/mongoid/extensions/date.rb +26 -20
  85. data/lib/mongoid/extensions/date_time.rb +1 -1
  86. data/lib/mongoid/extensions/float.rb +4 -5
  87. data/lib/mongoid/extensions/hash.rb +12 -5
  88. data/lib/mongoid/extensions/integer.rb +4 -5
  89. data/lib/mongoid/extensions/object.rb +2 -0
  90. data/lib/mongoid/extensions/range.rb +41 -10
  91. data/lib/mongoid/extensions/regexp.rb +11 -4
  92. data/lib/mongoid/extensions/set.rb +11 -4
  93. data/lib/mongoid/extensions/string.rb +2 -13
  94. data/lib/mongoid/extensions/symbol.rb +3 -14
  95. data/lib/mongoid/extensions/time.rb +27 -16
  96. data/lib/mongoid/extensions/time_with_zone.rb +1 -2
  97. data/lib/mongoid/extensions.rb +1 -0
  98. data/lib/mongoid/factory.rb +42 -7
  99. data/lib/mongoid/fields/foreign_key.rb +7 -0
  100. data/lib/mongoid/fields/validators/macro.rb +3 -9
  101. data/lib/mongoid/fields.rb +49 -7
  102. data/lib/mongoid/findable.rb +21 -16
  103. data/lib/mongoid/indexable/specification.rb +1 -1
  104. data/lib/mongoid/indexable/validators/options.rb +4 -1
  105. data/lib/mongoid/interceptable.rb +69 -9
  106. data/lib/mongoid/persistable/creatable.rb +14 -5
  107. data/lib/mongoid/persistable/updatable.rb +12 -5
  108. data/lib/mongoid/persistence_context.rb +8 -42
  109. data/lib/mongoid/query_cache.rb +6 -258
  110. data/lib/mongoid/railties/controller_runtime.rb +1 -1
  111. data/lib/mongoid/reloadable.rb +7 -3
  112. data/lib/mongoid/scopable.rb +9 -11
  113. data/lib/mongoid/selectable.rb +1 -2
  114. data/lib/mongoid/shardable.rb +11 -35
  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 +1 -0
  120. data/lib/mongoid/validatable/uniqueness.rb +2 -1
  121. data/lib/mongoid/version.rb +1 -1
  122. data/lib/mongoid/warnings.rb +3 -4
  123. data/lib/mongoid.rb +1 -0
  124. data/spec/config/mongoid.yml +16 -0
  125. data/spec/integration/app_spec.rb +8 -12
  126. data/spec/integration/associations/belongs_to_spec.rb +18 -0
  127. data/spec/integration/associations/embedded_spec.rb +15 -0
  128. data/spec/integration/associations/embeds_many_spec.rb +15 -2
  129. data/spec/integration/associations/embeds_one_spec.rb +18 -0
  130. data/spec/integration/associations/foreign_key_spec.rb +9 -0
  131. data/spec/integration/associations/has_and_belongs_to_many_spec.rb +21 -0
  132. data/spec/integration/associations/has_one_spec.rb +97 -1
  133. data/spec/integration/associations/scope_option_spec.rb +1 -1
  134. data/spec/integration/callbacks_models.rb +95 -1
  135. data/spec/integration/callbacks_spec.rb +226 -4
  136. data/spec/integration/criteria/range_spec.rb +95 -1
  137. data/spec/integration/discriminator_key_spec.rb +115 -76
  138. data/spec/integration/dots_and_dollars_spec.rb +277 -0
  139. data/spec/integration/i18n_fallbacks_spec.rb +1 -15
  140. data/spec/integration/matcher_examples_spec.rb +20 -13
  141. data/spec/integration/matcher_operator_data/type_decimal.yml +3 -2
  142. data/spec/integration/matcher_operator_spec.rb +3 -5
  143. data/spec/integration/persistence/range_field_spec.rb +350 -0
  144. data/spec/mongoid/association/counter_cache_spec.rb +1 -1
  145. data/spec/mongoid/association/depending_spec.rb +9 -9
  146. data/spec/mongoid/association/eager_spec.rb +2 -1
  147. data/spec/mongoid/association/embedded/embedded_in/binding_spec.rb +2 -1
  148. data/spec/mongoid/association/embedded/embedded_in/buildable_spec.rb +54 -0
  149. data/spec/mongoid/association/embedded/embedded_in/proxy_spec.rb +69 -9
  150. data/spec/mongoid/association/embedded/embeds_many/buildable_spec.rb +112 -0
  151. data/spec/mongoid/association/embedded/embeds_many/proxy_spec.rb +198 -8
  152. data/spec/mongoid/association/embedded/embeds_many_models.rb +36 -0
  153. data/spec/mongoid/association/embedded/embeds_many_query_spec.rb +12 -0
  154. data/spec/mongoid/association/embedded/embeds_many_spec.rb +68 -0
  155. data/spec/mongoid/association/embedded/embeds_one/buildable_spec.rb +25 -0
  156. data/spec/mongoid/association/embedded/embeds_one_models.rb +19 -0
  157. data/spec/mongoid/association/embedded/embeds_one_spec.rb +28 -0
  158. data/spec/mongoid/association/referenced/belongs_to/binding_spec.rb +2 -1
  159. data/spec/mongoid/association/referenced/belongs_to/buildable_spec.rb +54 -0
  160. data/spec/mongoid/association/referenced/belongs_to/proxy_spec.rb +15 -0
  161. data/spec/mongoid/association/referenced/belongs_to_models.rb +11 -0
  162. data/spec/mongoid/association/referenced/belongs_to_spec.rb +2 -2
  163. data/spec/mongoid/association/referenced/has_and_belongs_to_many/proxy_spec.rb +38 -5
  164. data/spec/mongoid/association/referenced/has_and_belongs_to_many_models.rb +25 -0
  165. data/spec/mongoid/association/referenced/has_and_belongs_to_many_spec.rb +35 -2
  166. data/spec/mongoid/association/referenced/has_many/buildable_spec.rb +109 -0
  167. data/spec/mongoid/association/referenced/has_many/enumerable_spec.rb +2 -56
  168. data/spec/mongoid/association/referenced/has_many/proxy_spec.rb +62 -13
  169. data/spec/mongoid/association/referenced/has_many_models.rb +3 -1
  170. data/spec/mongoid/association/referenced/has_many_spec.rb +25 -0
  171. data/spec/mongoid/association/referenced/has_one/buildable_spec.rb +2 -2
  172. data/spec/mongoid/association/referenced/has_one/proxy_spec.rb +107 -1
  173. data/spec/mongoid/association/referenced/has_one_models.rb +16 -0
  174. data/spec/mongoid/association/syncable_spec.rb +14 -0
  175. data/spec/mongoid/atomic/paths_spec.rb +0 -14
  176. data/spec/mongoid/attributes/nested_spec.rb +80 -11
  177. data/spec/mongoid/attributes/nested_spec_models.rb +48 -0
  178. data/spec/mongoid/attributes/projector_spec.rb +1 -5
  179. data/spec/mongoid/attributes_spec.rb +480 -27
  180. data/spec/mongoid/cacheable_spec.rb +3 -3
  181. data/spec/mongoid/changeable_spec.rb +130 -13
  182. data/spec/mongoid/clients/factory_spec.rb +23 -30
  183. data/spec/mongoid/clients/sessions_spec.rb +0 -38
  184. data/spec/mongoid/clients_spec.rb +2 -2
  185. data/spec/mongoid/config_spec.rb +52 -14
  186. data/spec/mongoid/contextual/aggregable/memory_spec.rb +396 -158
  187. data/spec/mongoid/contextual/aggregable/memory_table.yml +88 -0
  188. data/spec/mongoid/contextual/aggregable/memory_table_spec.rb +62 -0
  189. data/spec/mongoid/contextual/map_reduce_spec.rb +2 -16
  190. data/spec/mongoid/contextual/memory_spec.rb +521 -14
  191. data/spec/mongoid/contextual/mongo_spec.rb +566 -416
  192. data/spec/mongoid/contextual/none_spec.rb +11 -19
  193. data/spec/mongoid/copyable_spec.rb +451 -1
  194. data/spec/mongoid/criteria/findable_spec.rb +86 -210
  195. data/spec/mongoid/criteria/includable_spec.rb +1492 -0
  196. data/spec/mongoid/criteria/includable_spec_models.rb +54 -0
  197. data/spec/mongoid/criteria/marshalable_spec.rb +18 -1
  198. data/spec/mongoid/criteria/queryable/extensions/array_spec.rb +7 -19
  199. data/spec/mongoid/criteria/queryable/extensions/big_decimal_spec.rb +134 -26
  200. data/spec/mongoid/criteria/queryable/extensions/date_spec.rb +11 -0
  201. data/spec/mongoid/criteria/queryable/extensions/date_time_spec.rb +11 -0
  202. data/spec/mongoid/criteria/queryable/extensions/hash_spec.rb +0 -15
  203. data/spec/mongoid/criteria/queryable/extensions/numeric_spec.rb +73 -7
  204. data/spec/mongoid/criteria/queryable/extensions/time_spec.rb +11 -0
  205. data/spec/mongoid/criteria/queryable/extensions/time_with_zone_spec.rb +11 -0
  206. data/spec/mongoid/criteria/queryable/optional_spec.rb +0 -484
  207. data/spec/mongoid/criteria/queryable/selectable_logical_spec.rb +50 -0
  208. data/spec/mongoid/criteria/queryable/selectable_spec.rb +77 -85
  209. data/spec/mongoid/criteria/queryable/selector_spec.rb +14 -2
  210. data/spec/mongoid/criteria_spec.rb +469 -1201
  211. data/spec/mongoid/document_fields_spec.rb +173 -24
  212. data/spec/mongoid/document_spec.rb +32 -41
  213. data/spec/mongoid/equality_spec.rb +12 -12
  214. data/spec/mongoid/errors/document_not_found_spec.rb +29 -2
  215. data/spec/mongoid/errors/invalid_field_spec.rb +1 -1
  216. data/spec/mongoid/errors/invalid_field_type_spec.rb +55 -0
  217. data/spec/mongoid/errors/mongoid_error_spec.rb +3 -1
  218. data/spec/mongoid/errors/no_environment_spec.rb +3 -3
  219. data/spec/mongoid/errors/too_many_nested_attribute_records_spec.rb +1 -1
  220. data/spec/mongoid/extensions/array_spec.rb +16 -2
  221. data/spec/mongoid/extensions/big_decimal_spec.rb +697 -212
  222. data/spec/mongoid/extensions/binary_spec.rb +44 -9
  223. data/spec/mongoid/extensions/boolean_spec.rb +68 -82
  224. data/spec/mongoid/extensions/date_class_mongoize_spec.rb +7 -3
  225. data/spec/mongoid/extensions/date_spec.rb +71 -1
  226. data/spec/mongoid/extensions/date_time_spec.rb +15 -9
  227. data/spec/mongoid/extensions/float_spec.rb +48 -76
  228. data/spec/mongoid/extensions/hash_spec.rb +30 -0
  229. data/spec/mongoid/extensions/integer_spec.rb +45 -66
  230. data/spec/mongoid/extensions/range_spec.rb +255 -54
  231. data/spec/mongoid/extensions/regexp_spec.rb +58 -33
  232. data/spec/mongoid/extensions/set_spec.rb +106 -0
  233. data/spec/mongoid/extensions/string_spec.rb +53 -25
  234. data/spec/mongoid/extensions/symbol_spec.rb +18 -25
  235. data/spec/mongoid/extensions/time_spec.rb +634 -66
  236. data/spec/mongoid/extensions/time_with_zone_spec.rb +17 -31
  237. data/spec/mongoid/factory_spec.rb +61 -1
  238. data/spec/mongoid/fields_spec.rb +321 -50
  239. data/spec/mongoid/findable_spec.rb +64 -29
  240. data/spec/mongoid/indexable/specification_spec.rb +2 -2
  241. data/spec/mongoid/indexable_spec.rb +16 -19
  242. data/spec/mongoid/interceptable_spec.rb +584 -5
  243. data/spec/mongoid/interceptable_spec_models.rb +235 -4
  244. data/spec/mongoid/matcher/extract_attribute_spec.rb +1 -5
  245. data/spec/mongoid/mongoizable_spec.rb +285 -0
  246. data/spec/mongoid/persistable/creatable_spec.rb +2 -2
  247. data/spec/mongoid/persistable/deletable_spec.rb +2 -2
  248. data/spec/mongoid/persistable/destroyable_spec.rb +2 -2
  249. data/spec/mongoid/persistable/upsertable_spec.rb +14 -0
  250. data/spec/mongoid/persistence_context_spec.rb +24 -0
  251. data/spec/mongoid/query_cache_middleware_spec.rb +0 -18
  252. data/spec/mongoid/query_cache_spec.rb +0 -154
  253. data/spec/mongoid/reloadable_spec.rb +35 -2
  254. data/spec/mongoid/scopable_spec.rb +36 -34
  255. data/spec/mongoid/shardable_models.rb +0 -14
  256. data/spec/mongoid/shardable_spec.rb +61 -153
  257. data/spec/mongoid/stateful_spec.rb +28 -0
  258. data/spec/mongoid/timestamps_spec.rb +390 -0
  259. data/spec/mongoid/timestamps_spec_models.rb +67 -0
  260. data/spec/mongoid/touchable_spec.rb +116 -0
  261. data/spec/mongoid/touchable_spec_models.rb +12 -8
  262. data/spec/mongoid/traversable_spec.rb +4 -11
  263. data/spec/mongoid/validatable/presence_spec.rb +1 -1
  264. data/spec/mongoid/validatable/uniqueness_spec.rb +60 -31
  265. data/spec/mongoid/warnings_spec.rb +35 -0
  266. data/spec/mongoid_spec.rb +1 -7
  267. data/spec/rails/controller_extension/controller_runtime_spec.rb +2 -2
  268. data/spec/rails/mongoid_spec.rb +4 -16
  269. data/spec/shared/lib/mrss/event_subscriber.rb +5 -15
  270. data/spec/shared/lib/mrss/lite_constraints.rb +0 -8
  271. data/spec/shared/shlib/server.sh +5 -5
  272. data/spec/support/constraints.rb +24 -0
  273. data/spec/support/macros.rb +30 -0
  274. data/spec/support/models/augmentation.rb +12 -0
  275. data/spec/support/models/band.rb +3 -0
  276. data/spec/support/models/catalog.rb +24 -0
  277. data/spec/support/models/circus.rb +3 -0
  278. data/spec/support/models/fanatic.rb +8 -0
  279. data/spec/support/models/implant.rb +9 -0
  280. data/spec/support/models/label.rb +2 -0
  281. data/spec/support/models/passport.rb +9 -0
  282. data/spec/support/models/person.rb +1 -0
  283. data/spec/support/models/player.rb +2 -0
  284. data/spec/support/models/powerup.rb +12 -0
  285. data/spec/support/models/registry.rb +1 -0
  286. data/spec/support/models/school.rb +14 -0
  287. data/spec/support/models/shield.rb +18 -0
  288. data/spec/support/models/student.rb +14 -0
  289. data/spec/support/models/weapon.rb +12 -0
  290. data.tar.gz.sig +0 -0
  291. metadata +669 -638
  292. metadata.gz.sig +0 -0
  293. data/lib/mongoid/errors/eager_load.rb +0 -23
  294. data/lib/mongoid/errors/invalid_value.rb +0 -17
  295. data/spec/mongoid/errors/eager_load_spec.rb +0 -31
@@ -10,7 +10,11 @@ module Mongoid
10
10
  # the exception of the document's id, and will reset all the
11
11
  # instance variables.
12
12
  #
13
- # This clone also includes embedded documents.
13
+ # This clone also includes embedded documents. If there is an _id field in
14
+ # the embedded document, it will be maintained, unlike the root's _id.
15
+ #
16
+ # If cloning an embedded child, the embedded parent is not cloned and the
17
+ # embedded_in association is not set.
14
18
  #
15
19
  # @example Clone the document.
16
20
  # document.clone
@@ -19,19 +23,42 @@ module Mongoid
19
23
  def clone
20
24
  # @note This next line is here to address #2704, even though having an
21
25
  # _id and id field in the document would cause problems with Mongoid
22
- # elsewhere.
26
+ # elsewhere. Note this is only done on the root document as we want
27
+ # to maintain the same _id on the embedded documents.
23
28
  attrs = clone_document.except(*self.class.id_fields)
29
+ Copyable.clone_with_hash(self.class, attrs)
30
+ end
31
+ alias :dup :clone
32
+
33
+ private
34
+
35
+ # Create clone of a document of the given klass with the given attributes
36
+ # hash. This is used recursively so that embedded associations are cloned
37
+ # safely.
38
+ #
39
+ # @param klass [ Class ] The class of the document to create.
40
+ # @param attrs [ Hash ] The hash of the attributes.
41
+ #
42
+ # @return [ Document ] The new document.
43
+ def self.clone_with_hash(klass, attrs)
24
44
  dynamic_attrs = {}
25
- _attribute_names = self.attribute_names
45
+ _attribute_names = klass.attribute_names
26
46
  attrs.reject! do |attr_name, value|
27
47
  unless _attribute_names.include?(attr_name)
28
48
  dynamic_attrs[attr_name] = value
29
49
  true
30
50
  end
31
51
  end
32
- self.class.new(attrs).tap do |object|
52
+
53
+ Factory.build(klass, attrs).tap do |object|
33
54
  dynamic_attrs.each do |attr_name, value|
34
- if object.respond_to?("#{attr_name}=")
55
+ assoc = object.embedded_relations[attr_name]
56
+ if assoc&.one? && Hash === value
57
+ object.send("#{attr_name}=", clone_with_hash(assoc.klass, value))
58
+ elsif assoc&.many? && Array === value
59
+ docs = value.map { |h| clone_with_hash(assoc.klass, h) }
60
+ object.send("#{attr_name}=", docs)
61
+ elsif object.respond_to?("#{attr_name}=")
35
62
  object.send("#{attr_name}=", value)
36
63
  else
37
64
  object.attributes[attr_name] = value
@@ -39,9 +66,6 @@ module Mongoid
39
66
  end
40
67
  end
41
68
  end
42
- alias :dup :clone
43
-
44
- private
45
69
 
46
70
  # Clone the document attributes
47
71
  #
@@ -26,15 +26,12 @@ module Mongoid
26
26
  #
27
27
  # @return [ Criteria ] The cloned criteria.
28
28
  def includes(*relations)
29
- extract_includes_list(klass, relations)
29
+ extract_includes_list(klass, nil, relations)
30
30
  clone
31
31
  end
32
32
 
33
33
  # Get a list of criteria that are to be executed for eager loading.
34
34
  #
35
- # @example Get the eager loading inclusions.
36
- # Person.includes(:game).inclusions
37
- #
38
35
  # @return [ Array<Association> ] The inclusions.
39
36
  def inclusions
40
37
  @inclusions ||= []
@@ -42,9 +39,6 @@ module Mongoid
42
39
 
43
40
  # Set the inclusions for the criteria.
44
41
  #
45
- # @example Set the inclusions.
46
- # criteria.inclusions = [ association ]
47
- #
48
42
  # @param [ Array<Association> ] value The inclusions.
49
43
  #
50
44
  # @return [ Array<Association> ] The new inclusions.
@@ -56,30 +50,40 @@ module Mongoid
56
50
 
57
51
  # Add an inclusion definition to the list of inclusions for the criteria.
58
52
  #
59
- # @example Add an inclusion.
60
- # criteria.add_inclusion(Person, :posts)
61
- #
62
- # @param [ Class, String, Symbol ] _klass The class or string/symbol of the class name.
63
- # @param [ Symbol ] association The association.
64
- #
65
- # @raise [ Errors::InvalidIncludes ] If no association is found.
66
- def add_inclusion(_klass, association)
67
- inclusions.push(association) unless inclusions.include?(association)
53
+ # @param [ Association ] association The association.
54
+ # @param [ String ] parent The name of the association above this one in
55
+ # the inclusion tree, if it is a nested inclusion.
56
+ def add_inclusion(association, parent = nil)
57
+ if assoc = inclusions.detect { |a| a == association }
58
+ assoc.parent_inclusions.push(parent) if parent
59
+ else
60
+ assoc = association.dup
61
+ assoc.parent_inclusions = []
62
+ assoc.parent_inclusions.push(parent) if parent
63
+ inclusions.push(assoc)
64
+ end
68
65
  end
69
66
 
70
- def extract_includes_list(_parent_class, *relations_list)
67
+ # Iterate through the list of relations and create the inclusions list.
68
+ #
69
+ # @param [ Class, String, Symbol ] _parent_class The class from which the
70
+ # association originates.
71
+ # @param [ String ] parent The name of the association above this one in
72
+ # the inclusion tree, if it is a nested inclusion.
73
+ # @param relations_list The names of the associations to eager load.
74
+ def extract_includes_list(_parent_class, parent, *relations_list)
71
75
  relations_list.flatten.each do |relation_object|
72
76
  if relation_object.is_a?(Hash)
73
77
  relation_object.each do |relation, _includes|
74
78
  association = _parent_class.reflect_on_association(relation)
75
79
  raise Errors::InvalidIncludes.new(_klass, [ relation ]) unless association
76
- add_inclusion(_parent_class, association)
77
- extract_includes_list(association.klass, _includes)
80
+ add_inclusion(association, parent)
81
+ extract_includes_list(association.klass, association.name, _includes)
78
82
  end
79
83
  else
80
84
  association = _parent_class.reflect_on_association(relation_object)
81
85
  raise Errors::InvalidIncludes.new(_parent_class, [ relation_object ]) unless association
82
- add_inclusion(_parent_class, association)
86
+ add_inclusion(association, parent)
83
87
  end
84
88
  end
85
89
  end
@@ -9,9 +9,12 @@ module Mongoid
9
9
  # @example Dump the criteria.
10
10
  # Marshal.dump(criteria)
11
11
  #
12
+ # Note :mongo is written here for backwards compatibility with Mongoid 7
13
+ # and earlier.
14
+ #
12
15
  # @return [ Array<Object> ] The dumped data.
13
16
  def marshal_dump
14
- data = [ klass, driver, inclusions, documents, strategy, negating ]
17
+ data = [ klass, :mongo, inclusions, documents, strategy, negating ]
15
18
  data.push(scoping_options).push(dump_hash(:selector)).push(dump_hash(:options))
16
19
  end
17
20
 
@@ -23,7 +26,12 @@ module Mongoid
23
26
  # @param [ Array ] data The raw data.
24
27
  def marshal_load(data)
25
28
  @scoping_options, raw_selector, raw_options = data.pop(3)
26
- @klass, @driver, @inclusions, @documents, @strategy, @negating = data
29
+ @klass, driver, @inclusions, @documents, @strategy, @negating = data
30
+
31
+ if driver == :mongo1x
32
+ raise NotImplementedError, "Mongoid no longer supports marshalling with driver version 1.x."
33
+ end
34
+
27
35
  @selector = load_hash(Queryable::Selector, raw_selector)
28
36
  @options = load_hash(Queryable::Options, raw_options)
29
37
  end
@@ -108,20 +108,6 @@ module Mongoid
108
108
  { first => last.to_direction }
109
109
  end
110
110
 
111
- # Update all the values in the hash with the provided block.
112
- #
113
- # @example Update the values in place.
114
- # [ 1, 2, 3 ].update_values(&:to_s)
115
- #
116
- # @param [ Proc ] block The block to execute on each value.
117
- #
118
- # @return [ Array ] the array.
119
- #
120
- # @deprecated
121
- def update_values(&block)
122
- replace(map(&block))
123
- end
124
-
125
111
  private
126
112
 
127
113
  # Converts the array to a multi-dimensional array.
@@ -147,7 +133,8 @@ module Mongoid
147
133
  #
148
134
  # @return [ Object ] The evolved object.
149
135
  def evolve(object)
150
- if object.is_a?(::Array)
136
+ case object
137
+ when ::Array, ::Set
151
138
  object.map { |obj| obj.class.evolve(obj) }
152
139
  else
153
140
  object
@@ -12,18 +12,39 @@ module Mongoid
12
12
  module BigDecimal
13
13
  module ClassMethods
14
14
 
15
- # Evolves the big decimal into a MongoDB friendly value - in this case
16
- # a string.
15
+ # Evolves the big decimal into a MongoDB friendly value.
17
16
  #
18
17
  # @example Evolve the big decimal
19
18
  # BigDecimal.evolve(decimal)
20
19
  #
21
20
  # @param [ BigDecimal ] object The object to convert.
22
21
  #
23
- # @return [ String ] The big decimal as a string.
22
+ # @return [ Object ] The big decimal as a string, a Decimal128,
23
+ # or the inputted object if it is uncastable.
24
24
  def evolve(object)
25
25
  __evolve__(object) do |obj|
26
- obj ? obj.to_s : obj
26
+ return if obj.nil?
27
+ case obj
28
+ when ::BigDecimal
29
+ if Mongoid.map_big_decimal_to_decimal128
30
+ BSON::Decimal128.new(obj)
31
+ else
32
+ obj.to_s
33
+ end
34
+ # Always return on string for backwards compatibility with querying
35
+ # string-backed BigDecimal fields.
36
+ when BSON::Decimal128, String then obj
37
+ else
38
+ if obj.numeric?
39
+ if Mongoid.map_big_decimal_to_decimal128
40
+ BSON::Decimal128.new(object.to_s)
41
+ else
42
+ obj.to_s
43
+ end
44
+ else
45
+ obj
46
+ end
47
+ end
27
48
  end
28
49
  end
29
50
  end
@@ -20,7 +20,7 @@ module Mongoid
20
20
  # @return [ true, false ] The boolean value.
21
21
  def evolve(object)
22
22
  __evolve__(object) do |obj|
23
- obj.to_s =~ (/\A(true|t|yes|y|on|1|1.0)\z/i) ? true : false
23
+ mongoize(obj)
24
24
  end
25
25
  end
26
26
  end
@@ -45,7 +45,12 @@ module Mongoid
45
45
  #
46
46
  # @return [ Time ] The evolved date.
47
47
  def evolve(object)
48
- object.__evolve_date__
48
+ res = begin
49
+ object.try(:__evolve_date__)
50
+ rescue ArgumentError
51
+ nil
52
+ end
53
+ res.nil? ? object : res
49
54
  end
50
55
  end
51
56
  end
@@ -34,7 +34,12 @@ module Mongoid
34
34
  #
35
35
  # @return [ Time ] The evolved date time.
36
36
  def evolve(object)
37
- object.__evolve_time__
37
+ res = begin
38
+ object.try(:__evolve_time__)
39
+ rescue ArgumentError
40
+ nil
41
+ end
42
+ res.nil? ? object : res
38
43
  end
39
44
  end
40
45
  end
@@ -134,22 +134,6 @@ module Mongoid
134
134
  replacement
135
135
  end
136
136
 
137
- # Update all the values in the hash with the provided block.
138
- #
139
- # @example Update the values in place.
140
- # { field: "1" }.update_values(&:to_i)
141
- #
142
- # @param [ Proc ] block The block to execute on each value.
143
- #
144
- # @return [ Hash ] the hash.
145
- #
146
- # @deprecated
147
- def update_values(&block)
148
- each_pair do |key, value|
149
- store(key, block[value])
150
- end
151
- end
152
-
153
137
  private
154
138
 
155
139
  # Apply the provided strategy for the hash with the given object.
@@ -51,7 +51,7 @@ module Mongoid
51
51
  #
52
52
  # @return [ Object ] The converted number.
53
53
  def __numeric__(object)
54
- object.to_s =~ /(\A[-+]?[0-9]+\z)|(\.0+\z)|(\.\z)/ ? object.to_i : Float(object)
54
+ object.to_s.match?(/\A[-+]?[0-9]*[0-9.]0*\z/) ? object.to_i : Float(object)
55
55
  end
56
56
 
57
57
  # Evolve the object to an integer.
@@ -167,7 +167,8 @@ module Mongoid
167
167
  when ::Range
168
168
  object.__evolve_range__
169
169
  else
170
- yield(object)
170
+ res = yield(object)
171
+ res.nil? ? object : res
171
172
  end
172
173
  end
173
174
  end
@@ -43,13 +43,21 @@ module Mongoid
43
43
  # @example Evolve the range.
44
44
  # (11231312..213123131).__evolve_range__
45
45
  #
46
+ # @param [ Object ] serializer The optional serializer for the field.
47
+ #
46
48
  # @return [ Hash ] The $gte/$lte range query.
47
- def __evolve_range__
49
+ #
50
+ # @api private
51
+ def __evolve_range__(serializer: nil)
48
52
  __evolve_range_naive__.transform_values! do |value|
49
- case value
50
- when Time, DateTime then value.__evolve_time__
51
- when Date then value.__evolve_date__
52
- else value
53
+ if serializer
54
+ serializer.evolve(value)
55
+ else
56
+ case value
57
+ when Time, DateTime then value.__evolve_time__
58
+ when Date then value.__evolve_date__
59
+ else value
60
+ end
53
61
  end
54
62
  end
55
63
  end
@@ -28,7 +28,7 @@ module Mongoid
28
28
  # @return [ Regexp ] The evolved regex.
29
29
  def evolve(object)
30
30
  __evolve__(object) do |obj|
31
- ::Regexp.new(obj)
31
+ mongoize(obj)
32
32
  end
33
33
  end
34
34
  end
@@ -59,7 +59,9 @@ module Mongoid
59
59
  #
60
60
  # @return [ Symbol ] The value as a symbol.
61
61
  def evolve(object)
62
- __evolve__(object) { |obj| obj.to_sym }
62
+ __evolve__(object) do |obj|
63
+ obj.try(:to_sym)
64
+ end
63
65
  end
64
66
  end
65
67
  end
@@ -42,7 +42,12 @@ module Mongoid
42
42
  #
43
43
  # @return [ Time ] The evolved date time.
44
44
  def evolve(object)
45
- object.__evolve_time__
45
+ res = begin
46
+ object.try(:__evolve_time__)
47
+ rescue ArgumentError
48
+ nil
49
+ end
50
+ res.nil? ? object : res
46
51
  end
47
52
  end
48
53
  end
@@ -42,7 +42,12 @@ module Mongoid
42
42
  #
43
43
  # @return [ Time ] The evolved date time.
44
44
  def evolve(object)
45
- object.__evolve_time__
45
+ res = begin
46
+ object.try(:__evolve_time__)
47
+ rescue ArgumentError
48
+ nil
49
+ end
50
+ res.nil? ? object : res
46
51
  end
47
52
  end
48
53
  end
@@ -318,15 +318,9 @@ module Mongoid
318
318
  #
319
319
  # @return [ Optional ] The cloned optional.
320
320
  def add_sort_option(options, field, direction)
321
- if driver == :mongo1x
322
- sorting = (options[:sort] || []).dup
323
- sorting.push([ field, direction ])
324
- options.store(:sort, sorting)
325
- else
326
- sorting = (options[:sort] || {}).dup
327
- sorting[field] = direction
328
- options.store(:sort, sorting)
329
- end
321
+ sorting = (options[:sort] || {}).dup
322
+ sorting[field] = direction
323
+ options.store(:sort, sorting)
330
324
  end
331
325
 
332
326
  # Take the provided criterion and store it as an option in the query
@@ -84,7 +84,7 @@ module Mongoid
84
84
  #
85
85
  # @return [ Options ] The copied options.
86
86
  def __deep_copy__
87
- self.class.new(aliases, serializers) do |copy|
87
+ self.class.new(aliases, serializers, associations, aliased_associations) do |copy|
88
88
  each_pair do |key, value|
89
89
  copy.merge!(key => value.__deep_copy__)
90
90
  end
@@ -227,19 +227,6 @@ module Mongoid
227
227
  __merge__(criterion)
228
228
  end
229
229
 
230
- # Alias for +geo_spatial+.
231
- #
232
- # @deprecated
233
- def geo_spacial(criterion)
234
- # Duplicate method body so that we can raise this exception with
235
- # geo_spacial as the indicated operator rather than geo_spatial.
236
- if criterion.nil?
237
- raise Errors::CriteriaArgumentRequired, :geo_spacial
238
- end
239
-
240
- __merge__(criterion)
241
- end
242
-
243
230
  key :intersects_line, :override, "$geoIntersects", "$geometry" do |value|
244
231
  { "type" => LINE_STRING, "coordinates" => value }
245
232
  end
@@ -679,16 +666,7 @@ module Mongoid
679
666
  end]
680
667
  end
681
668
  end
682
- # Should be able to do:
683
- #where('$or' => exprs)
684
- # But since that is broken do instead:
685
- clone.tap do |query|
686
- if query.selector['$or']
687
- query.selector.store('$or', query.selector['$or'] + exprs)
688
- else
689
- query.selector.store('$or', exprs)
690
- end
691
- end
669
+ self.and('$or' => exprs)
692
670
  end
693
671
  end
694
672
 
@@ -874,7 +852,7 @@ module Mongoid
874
852
  # @param [ Hash ] criterion The criterion.
875
853
  def typed_override(criterion, operator)
876
854
  if criterion
877
- criterion.update_values do |value|
855
+ criterion.transform_values! do |value|
878
856
  yield(value)
879
857
  end
880
858
  end
@@ -53,8 +53,7 @@ module Mongoid
53
53
  store_name = name
54
54
  store_value = evolve_multi(value)
55
55
  else
56
- store_name = localized_key(name, serializer)
57
- store_value = evolve(serializer, value)
56
+ store_name, store_value = store_creds(name, serializer, value)
58
57
  end
59
58
  super(store_name, store_value)
60
59
  end
@@ -74,6 +73,24 @@ module Mongoid
74
73
 
75
74
  private
76
75
 
76
+ # Get the store name and store value. If the value is of type range,
77
+ # we need may need to change the store_name as well as the store_value,
78
+ # therefore, we cannot just use the evole method.
79
+ #
80
+ # @param [ String ] name The name of the field.
81
+ # @param [ Object ] serializer The optional serializer for the field.
82
+ # @param [ Object ] value The value to serialize.
83
+ #
84
+ # @return [ Array<String, String> ] The store name and store value.
85
+ def store_creds(name, serializer, value)
86
+ store_name = localized_key(name, serializer)
87
+ if Range === value
88
+ evolve_range(store_name, serializer, value)
89
+ else
90
+ [ store_name, evolve(serializer, value) ]
91
+ end
92
+ end
93
+
77
94
  # Evolves a multi-list selection, like an $and or $or criterion, and
78
95
  # performs the necessary serialization.
79
96
  #
@@ -103,11 +120,10 @@ module Mongoid
103
120
  # some reason, although per its documentation Smash supposedly
104
121
  # owns both.
105
122
  name, serializer = storage_pair(key)
106
- final_key = localized_key(name, serializer)
107
123
  # This performs type conversions on the value and transformations
108
124
  # that depend on the type of the field that the value is stored
109
125
  # in, but not transformations that have to do with query shape.
110
- evolved_value = evolve(serializer, value)
126
+ final_key, evolved_value = store_creds(name, serializer, value)
111
127
 
112
128
  # This builds a query shape around the value, when the query
113
129
  # involves complex keys. For example, {:foo.lt => 5} produces
@@ -139,6 +155,8 @@ module Mongoid
139
155
  evolve_hash(serializer, value)
140
156
  when Array
141
157
  evolve_array(serializer, value)
158
+ when Range
159
+ value.__evolve_range__(serializer: serializer)
142
160
  else
143
161
  (serializer || value.class).evolve(value)
144
162
  end
@@ -182,6 +200,73 @@ module Mongoid
182
200
  end
183
201
  end
184
202
 
203
+ # Evolve a single key selection with range values. This method traverses
204
+ # the association tree to build a query for the given value and
205
+ # serializer. There are three parts to the query here:
206
+ #
207
+ # (1) "klass.child.gchild" => {
208
+ # "$elemMatch" => {
209
+ # (2) "ggchild.field" => (3) { "$gte" => 6, "$lte" => 10 }
210
+ # }
211
+ # }
212
+ # (1) The first n fields are dotted together until the last
213
+ # embeds_many or field of type array. In the above case, gchild
214
+ # would be an embeds_many or Array, and ggchild would be an
215
+ # embeds_one or a hash.
216
+ # (2) The last fields are used inside the $elemMatch. This one is
217
+ # actually optional, and will be ignored if the last field is an
218
+ # array or embeds_many. If the last field is an array (1), (2) and
219
+ # (3) will look like:
220
+ #
221
+ # "klass.child.gchild.ggchild.field" => {
222
+ # { "$elemMatch" => { "$gte" => 6, "$lte" => 10 } }
223
+ # }
224
+ #
225
+ # (3) This is calculated by:
226
+ #
227
+ # value.__evolve_range__(serializer: serializer).
228
+ #
229
+ # @api private
230
+ #
231
+ # @param [ String ] key The to store the range for.
232
+ # @param [ Object ] serializer The optional serializer for the field.
233
+ # @param [ Range ] value The Range to serialize.
234
+ #
235
+ # @return [ Array<String, Hash> ] The store name and serialized Range.
236
+ def evolve_range(key, serializer, value)
237
+ v = value.__evolve_range__(serializer: serializer)
238
+ assocs = []
239
+ Fields.traverse_association_tree(key, serializers, associations, aliased_associations) do |meth, obj, is_field|
240
+ assocs.push([meth, obj, is_field])
241
+ end
242
+
243
+ # Iterate backwards until you get a field with type
244
+ # Array or an embeds_many association.
245
+ inner_key = ""
246
+ loop do
247
+ # If there are no arrays or embeds_many associations, just return
248
+ # the key and value without $elemMatch.
249
+ return [ key, v ] if assocs.empty?
250
+
251
+ meth, obj, is_field = assocs.last
252
+ break if (is_field && obj.type == Array) || (!is_field && obj.is_a?(Association::Embedded::EmbedsMany))
253
+
254
+ assocs.pop
255
+ inner_key = "#{meth}.#{inner_key}"
256
+ end
257
+
258
+ # If the last array or embeds_many association is the last field,
259
+ # the inner key (2) is ignored, and the outer key (1) is the original
260
+ # key.
261
+ if inner_key.blank?
262
+ [ key, { "$elemMatch" => v }]
263
+ else
264
+ store_key = assocs.map(&:first).join('.')
265
+ store_value = { "$elemMatch" => { inner_key.chop => v } }
266
+ [ store_key, store_value ]
267
+ end
268
+ end
269
+
185
270
  # Determines if the selection is a multi-select, like an $and or $or or $nor
186
271
  # selection.
187
272
  #