mongoid 5.4.1 → 6.0.0.beta

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 (264) hide show
  1. checksums.yaml +5 -5
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/lib/config/locales/en.yml +23 -16
  5. data/lib/mongoid.rb +4 -9
  6. data/lib/mongoid/atomic.rb +1 -1
  7. data/lib/mongoid/atomic/modifiers.rb +8 -12
  8. data/lib/mongoid/attributes.rb +9 -11
  9. data/lib/mongoid/attributes/dynamic.rb +5 -6
  10. data/lib/mongoid/attributes/nested.rb +1 -1
  11. data/lib/mongoid/attributes/processing.rb +4 -0
  12. data/lib/mongoid/attributes/readonly.rb +22 -0
  13. data/lib/mongoid/cacheable.rb +36 -0
  14. data/lib/mongoid/changeable.rb +37 -1
  15. data/lib/mongoid/clients.rb +0 -63
  16. data/lib/mongoid/clients/factory.rb +0 -2
  17. data/lib/mongoid/clients/options.rb +54 -249
  18. data/lib/mongoid/clients/storage_options.rb +1 -69
  19. data/lib/mongoid/composable.rb +26 -2
  20. data/lib/mongoid/config.rb +1 -1
  21. data/lib/mongoid/config/options.rb +1 -1
  22. data/lib/mongoid/contextual/aggregable/mongo.rb +1 -0
  23. data/lib/mongoid/contextual/atomic.rb +6 -9
  24. data/lib/mongoid/contextual/geo_near.rb +2 -3
  25. data/lib/mongoid/contextual/map_reduce.rb +97 -24
  26. data/lib/mongoid/contextual/memory.rb +7 -4
  27. data/lib/mongoid/contextual/mongo.rb +63 -54
  28. data/lib/mongoid/contextual/none.rb +2 -2
  29. data/lib/mongoid/copyable.rb +19 -19
  30. data/lib/mongoid/criteria.rb +5 -4
  31. data/lib/mongoid/criteria/findable.rb +2 -3
  32. data/lib/mongoid/criteria/includable.rb +63 -16
  33. data/lib/mongoid/criteria/marshalable.rb +2 -2
  34. data/lib/mongoid/criteria/modifiable.rb +17 -1
  35. data/lib/mongoid/criteria/options.rb +25 -0
  36. data/lib/mongoid/criteria/queryable.rb +86 -0
  37. data/lib/mongoid/criteria/queryable/aggregable.rb +120 -0
  38. data/lib/mongoid/criteria/queryable/extensions.rb +28 -0
  39. data/lib/mongoid/criteria/queryable/extensions/array.rb +185 -0
  40. data/lib/mongoid/criteria/queryable/extensions/big_decimal.rb +37 -0
  41. data/lib/mongoid/criteria/queryable/extensions/boolean.rb +34 -0
  42. data/lib/mongoid/criteria/queryable/extensions/date.rb +63 -0
  43. data/lib/mongoid/criteria/queryable/extensions/date_time.rb +53 -0
  44. data/lib/mongoid/criteria/queryable/extensions/hash.rb +200 -0
  45. data/lib/mongoid/criteria/queryable/extensions/nil_class.rb +86 -0
  46. data/lib/mongoid/criteria/queryable/extensions/numeric.rb +90 -0
  47. data/lib/mongoid/criteria/queryable/extensions/object.rb +206 -0
  48. data/lib/mongoid/criteria/queryable/extensions/range.rb +70 -0
  49. data/lib/mongoid/criteria/queryable/extensions/regexp.rb +45 -0
  50. data/lib/mongoid/criteria/queryable/extensions/set.rb +34 -0
  51. data/lib/mongoid/criteria/queryable/extensions/string.rb +137 -0
  52. data/lib/mongoid/criteria/queryable/extensions/symbol.rb +79 -0
  53. data/lib/mongoid/criteria/queryable/extensions/time.rb +60 -0
  54. data/lib/mongoid/criteria/queryable/extensions/time_with_zone.rb +54 -0
  55. data/lib/mongoid/criteria/queryable/forwardable.rb +65 -0
  56. data/lib/mongoid/criteria/queryable/key.rb +103 -0
  57. data/lib/mongoid/criteria/queryable/macroable.rb +27 -0
  58. data/lib/mongoid/criteria/queryable/mergeable.rb +271 -0
  59. data/lib/mongoid/criteria/queryable/optional.rb +411 -0
  60. data/lib/mongoid/criteria/queryable/options.rb +136 -0
  61. data/lib/mongoid/criteria/queryable/pipeline.rb +111 -0
  62. data/lib/mongoid/criteria/queryable/selectable.rb +662 -0
  63. data/lib/mongoid/criteria/queryable/selector.rb +196 -0
  64. data/lib/mongoid/criteria/queryable/smash.rb +103 -0
  65. data/lib/mongoid/document.rb +9 -23
  66. data/lib/mongoid/errors.rb +2 -1
  67. data/lib/mongoid/errors/ambiguous_relationship.rb +1 -1
  68. data/lib/mongoid/errors/delete_restriction.rb +2 -2
  69. data/lib/mongoid/errors/invalid_field.rb +2 -2
  70. data/lib/mongoid/errors/invalid_persistence_option.rb +29 -0
  71. data/lib/mongoid/errors/invalid_relation.rb +66 -0
  72. data/lib/mongoid/errors/inverse_not_found.rb +1 -1
  73. data/lib/mongoid/errors/mongoid_error.rb +1 -1
  74. data/lib/mongoid/evolvable.rb +1 -1
  75. data/lib/mongoid/extensions.rb +0 -5
  76. data/lib/mongoid/extensions/big_decimal.rb +17 -8
  77. data/lib/mongoid/extensions/date.rb +4 -1
  78. data/lib/mongoid/extensions/hash.rb +2 -3
  79. data/lib/mongoid/extensions/object.rb +2 -2
  80. data/lib/mongoid/extensions/string.rb +4 -3
  81. data/lib/mongoid/extensions/time.rb +5 -2
  82. data/lib/mongoid/factory.rb +1 -0
  83. data/lib/mongoid/fields/foreign_key.rb +2 -2
  84. data/lib/mongoid/fields/localized.rb +3 -8
  85. data/lib/mongoid/fields/validators/macro.rb +18 -0
  86. data/lib/mongoid/findable.rb +3 -3
  87. data/lib/mongoid/indexable.rb +17 -16
  88. data/lib/mongoid/indexable/specification.rb +1 -1
  89. data/lib/mongoid/indexable/validators/options.rb +1 -2
  90. data/lib/mongoid/interceptable.rb +6 -17
  91. data/lib/mongoid/loggable.rb +1 -1
  92. data/lib/mongoid/matchable.rb +3 -10
  93. data/lib/mongoid/matchable/gt.rb +2 -0
  94. data/lib/mongoid/matchable/gte.rb +2 -0
  95. data/lib/mongoid/matchable/lt.rb +2 -0
  96. data/lib/mongoid/matchable/lte.rb +2 -0
  97. data/lib/mongoid/persistable.rb +6 -5
  98. data/lib/mongoid/persistable/creatable.rb +2 -0
  99. data/lib/mongoid/persistable/deletable.rb +7 -3
  100. data/lib/mongoid/persistable/settable.rb +3 -16
  101. data/lib/mongoid/persistable/updatable.rb +10 -12
  102. data/lib/mongoid/persistence_context.rb +216 -0
  103. data/lib/mongoid/query_cache.rb +5 -30
  104. data/lib/mongoid/relations/accessors.rb +6 -2
  105. data/lib/mongoid/relations/auto_save.rb +12 -4
  106. data/lib/mongoid/relations/bindings/embedded/in.rb +4 -0
  107. data/lib/mongoid/relations/bindings/embedded/many.rb +8 -1
  108. data/lib/mongoid/relations/bindings/embedded/one.rb +10 -0
  109. data/lib/mongoid/relations/bindings/referenced/many.rb +4 -0
  110. data/lib/mongoid/relations/builders.rb +2 -2
  111. data/lib/mongoid/relations/builders/embedded/one.rb +1 -1
  112. data/lib/mongoid/relations/builders/nested_attributes/many.rb +1 -1
  113. data/lib/mongoid/relations/conversions.rb +1 -1
  114. data/lib/mongoid/relations/counter_cache.rb +28 -18
  115. data/lib/mongoid/relations/eager.rb +19 -7
  116. data/lib/mongoid/relations/eager/base.rb +5 -5
  117. data/lib/mongoid/relations/embedded/batchable.rb +9 -33
  118. data/lib/mongoid/relations/embedded/in.rb +16 -2
  119. data/lib/mongoid/relations/embedded/many.rb +23 -8
  120. data/lib/mongoid/relations/embedded/one.rb +17 -2
  121. data/lib/mongoid/relations/macros.rb +9 -2
  122. data/lib/mongoid/relations/metadata.rb +3 -3
  123. data/lib/mongoid/relations/nested_builder.rb +1 -1
  124. data/lib/mongoid/relations/options.rb +2 -2
  125. data/lib/mongoid/relations/proxy.rb +2 -33
  126. data/lib/mongoid/relations/referenced/in.rb +23 -11
  127. data/lib/mongoid/relations/referenced/many.rb +24 -16
  128. data/lib/mongoid/relations/referenced/many_to_many.rb +20 -13
  129. data/lib/mongoid/relations/referenced/one.rb +17 -1
  130. data/lib/mongoid/relations/reflections.rb +3 -5
  131. data/lib/mongoid/relations/touchable.rb +1 -1
  132. data/lib/mongoid/reloadable.rb +1 -1
  133. data/lib/mongoid/scopable.rb +3 -3
  134. data/lib/mongoid/serializable.rb +2 -3
  135. data/lib/mongoid/tasks/database.rb +1 -2
  136. data/lib/mongoid/threaded.rb +4 -4
  137. data/lib/mongoid/traversable.rb +1 -1
  138. data/lib/mongoid/validatable.rb +1 -1
  139. data/lib/mongoid/validatable/macros.rb +2 -4
  140. data/lib/mongoid/validatable/uniqueness.rb +1 -2
  141. data/lib/mongoid/version.rb +1 -1
  142. data/lib/rails/generators/mongoid/config/templates/mongoid.yml +4 -7
  143. data/spec/app/models/album.rb +5 -1
  144. data/spec/app/models/artist.rb +21 -0
  145. data/spec/app/models/band.rb +0 -1
  146. data/spec/app/models/church.rb +0 -2
  147. data/spec/app/models/ordered_post.rb +5 -0
  148. data/spec/app/models/oscar.rb +1 -2
  149. data/spec/app/models/person.rb +3 -1
  150. data/spec/app/models/post.rb +0 -1
  151. data/spec/app/models/princess.rb +2 -0
  152. data/spec/app/models/record.rb +1 -0
  153. data/spec/app/models/thing.rb +1 -1
  154. data/spec/config/mongoid.yml +1 -5
  155. data/spec/mongoid/atomic/modifiers_spec.rb +17 -17
  156. data/spec/mongoid/atomic_spec.rb +17 -17
  157. data/spec/mongoid/attributes/nested_spec.rb +14 -14
  158. data/spec/mongoid/attributes/readonly_spec.rb +87 -44
  159. data/spec/mongoid/attributes_spec.rb +63 -0
  160. data/spec/mongoid/cacheable_spec.rb +112 -0
  161. data/spec/mongoid/changeable_spec.rb +58 -0
  162. data/spec/mongoid/clients/factory_spec.rb +3 -11
  163. data/spec/mongoid/clients/options_spec.rb +378 -96
  164. data/spec/mongoid/clients_spec.rb +207 -170
  165. data/spec/mongoid/composable_spec.rb +7 -0
  166. data/spec/mongoid/config_spec.rb +41 -21
  167. data/spec/mongoid/contextual/atomic_spec.rb +77 -343
  168. data/spec/mongoid/contextual/map_reduce_spec.rb +119 -111
  169. data/spec/mongoid/contextual/memory_spec.rb +56 -316
  170. data/spec/mongoid/contextual/mongo_spec.rb +104 -378
  171. data/spec/mongoid/copyable_spec.rb +8 -15
  172. data/spec/mongoid/criteria/modifiable_spec.rb +239 -7
  173. data/spec/mongoid/criteria/options_spec.rb +29 -0
  174. data/spec/mongoid/criteria/queryable/aggregable_spec.rb +370 -0
  175. data/spec/mongoid/criteria/queryable/extensions/array_spec.rb +523 -0
  176. data/spec/mongoid/criteria/queryable/extensions/big_decimal_spec.rb +59 -0
  177. data/spec/mongoid/criteria/queryable/extensions/bignum_spec.rb +58 -0
  178. data/spec/mongoid/criteria/queryable/extensions/boolean_spec.rb +213 -0
  179. data/spec/mongoid/criteria/queryable/extensions/date_spec.rb +330 -0
  180. data/spec/mongoid/criteria/queryable/extensions/date_time_spec.rb +405 -0
  181. data/spec/mongoid/criteria/queryable/extensions/fixnum_spec.rb +58 -0
  182. data/spec/mongoid/criteria/queryable/extensions/float_spec.rb +65 -0
  183. data/spec/mongoid/criteria/queryable/extensions/hash_spec.rb +327 -0
  184. data/spec/mongoid/criteria/queryable/extensions/integer_spec.rb +65 -0
  185. data/spec/mongoid/criteria/queryable/extensions/nil_class_spec.rb +77 -0
  186. data/spec/mongoid/criteria/queryable/extensions/object_spec.rb +108 -0
  187. data/spec/mongoid/criteria/queryable/extensions/range_spec.rb +309 -0
  188. data/spec/mongoid/{extensions/origin/regexp_raw_spec.rb → criteria/queryable/extensions/regexp_spec.rb} +21 -20
  189. data/spec/mongoid/criteria/queryable/extensions/set_spec.rb +39 -0
  190. data/spec/mongoid/criteria/queryable/extensions/string_spec.rb +302 -0
  191. data/spec/mongoid/criteria/queryable/extensions/symbol_spec.rb +167 -0
  192. data/spec/mongoid/criteria/queryable/extensions/time_spec.rb +376 -0
  193. data/spec/mongoid/criteria/queryable/extensions/time_with_zone_spec.rb +347 -0
  194. data/spec/mongoid/criteria/queryable/forwardable_spec.rb +87 -0
  195. data/spec/mongoid/criteria/queryable/key_spec.rb +52 -0
  196. data/spec/mongoid/criteria/queryable/mergeable_spec.rb +49 -0
  197. data/spec/mongoid/criteria/queryable/optional_spec.rb +1786 -0
  198. data/spec/mongoid/criteria/queryable/options_spec.rb +360 -0
  199. data/spec/mongoid/criteria/queryable/pipeline_spec.rb +200 -0
  200. data/spec/mongoid/criteria/queryable/queryable_spec.rb +137 -0
  201. data/spec/mongoid/criteria/queryable/selectable_spec.rb +4159 -0
  202. data/spec/mongoid/criteria/queryable/selector_spec.rb +778 -0
  203. data/spec/mongoid/criteria/queryable/smash_spec.rb +30 -0
  204. data/spec/mongoid/criteria_spec.rb +45 -63
  205. data/spec/mongoid/document_spec.rb +21 -88
  206. data/spec/mongoid/errors/invalid_relation_spec.rb +37 -0
  207. data/spec/mongoid/errors/mongoid_error_spec.rb +6 -3
  208. data/spec/mongoid/extensions/big_decimal_spec.rb +320 -18
  209. data/spec/mongoid/extensions/date_spec.rb +2 -6
  210. data/spec/mongoid/extensions/date_time_spec.rb +2 -6
  211. data/spec/mongoid/extensions/float_spec.rb +8 -1
  212. data/spec/mongoid/extensions/integer_spec.rb +8 -1
  213. data/spec/mongoid/extensions/object_spec.rb +11 -0
  214. data/spec/mongoid/extensions/string_spec.rb +21 -0
  215. data/spec/mongoid/extensions/time_spec.rb +4 -8
  216. data/spec/mongoid/extensions/time_with_zone_spec.rb +2 -6
  217. data/spec/mongoid/fields/localized_spec.rb +0 -91
  218. data/spec/mongoid/findable_spec.rb +46 -1
  219. data/spec/mongoid/indexable_spec.rb +6 -46
  220. data/spec/mongoid/interceptable_spec.rb +49 -10
  221. data/spec/mongoid/matchable/gt_spec.rb +11 -0
  222. data/spec/mongoid/matchable/gte_spec.rb +10 -0
  223. data/spec/mongoid/matchable/lt_spec.rb +11 -0
  224. data/spec/mongoid/matchable/lte_spec.rb +11 -0
  225. data/spec/mongoid/matchable_spec.rb +1 -51
  226. data/spec/mongoid/persistable/creatable_spec.rb +2 -2
  227. data/spec/mongoid/persistable/deletable_spec.rb +1 -1
  228. data/spec/mongoid/persistable/destroyable_spec.rb +6 -2
  229. data/spec/mongoid/persistable/savable_spec.rb +30 -30
  230. data/spec/mongoid/persistable/settable_spec.rb +0 -185
  231. data/spec/mongoid/persistable/updatable_spec.rb +166 -5
  232. data/spec/mongoid/persistence_context_spec.rb +654 -0
  233. data/spec/mongoid/positional_spec.rb +10 -10
  234. data/spec/mongoid/query_cache_spec.rb +89 -65
  235. data/spec/mongoid/relations/accessors_spec.rb +1 -1
  236. data/spec/mongoid/relations/auto_save_spec.rb +39 -6
  237. data/spec/mongoid/relations/builders_spec.rb +37 -10
  238. data/spec/mongoid/relations/counter_cache_spec.rb +64 -15
  239. data/spec/mongoid/relations/cyclic_spec.rb +0 -22
  240. data/spec/mongoid/relations/embedded/many_spec.rb +9 -41
  241. data/spec/mongoid/relations/embedded/one_spec.rb +2 -1
  242. data/spec/mongoid/relations/macros_spec.rb +395 -7
  243. data/spec/mongoid/relations/proxy_spec.rb +3 -1
  244. data/spec/mongoid/relations/referenced/in_spec.rb +41 -1
  245. data/spec/mongoid/relations/referenced/many_spec.rb +6 -29
  246. data/spec/mongoid/relations/referenced/many_to_many_spec.rb +6 -29
  247. data/spec/mongoid/relations/reflections_spec.rb +9 -9
  248. data/spec/mongoid/reloadable_spec.rb +51 -0
  249. data/spec/mongoid/scopable_spec.rb +0 -12
  250. data/spec/mongoid/serializable_spec.rb +0 -50
  251. data/spec/mongoid/validatable/presence_spec.rb +1 -1
  252. data/spec/mongoid/validatable/uniqueness_spec.rb +16 -9
  253. data/spec/mongoid/validatable_spec.rb +16 -0
  254. data/spec/spec_helper.rb +10 -10
  255. metadata +536 -479
  256. metadata.gz.sig +0 -0
  257. data/lib/mongoid/clients/thread_options.rb +0 -19
  258. data/lib/mongoid/errors/in_memory_collation_not_supported.rb +0 -20
  259. data/lib/mongoid/extensions/decimal128.rb +0 -39
  260. data/lib/mongoid/extensions/origin/regexp_raw.rb +0 -43
  261. data/lib/mongoid/matchable/regexp.rb +0 -27
  262. data/spec/app/models/post_genre.rb +0 -6
  263. data/spec/mongoid/extensions/decimal128_spec.rb +0 -44
  264. data/spec/mongoid/matchable/regexp_spec.rb +0 -59
@@ -57,7 +57,7 @@ module Mongoid
57
57
  # @example Allow pluck for null context.
58
58
  # context.pluck(:name)
59
59
  #
60
- # @param [ String, Symbol, Array ] args Field or fields to pluck.
60
+ # @param [ String, Symbol, Array ] field or fields to pluck.
61
61
  #
62
62
  # @return [ Array ] Emtpy Array
63
63
  def pluck(*args)
@@ -69,7 +69,7 @@ module Mongoid
69
69
  # @example Create the new context.
70
70
  # Null.new(criteria)
71
71
  #
72
- # @param [ Criteria ] criteria The criteria.
72
+ # @param [ Criteria ] The criteria.
73
73
  #
74
74
  # @since 4.0.0
75
75
  def initialize(criteria)
@@ -14,17 +14,26 @@ module Mongoid
14
14
  # @example Clone the document.
15
15
  # document.clone
16
16
  #
17
+ # @param [ Document ] other The document getting cloned.
18
+ #
17
19
  # @return [ Document ] The new document.
18
20
  def clone
19
21
  # @note This next line is here to address #2704, even though having an
20
22
  # _id and id field in the document would cause problems with Mongoid
21
23
  # elsewhere.
22
24
  attrs = clone_document.except("_id", "id")
23
- begin
24
- self.class.new(attrs)
25
- rescue Errors::UnknownAttribute
26
- self.class.send(:include, Attributes::Dynamic)
27
- self.class.new(attrs)
25
+ dynamic_attrs = {}
26
+ attrs.reject! do |attr_name, value|
27
+ dynamic_attrs[attr_name] = value unless self.attribute_names.include?(attr_name)
28
+ end
29
+ self.class.new(attrs).tap do |object|
30
+ dynamic_attrs.each do |attr_name, value|
31
+ if object.respond_to?("#{attr_name}=")
32
+ object.send("#{attr_name}=", value)
33
+ else
34
+ object.attributes[attr_name] = value
35
+ end
36
+ end
28
37
  end
29
38
  end
30
39
  alias :dup :clone
@@ -38,10 +47,12 @@ module Mongoid
38
47
  # @example clone document
39
48
  # model.clone_document
40
49
  #
50
+ # @param [ Hash ] dcoument The document with hash format
51
+ #
41
52
  # @since 3.0.22
42
53
  def clone_document
43
54
  attrs = as_document.__deep_copy__
44
- process_localized_attributes(self, attrs)
55
+ process_localized_attributes(attrs)
45
56
  attrs
46
57
  end
47
58
 
@@ -56,23 +67,12 @@ module Mongoid
56
67
  # @param [ Hash ] attrs The attributes.
57
68
  #
58
69
  # @since 3.0.20
59
- def process_localized_attributes(klass, attrs)
60
- klass.localized_fields.keys.each do |name|
70
+ def process_localized_attributes(attrs)
71
+ localized_fields.keys.each do |name|
61
72
  if value = attrs.delete(name)
62
73
  attrs["#{name}_translations"] = value
63
74
  end
64
75
  end
65
- klass.embedded_relations.each do |_, metadata|
66
- next unless attrs.present? && attrs[metadata.key].present?
67
-
68
- if metadata.macro == :embeds_many
69
- attrs[metadata.key].each do |attr|
70
- process_localized_attributes(metadata.klass, attr)
71
- end
72
- else
73
- process_localized_attributes(metadata.klass, attrs[metadata.key])
74
- end
75
- end
76
76
  end
77
77
  end
78
78
  end
@@ -4,7 +4,9 @@ require "mongoid/criteria/includable"
4
4
  require "mongoid/criteria/inspectable"
5
5
  require "mongoid/criteria/marshalable"
6
6
  require "mongoid/criteria/modifiable"
7
+ require "mongoid/criteria/queryable"
7
8
  require "mongoid/criteria/scopable"
9
+ require "mongoid/criteria/options"
8
10
 
9
11
  module Mongoid
10
12
 
@@ -17,7 +19,7 @@ module Mongoid
17
19
  class Criteria
18
20
  include Enumerable
19
21
  include Contextual
20
- include Origin::Queryable
22
+ include Queryable
21
23
  include Findable
22
24
  include Inspectable
23
25
  include Includable
@@ -25,6 +27,7 @@ module Mongoid
25
27
  include Modifiable
26
28
  include Scopable
27
29
  include Clients::Options
30
+ include Options
28
31
 
29
32
  # Static array used to check with method missing - we only need to ever
30
33
  # instantiate once.
@@ -193,8 +196,6 @@ module Mongoid
193
196
  # @since 1.0.0
194
197
  def initialize(klass)
195
198
  @klass = klass
196
- @embedded = nil
197
- @none = nil
198
199
  klass ? super(klass.aliased_fields, klass.fields) : super({}, {})
199
200
  end
200
201
 
@@ -386,7 +387,7 @@ module Mongoid
386
387
  # @example Add a javascript selection.
387
388
  # criteria.where("this.name == 'syd'")
388
389
  #
389
- # @param [ String, Hash ] expression The javascript or standard selection.
390
+ # @param [ String, Hash ] criterion The javascript or standard selection.
390
391
  #
391
392
  # @raise [ UnsupportedJavascript ] If provided a string and the criteria
392
393
  # is embedded.
@@ -8,8 +8,7 @@ module Mongoid
8
8
  # @example Execute or raise
9
9
  # criteria.execute_or_raise(id)
10
10
  #
11
- # @param [ Object ] ids The arguments passed.
12
- # @param [ true, false ] multi Whether there arguments were a list.
11
+ # @param [ Object ] args The arguments passed.
13
12
  #
14
13
  # @raise [ Errors::DocumentNotFound ] If nothing returned.
15
14
  #
@@ -67,7 +66,7 @@ module Mongoid
67
66
  # @example Get the documents from the map or criteria.
68
67
  # criteria.multiple_from_map_or_db(ids)
69
68
  #
70
- # @param [ Array<Object> ] ids The searched ids.
69
+ # @param [ ids ] The searched ids.
71
70
  #
72
71
  # @return [ Array<Document> ] The found documents.
73
72
  def multiple_from_db(ids)
@@ -27,7 +27,13 @@ module Mongoid
27
27
  #
28
28
  # @since 2.2.0
29
29
  def includes(*relations)
30
- extract_includes_list(klass, relations)
30
+ relations.flatten.each do |relation|
31
+ if relation.is_a?(Hash)
32
+ extract_nested_inclusion(klass, relation)
33
+ else
34
+ add_inclusion(klass, relation)
35
+ end
36
+ end
31
37
  clone
32
38
  end
33
39
 
@@ -48,7 +54,7 @@ module Mongoid
48
54
  # @example Set the inclusions.
49
55
  # criteria.inclusions = [ meta ]
50
56
  #
51
- # @param [ Array<Metadata> ] value The inclusions.
57
+ # @param [ Array<Metadata> ] The inclusions.
52
58
  #
53
59
  # @return [ Array<Metadata> ] The new inclusions.
54
60
  #
@@ -65,31 +71,72 @@ module Mongoid
65
71
  # criteria.add_inclusion(Person, :posts)
66
72
  #
67
73
  # @param [ Class, String, Symbol ] _klass The class or string/symbol of the class name.
68
- # @param [ Symbol ] metadata The relation.
74
+ # @param [ Symbol ] relation The relation.
69
75
  #
70
76
  # @raise [ Errors::InvalidIncludes ] If no relation is found.
71
77
  #
72
78
  # @since 5.1.0
73
- def add_inclusion(_klass, metadata)
79
+ def add_inclusion(_klass, relation)
80
+ metadata = get_inclusion_metadata(_klass, relation)
81
+ raise Errors::InvalidIncludes.new(_klass, [ relation ]) unless metadata
74
82
  inclusions.push(metadata) unless inclusions.include?(metadata)
75
83
  end
76
84
 
77
- def extract_includes_list(_parent_class, *relations_list)
78
- relations_list.flatten.each do |relation_object|
79
- if relation_object.is_a?(Hash)
80
- relation_object.each do |relation, _includes|
81
- metadata = _parent_class.reflect_on_association(relation)
82
- raise Errors::InvalidIncludes.new(_klass, [ relation ]) unless metadata
83
- add_inclusion(_parent_class, metadata)
84
- extract_includes_list(metadata.klass, _includes)
85
- end
85
+ # Extract inclusion definitions from a list.
86
+ #
87
+ # @example Extract the inclusions from a list.
88
+ # criteria.extract_relations_list(:posts, [{ :alerts => :items }])
89
+ #
90
+ # @param [ Symbol ] association The name of the association.
91
+ # @param [ Array ] relations A list of associations.
92
+ #
93
+ # @since 5.1.0
94
+ def extract_relations_list(association, relations)
95
+ relations.each do |relation|
96
+ if relation.is_a?(Hash)
97
+ extract_nested_inclusion(association, relation)
86
98
  else
87
- metadata = _parent_class.reflect_on_association(relation_object)
88
- raise Errors::InvalidIncludes.new(_parent_class, [ relation_object ]) unless metadata
89
- add_inclusion(_parent_class, metadata)
99
+ add_inclusion(association, relation)
90
100
  end
91
101
  end
92
102
  end
103
+
104
+ # Extract nested inclusion.
105
+ #
106
+ # @example Extract the inclusions from a nested definition.
107
+ # criteria.extract_nested_inclusion(User, { :posts => [:alerts] })
108
+ #
109
+ # @param [ Class, Symbol ] _klass The class for which the inclusion should be added.
110
+ # @param [ Hash ] relation The nested inclusion.
111
+ #
112
+ # @since 5.1.0
113
+ def extract_nested_inclusion(_klass, relation)
114
+ relation.each do |association, _inclusion|
115
+ add_inclusion(_klass, association)
116
+ if _inclusion.is_a?(Array)
117
+ extract_relations_list(association, _inclusion)
118
+ else
119
+ add_inclusion(association, _inclusion)
120
+ end
121
+ end
122
+ end
123
+
124
+ # Get the metadata for an inclusion.
125
+ #
126
+ # @example Get the metadata for an inclusion definition.
127
+ # criteria.get_inclusion_metadata(User, :posts)
128
+ #
129
+ # @param [ Class, Symbol, String ] _klass The class for determining the association metadata
130
+ # @param [ Symbol ] association The name of the association.
131
+ #
132
+ # @since 5.1.0
133
+ def get_inclusion_metadata(_klass, association)
134
+ if _klass.is_a?(Class)
135
+ _klass.reflect_on_association(association)
136
+ else
137
+ _klass.to_s.classify.constantize.reflect_on_association(association)
138
+ end
139
+ end
93
140
  end
94
141
  end
95
142
  end
@@ -27,8 +27,8 @@ module Mongoid
27
27
  def marshal_load(data)
28
28
  @scoping_options, raw_selector, raw_options = data.pop(3)
29
29
  @klass, @driver, @inclusions, @documents, @strategy, @negating = data
30
- @selector = load_hash(Origin::Selector, raw_selector)
31
- @options = load_hash(Origin::Options, raw_options)
30
+ @selector = load_hash(Queryable::Selector, raw_selector)
31
+ @options = load_hash(Queryable::Options, raw_options)
32
32
  end
33
33
 
34
34
  private
@@ -173,7 +173,7 @@ module Mongoid
173
173
  # @since 3.0.0
174
174
  def create_document(method, attrs = nil, &block)
175
175
  attributes = selector.reduce(attrs ? attrs.dup : {}) do |hash, (key, value)|
176
- unless key.to_s =~ /\$/ || value.is_a?(Hash)
176
+ unless invalid_key?(hash, key) || invalid_embedded_doc?(value)
177
177
  hash[key] = value
178
178
  end
179
179
  hash
@@ -216,6 +216,22 @@ module Mongoid
216
216
  def first_or(method, attrs = {}, &block)
217
217
  first || create_document(method, attrs, &block)
218
218
  end
219
+
220
+ private
221
+
222
+ def invalid_key?(hash, key)
223
+ # @todo Change this to BSON::String::ILLEGAL_KEY when ruby driver 2.3.0 is
224
+ # released and mongoid is updated to depend on driver >= 2.3.0
225
+ key.to_s =~ Mongoid::Document::ILLEGAL_KEY || hash.key?(key.to_sym) || hash.key?(key)
226
+ end
227
+
228
+ def invalid_embedded_doc?(value)
229
+ # @todo Change this to BSON::String::ILLEGAL_KEY when ruby driver 2.3.0 is
230
+ # released and mongoid is updated to depend on driver >= 2.3.0
231
+ value.is_a?(Hash) && value.any? do |key, v|
232
+ key.to_s =~ Mongoid::Document::ILLEGAL_KEY || invalid_embedded_doc?(v)
233
+ end
234
+ end
219
235
  end
220
236
  end
221
237
  end
@@ -0,0 +1,25 @@
1
+ # encoding: utf-8
2
+ module Mongoid
3
+ class Criteria
4
+
5
+ # Module containing functionality for getting options on a Criteria object.
6
+ #
7
+ # @since 6.0.0
8
+ module Options
9
+
10
+ private
11
+
12
+ def persistence_context
13
+ klass.persistence_context
14
+ end
15
+
16
+ def set_persistence_context(options)
17
+ PersistenceContext.set(klass, options)
18
+ end
19
+
20
+ def clear_persistence_context(original_cluster)
21
+ PersistenceContext.clear(klass, original_cluster)
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,86 @@
1
+ # encoding: utf-8
2
+ require "mongoid/criteria/queryable/extensions"
3
+ require "mongoid/criteria/queryable/forwardable"
4
+ require "mongoid/criteria/queryable/key"
5
+ require "mongoid/criteria/queryable/macroable"
6
+ require "mongoid/criteria/queryable/mergeable"
7
+ require "mongoid/criteria/queryable/smash"
8
+ require "mongoid/criteria/queryable/aggregable"
9
+ require "mongoid/criteria/queryable/pipeline"
10
+ require "mongoid/criteria/queryable/optional"
11
+ require "mongoid/criteria/queryable/options"
12
+ require "mongoid/criteria/queryable/selectable"
13
+ require "mongoid/criteria/queryable/selector"
14
+
15
+ module Mongoid
16
+ class Criteria
17
+
18
+ # A queryable is any object that needs queryable's dsl injected into it to build
19
+ # MongoDB queries. For example, a Mongoid::Criteria is an Queryable.
20
+ #
21
+ # @example Include queryable functionality.
22
+ # class Criteria
23
+ # include Queryable
24
+ # end
25
+ module Queryable
26
+ include Mergeable
27
+ include Aggregable
28
+ include Selectable
29
+ include Optional
30
+
31
+ # @attribute [r] aliases The aliases.
32
+ # @attribute [r] driver The Mongo driver being used.
33
+ # @attribute [r] serializers The serializers.
34
+ attr_reader :aliases, :driver, :serializers
35
+
36
+ # Is this queryable equal to another object? Is true if the selector and
37
+ # options are equal.
38
+ #
39
+ # @example Are the objects equal?
40
+ # queryable == criteria
41
+ #
42
+ # @param [ Object ] other The object to compare against.
43
+ #
44
+ # @return [ true, false ] If the objects are equal.
45
+ #
46
+ # @since 1.0.0
47
+ def ==(other)
48
+ return false unless other.is_a?(Queryable)
49
+ selector == other.selector && options == other.options
50
+ end
51
+
52
+ # Initialize the new queryable. Will yield itself to the block if a block
53
+ # is provided for objects that need additional behaviour.
54
+ #
55
+ # @example Initialize the queryable.
56
+ # Queryable.new
57
+ #
58
+ # @param [ Hash ] aliases The optional field aliases.
59
+ # @param [ Hash ] serializers The optional field serializers.
60
+ # @param [ Symbol ] driver The driver being used.
61
+ #
62
+ # @since 1.0.0
63
+ def initialize(aliases = {}, serializers = {}, driver = :mongo)
64
+ @aliases, @driver, @serializers = aliases, driver.to_sym, serializers
65
+ @options = Options.new(aliases, serializers)
66
+ @selector = Selector.new(aliases, serializers)
67
+ @pipeline = Pipeline.new(aliases)
68
+ yield(self) if block_given?
69
+ end
70
+
71
+ # Handle the creation of a copy via #clone or #dup.
72
+ #
73
+ # @example Handle copy initialization.
74
+ # queryable.initialize_copy(criteria)
75
+ #
76
+ # @param [ Queryable ] other The original copy.
77
+ #
78
+ # @since 1.0.0
79
+ def initialize_copy(other)
80
+ @options = other.options.__deep_copy__
81
+ @selector = other.selector.__deep_copy__
82
+ @pipeline = other.pipeline.__deep_copy__
83
+ end
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,120 @@
1
+ # encoding: utf-8
2
+ module Mongoid
3
+ class Criteria
4
+ module Queryable
5
+
6
+ # Provides a DSL around crafting aggregation framework commands.
7
+ #
8
+ # @since 2.0.0
9
+ module Aggregable
10
+ extend Macroable
11
+
12
+ # @attribute [r] pipeline The aggregation pipeline.
13
+ attr_reader :pipeline
14
+
15
+ # @attribute [rw] aggregating Flag for whether or not we are aggregating.
16
+ attr_writer :aggregating
17
+
18
+ # Has the aggregable enter an aggregation state. Ie, are only aggregation
19
+ # operations allowed at this point on.
20
+ #
21
+ # @example Is the aggregable aggregating?
22
+ # aggregable.aggregating?
23
+ #
24
+ # @return [ true, false ] If the aggregable is aggregating.
25
+ #
26
+ # @since 2.0.0
27
+ def aggregating?
28
+ !!@aggregating
29
+ end
30
+
31
+ # Add a group ($group) operation to the aggregation pipeline.
32
+ #
33
+ # @example Add a group operation being verbose.
34
+ # aggregable.group(count: { "$sum" => 1 }, max: { "$max" => "likes" })
35
+ #
36
+ # @example Add a group operation using symbol shortcuts.
37
+ # aggregable.group(:count.sum => 1, :max.max => "likes")
38
+ #
39
+ # @param [ Hash ] operation The group operation.
40
+ #
41
+ # @return [ Aggregable ] The aggregable.
42
+ #
43
+ # @since 2.0.0
44
+ def group(operation)
45
+ aggregation(operation) do |pipeline|
46
+ pipeline.group(operation)
47
+ end
48
+ end
49
+ key :avg, :override, "$avg"
50
+ key :max, :override, "$max"
51
+ key :min, :override, "$min"
52
+ key :sum, :override, "$sum"
53
+ key :last, :override, "$last"
54
+ key :push, :override, "$push"
55
+ key :first, :override, "$first"
56
+ key :add_to_set, :override, "$addToSet"
57
+
58
+ # Add a projection ($project) to the aggregation pipeline.
59
+ #
60
+ # @example Add a projection to the pipeline.
61
+ # aggregable.project(author: 1, name: 0)
62
+ #
63
+ # @param [ Hash ] criterion The projection to make.
64
+ #
65
+ # @return [ Aggregable ] The aggregable.
66
+ #
67
+ # @since 2.0.0
68
+ def project(operation = nil)
69
+ aggregation(operation) do |pipeline|
70
+ pipeline.project(operation)
71
+ end
72
+ end
73
+
74
+ # Add an unwind ($unwind) to the aggregation pipeline.
75
+ #
76
+ # @example Add an unwind to the pipeline.
77
+ # aggregable.unwind(:field)
78
+ #
79
+ # @param [ String, Symbol ] field The name of the field to unwind.
80
+ #
81
+ # @return [ Aggregable ] The aggregable.
82
+ #
83
+ # @since 2.0.0
84
+ def unwind(field)
85
+ aggregation(field) do |pipeline|
86
+ pipeline.unwind(field)
87
+ end
88
+ end
89
+
90
+ private
91
+
92
+ # Add the aggregation operation.
93
+ #
94
+ # @api private
95
+ #
96
+ # @example Aggregate on the operation.
97
+ # aggregation(operation) do |pipeline|
98
+ # pipeline.push("$project" => operation)
99
+ # end
100
+ #
101
+ # @param [ Hash ] operation The operation for the pipeline.
102
+ #
103
+ # @return [ Aggregable ] The cloned aggregable.
104
+ #
105
+ # @since 2.0.0
106
+ def aggregation(operation)
107
+ return self unless operation
108
+ clone.tap do |query|
109
+ unless aggregating?
110
+ query.pipeline.concat(query.selector.to_pipeline)
111
+ query.pipeline.concat(query.options.to_pipeline)
112
+ query.aggregating = true
113
+ end
114
+ yield(query.pipeline)
115
+ end
116
+ end
117
+ end
118
+ end
119
+ end
120
+ end