mongoid 5.4.0 → 6.4.8

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 (301) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/README.md +3 -3
  4. data/Rakefile +26 -0
  5. data/lib/config/locales/en.yml +40 -0
  6. data/lib/mongoid/atomic/modifiers.rb +2 -2
  7. data/lib/mongoid/atomic.rb +5 -5
  8. data/lib/mongoid/attributes/readonly.rb +22 -0
  9. data/lib/mongoid/attributes.rb +22 -21
  10. data/lib/mongoid/cacheable.rb +36 -0
  11. data/lib/mongoid/changeable.rb +36 -0
  12. data/lib/mongoid/clients/options.rb +55 -250
  13. data/lib/mongoid/clients/sessions.rb +113 -0
  14. data/lib/mongoid/clients/storage_options.rb +2 -69
  15. data/lib/mongoid/clients.rb +10 -63
  16. data/lib/mongoid/composable.rb +29 -2
  17. data/lib/mongoid/config.rb +1 -0
  18. data/lib/mongoid/contextual/aggregable/mongo.rb +1 -1
  19. data/lib/mongoid/contextual/atomic.rb +4 -4
  20. data/lib/mongoid/contextual/map_reduce.rb +7 -3
  21. data/lib/mongoid/contextual/memory.rb +9 -4
  22. data/lib/mongoid/contextual/mongo.rb +65 -30
  23. data/lib/mongoid/contextual/none.rb +12 -0
  24. data/lib/mongoid/copyable.rb +13 -6
  25. data/lib/mongoid/criteria/marshalable.rb +2 -2
  26. data/lib/mongoid/criteria/modifiable.rb +29 -3
  27. data/lib/mongoid/criteria/options.rb +25 -0
  28. data/lib/mongoid/criteria/queryable/aggregable.rb +120 -0
  29. data/lib/mongoid/criteria/queryable/extensions/array.rb +185 -0
  30. data/lib/mongoid/criteria/queryable/extensions/big_decimal.rb +37 -0
  31. data/lib/mongoid/criteria/queryable/extensions/boolean.rb +34 -0
  32. data/lib/mongoid/criteria/queryable/extensions/date.rb +63 -0
  33. data/lib/mongoid/criteria/queryable/extensions/date_time.rb +53 -0
  34. data/lib/mongoid/criteria/queryable/extensions/hash.rb +200 -0
  35. data/lib/mongoid/criteria/queryable/extensions/nil_class.rb +86 -0
  36. data/lib/mongoid/criteria/queryable/extensions/numeric.rb +90 -0
  37. data/lib/mongoid/criteria/queryable/extensions/object.rb +206 -0
  38. data/lib/mongoid/criteria/queryable/extensions/range.rb +70 -0
  39. data/lib/mongoid/criteria/queryable/extensions/regexp.rb +79 -0
  40. data/lib/mongoid/criteria/queryable/extensions/set.rb +34 -0
  41. data/lib/mongoid/criteria/queryable/extensions/string.rb +137 -0
  42. data/lib/mongoid/criteria/queryable/extensions/symbol.rb +79 -0
  43. data/lib/mongoid/criteria/queryable/extensions/time.rb +60 -0
  44. data/lib/mongoid/criteria/queryable/extensions/time_with_zone.rb +54 -0
  45. data/lib/mongoid/criteria/queryable/extensions.rb +28 -0
  46. data/lib/mongoid/criteria/queryable/forwardable.rb +65 -0
  47. data/lib/mongoid/criteria/queryable/key.rb +103 -0
  48. data/lib/mongoid/criteria/queryable/macroable.rb +27 -0
  49. data/lib/mongoid/criteria/queryable/mergeable.rb +273 -0
  50. data/lib/mongoid/criteria/queryable/optional.rb +429 -0
  51. data/lib/mongoid/criteria/queryable/options.rb +153 -0
  52. data/lib/mongoid/criteria/queryable/pipeline.rb +111 -0
  53. data/lib/mongoid/criteria/queryable/selectable.rb +689 -0
  54. data/lib/mongoid/criteria/queryable/selector.rb +212 -0
  55. data/lib/mongoid/criteria/queryable/smash.rb +104 -0
  56. data/lib/mongoid/criteria/queryable.rb +87 -0
  57. data/lib/mongoid/criteria.rb +6 -2
  58. data/lib/mongoid/document.rb +34 -41
  59. data/lib/mongoid/errors/ambiguous_relationship.rb +1 -1
  60. data/lib/mongoid/errors/in_memory_collation_not_supported.rb +1 -1
  61. data/lib/mongoid/errors/invalid_field.rb +2 -2
  62. data/lib/mongoid/errors/invalid_persistence_option.rb +29 -0
  63. data/lib/mongoid/errors/invalid_relation.rb +66 -0
  64. data/lib/mongoid/errors/invalid_session_use.rb +24 -0
  65. data/lib/mongoid/errors.rb +3 -0
  66. data/lib/mongoid/evolvable.rb +1 -1
  67. data/lib/mongoid/extensions/big_decimal.rb +17 -8
  68. data/lib/mongoid/extensions/date.rb +4 -1
  69. data/lib/mongoid/extensions/decimal128.rb +3 -3
  70. data/lib/mongoid/extensions/hash.rb +1 -0
  71. data/lib/mongoid/extensions/regexp.rb +1 -0
  72. data/lib/mongoid/extensions/string.rb +6 -3
  73. data/lib/mongoid/extensions/time.rb +4 -1
  74. data/lib/mongoid/extensions.rb +0 -4
  75. data/lib/mongoid/factory.rb +2 -1
  76. data/lib/mongoid/fields/validators/macro.rb +18 -0
  77. data/lib/mongoid/findable.rb +2 -2
  78. data/lib/mongoid/indexable.rb +16 -14
  79. data/lib/mongoid/interceptable.rb +9 -22
  80. data/lib/mongoid/matchable/all.rb +2 -2
  81. data/lib/mongoid/matchable/and.rb +3 -3
  82. data/lib/mongoid/matchable/default.rb +2 -2
  83. data/lib/mongoid/matchable/elem_match.rb +28 -0
  84. data/lib/mongoid/matchable/exists.rb +2 -2
  85. data/lib/mongoid/matchable/gt.rb +4 -2
  86. data/lib/mongoid/matchable/gte.rb +4 -2
  87. data/lib/mongoid/matchable/in.rb +2 -2
  88. data/lib/mongoid/matchable/lt.rb +4 -2
  89. data/lib/mongoid/matchable/lte.rb +4 -2
  90. data/lib/mongoid/matchable/ne.rb +2 -2
  91. data/lib/mongoid/matchable/nin.rb +2 -2
  92. data/lib/mongoid/matchable/nor.rb +37 -0
  93. data/lib/mongoid/matchable/or.rb +3 -3
  94. data/lib/mongoid/matchable/regexp.rb +3 -3
  95. data/lib/mongoid/matchable/size.rb +2 -2
  96. data/lib/mongoid/matchable.rb +16 -7
  97. data/lib/mongoid/persistable/creatable.rb +5 -3
  98. data/lib/mongoid/persistable/deletable.rb +5 -3
  99. data/lib/mongoid/persistable/destroyable.rb +1 -5
  100. data/lib/mongoid/persistable/settable.rb +5 -5
  101. data/lib/mongoid/persistable/updatable.rb +7 -14
  102. data/lib/mongoid/persistable/upsertable.rb +2 -1
  103. data/lib/mongoid/persistable.rb +4 -6
  104. data/lib/mongoid/persistence_context.rb +220 -0
  105. data/lib/mongoid/query_cache.rb +67 -23
  106. data/lib/mongoid/railtie.rb +17 -1
  107. data/lib/mongoid/railties/controller_runtime.rb +86 -0
  108. data/lib/mongoid/relations/accessors.rb +3 -0
  109. data/lib/mongoid/relations/auto_save.rb +12 -4
  110. data/lib/mongoid/relations/bindings/referenced/many_to_many.rb +4 -4
  111. data/lib/mongoid/relations/counter_cache.rb +15 -5
  112. data/lib/mongoid/relations/eager/base.rb +3 -3
  113. data/lib/mongoid/relations/eager/has_and_belongs_to_many.rb +2 -2
  114. data/lib/mongoid/relations/eager/has_many.rb +1 -1
  115. data/lib/mongoid/relations/eager.rb +6 -11
  116. data/lib/mongoid/relations/embedded/batchable.rb +20 -18
  117. data/lib/mongoid/relations/embedded/in.rb +13 -1
  118. data/lib/mongoid/relations/embedded/many.rb +51 -10
  119. data/lib/mongoid/relations/embedded/one.rb +14 -1
  120. data/lib/mongoid/relations/macros.rb +9 -1
  121. data/lib/mongoid/relations/many.rb +4 -0
  122. data/lib/mongoid/relations/metadata.rb +3 -3
  123. data/lib/mongoid/relations/options.rb +2 -2
  124. data/lib/mongoid/relations/proxy.rb +1 -31
  125. data/lib/mongoid/relations/referenced/in.rb +19 -10
  126. data/lib/mongoid/relations/referenced/many.rb +30 -26
  127. data/lib/mongoid/relations/referenced/many_to_many.rb +20 -13
  128. data/lib/mongoid/relations/referenced/one.rb +15 -1
  129. data/lib/mongoid/relations/synchronization.rb +12 -12
  130. data/lib/mongoid/relations/targets/enumerable.rb +24 -4
  131. data/lib/mongoid/relations/touchable.rb +7 -4
  132. data/lib/mongoid/reloadable.rb +2 -2
  133. data/lib/mongoid/scopable.rb +3 -3
  134. data/lib/mongoid/serializable.rb +1 -1
  135. data/lib/mongoid/stateful.rb +1 -0
  136. data/lib/mongoid/tasks/database.rb +3 -2
  137. data/lib/mongoid/threaded.rb +74 -0
  138. data/lib/mongoid/traversable.rb +1 -1
  139. data/lib/mongoid/validatable/uniqueness.rb +1 -2
  140. data/lib/mongoid/version.rb +1 -1
  141. data/lib/mongoid.rb +6 -6
  142. data/lib/rails/generators/mongoid/config/templates/mongoid.yml +18 -3
  143. data/spec/app/models/agent.rb +2 -0
  144. data/spec/app/models/album.rb +5 -1
  145. data/spec/app/models/array_field.rb +7 -0
  146. data/spec/app/models/artist.rb +21 -0
  147. data/spec/app/models/band.rb +3 -0
  148. data/spec/app/models/book.rb +2 -1
  149. data/spec/app/models/delegating_patient.rb +16 -0
  150. data/spec/app/models/dokument.rb +1 -0
  151. data/spec/app/models/ordered_post.rb +5 -0
  152. data/spec/app/models/oscar.rb +1 -2
  153. data/spec/app/models/page.rb +1 -1
  154. data/spec/app/models/person.rb +3 -3
  155. data/spec/app/models/princess.rb +2 -0
  156. data/spec/app/models/record.rb +1 -0
  157. data/spec/app/models/subscription.rb +1 -0
  158. data/spec/app/models/thing.rb +1 -1
  159. data/spec/config/mongoid.yml +15 -0
  160. data/spec/integration/document_spec.rb +22 -0
  161. data/spec/mongoid/atomic/modifiers_spec.rb +3 -3
  162. data/spec/mongoid/atomic_spec.rb +5 -5
  163. data/spec/mongoid/attributes/nested_spec.rb +18 -14
  164. data/spec/mongoid/attributes/readonly_spec.rb +87 -44
  165. data/spec/mongoid/attributes_spec.rb +90 -5
  166. data/spec/mongoid/cacheable_spec.rb +112 -0
  167. data/spec/mongoid/changeable_spec.rb +58 -0
  168. data/spec/mongoid/clients/factory_spec.rb +80 -28
  169. data/spec/mongoid/clients/options_spec.rb +396 -95
  170. data/spec/mongoid/clients/sessions_spec.rb +334 -0
  171. data/spec/mongoid/clients_spec.rb +243 -101
  172. data/spec/mongoid/composable_spec.rb +7 -0
  173. data/spec/mongoid/config_spec.rb +67 -11
  174. data/spec/mongoid/contextual/atomic_spec.rb +3 -3
  175. data/spec/mongoid/contextual/geo_near_spec.rb +1 -0
  176. data/spec/mongoid/contextual/mongo_spec.rb +275 -22
  177. data/spec/mongoid/contextual/none_spec.rb +15 -0
  178. data/spec/mongoid/copyable_spec.rb +13 -4
  179. data/spec/mongoid/criteria/modifiable_spec.rb +297 -16
  180. data/spec/mongoid/criteria/options_spec.rb +29 -0
  181. data/spec/mongoid/criteria/queryable/aggregable_spec.rb +370 -0
  182. data/spec/mongoid/criteria/queryable/extensions/array_spec.rb +523 -0
  183. data/spec/mongoid/criteria/queryable/extensions/big_decimal_spec.rb +59 -0
  184. data/spec/mongoid/criteria/queryable/extensions/bignum_spec.rb +58 -0
  185. data/spec/mongoid/criteria/queryable/extensions/boolean_spec.rb +213 -0
  186. data/spec/mongoid/criteria/queryable/extensions/date_spec.rb +330 -0
  187. data/spec/mongoid/criteria/queryable/extensions/date_time_spec.rb +405 -0
  188. data/spec/mongoid/criteria/queryable/extensions/fixnum_spec.rb +58 -0
  189. data/spec/mongoid/criteria/queryable/extensions/float_spec.rb +65 -0
  190. data/spec/mongoid/criteria/queryable/extensions/hash_spec.rb +327 -0
  191. data/spec/mongoid/criteria/queryable/extensions/integer_spec.rb +65 -0
  192. data/spec/mongoid/criteria/queryable/extensions/nil_class_spec.rb +77 -0
  193. data/spec/mongoid/criteria/queryable/extensions/object_spec.rb +108 -0
  194. data/spec/mongoid/criteria/queryable/extensions/range_spec.rb +309 -0
  195. data/spec/mongoid/{extensions/origin → criteria/queryable/extensions}/regexp_raw_spec.rb +2 -2
  196. data/spec/mongoid/criteria/queryable/extensions/regexp_spec.rb +90 -0
  197. data/spec/mongoid/criteria/queryable/extensions/set_spec.rb +39 -0
  198. data/spec/mongoid/criteria/queryable/extensions/string_spec.rb +302 -0
  199. data/spec/mongoid/criteria/queryable/extensions/symbol_spec.rb +167 -0
  200. data/spec/mongoid/criteria/queryable/extensions/time_spec.rb +376 -0
  201. data/spec/mongoid/criteria/queryable/extensions/time_with_zone_spec.rb +347 -0
  202. data/spec/mongoid/criteria/queryable/forwardable_spec.rb +87 -0
  203. data/spec/mongoid/criteria/queryable/key_spec.rb +52 -0
  204. data/spec/mongoid/criteria/queryable/mergeable_spec.rb +49 -0
  205. data/spec/mongoid/criteria/queryable/optional_spec.rb +1799 -0
  206. data/spec/mongoid/criteria/queryable/options_spec.rb +360 -0
  207. data/spec/mongoid/criteria/queryable/pipeline_spec.rb +200 -0
  208. data/spec/mongoid/criteria/queryable/queryable_spec.rb +137 -0
  209. data/spec/mongoid/criteria/queryable/selectable_spec.rb +4242 -0
  210. data/spec/mongoid/criteria/queryable/selector_spec.rb +844 -0
  211. data/spec/mongoid/criteria/queryable/smash_spec.rb +30 -0
  212. data/spec/mongoid/criteria/scopable_spec.rb +81 -0
  213. data/spec/mongoid/criteria_spec.rb +156 -22
  214. data/spec/mongoid/document_spec.rb +100 -90
  215. data/spec/mongoid/errors/invalid_relation_spec.rb +37 -0
  216. data/spec/mongoid/errors/mongoid_error_spec.rb +6 -3
  217. data/spec/mongoid/extensions/big_decimal_spec.rb +321 -19
  218. data/spec/mongoid/extensions/boolean_spec.rb +14 -0
  219. data/spec/mongoid/extensions/date_spec.rb +2 -6
  220. data/spec/mongoid/extensions/date_time_spec.rb +2 -6
  221. data/spec/mongoid/extensions/decimal128_spec.rb +1 -1
  222. data/spec/mongoid/extensions/float_spec.rb +8 -1
  223. data/spec/mongoid/extensions/hash_spec.rb +15 -0
  224. data/spec/mongoid/extensions/integer_spec.rb +8 -1
  225. data/spec/mongoid/extensions/object_spec.rb +11 -0
  226. data/spec/mongoid/extensions/regexp_spec.rb +23 -0
  227. data/spec/mongoid/extensions/string_spec.rb +53 -4
  228. data/spec/mongoid/extensions/time_spec.rb +2 -6
  229. data/spec/mongoid/extensions/time_with_zone_spec.rb +2 -6
  230. data/spec/mongoid/factory_spec.rb +11 -0
  231. data/spec/mongoid/fields_spec.rb +1 -1
  232. data/spec/mongoid/findable_spec.rb +47 -2
  233. data/spec/mongoid/indexable_spec.rb +15 -3
  234. data/spec/mongoid/interceptable_spec.rb +85 -19
  235. data/spec/mongoid/matchable/all_spec.rb +4 -4
  236. data/spec/mongoid/matchable/and_spec.rb +10 -10
  237. data/spec/mongoid/matchable/default_spec.rb +12 -12
  238. data/spec/mongoid/matchable/elem_match_spec.rb +86 -0
  239. data/spec/mongoid/matchable/exists_spec.rb +5 -5
  240. data/spec/mongoid/matchable/gt_spec.rb +18 -7
  241. data/spec/mongoid/matchable/gte_spec.rb +17 -7
  242. data/spec/mongoid/matchable/in_spec.rb +5 -5
  243. data/spec/mongoid/matchable/lt_spec.rb +18 -7
  244. data/spec/mongoid/matchable/lte_spec.rb +18 -7
  245. data/spec/mongoid/matchable/ne_spec.rb +5 -5
  246. data/spec/mongoid/matchable/nin_spec.rb +5 -5
  247. data/spec/mongoid/matchable/nor_spec.rb +209 -0
  248. data/spec/mongoid/matchable/or_spec.rb +7 -7
  249. data/spec/mongoid/matchable/regexp_spec.rb +5 -5
  250. data/spec/mongoid/matchable/size_spec.rb +3 -3
  251. data/spec/mongoid/matchable_spec.rb +199 -54
  252. data/spec/mongoid/persistable/creatable_spec.rb +7 -2
  253. data/spec/mongoid/persistable/deletable_spec.rb +35 -1
  254. data/spec/mongoid/persistable/destroyable_spec.rb +25 -2
  255. data/spec/mongoid/persistable/incrementable_spec.rb +6 -6
  256. data/spec/mongoid/persistable/savable_spec.rb +34 -29
  257. data/spec/mongoid/persistable/settable_spec.rb +77 -27
  258. data/spec/mongoid/persistable/updatable_spec.rb +182 -3
  259. data/spec/mongoid/persistable_spec.rb +16 -16
  260. data/spec/mongoid/persistence_context_spec.rb +694 -0
  261. data/spec/mongoid/positional_spec.rb +1 -1
  262. data/spec/mongoid/query_cache_spec.rb +170 -12
  263. data/spec/mongoid/relations/accessors_spec.rb +1 -1
  264. data/spec/mongoid/relations/auto_save_spec.rb +39 -6
  265. data/spec/mongoid/relations/bindings/referenced/many_to_many_spec.rb +4 -4
  266. data/spec/mongoid/relations/builders_spec.rb +37 -10
  267. data/spec/mongoid/relations/counter_cache_spec.rb +64 -3
  268. data/spec/mongoid/relations/eager/has_and_belongs_to_many_spec.rb +16 -0
  269. data/spec/mongoid/relations/eager_spec.rb +40 -0
  270. data/spec/mongoid/relations/embedded/many_spec.rb +305 -59
  271. data/spec/mongoid/relations/embedded/one_spec.rb +2 -1
  272. data/spec/mongoid/relations/macros_spec.rb +415 -7
  273. data/spec/mongoid/relations/metadata_spec.rb +15 -1
  274. data/spec/mongoid/relations/proxy_spec.rb +27 -1
  275. data/spec/mongoid/relations/referenced/in_spec.rb +41 -1
  276. data/spec/mongoid/relations/referenced/many_spec.rb +35 -25
  277. data/spec/mongoid/relations/referenced/many_to_many_spec.rb +14 -26
  278. data/spec/mongoid/relations/synchronization_spec.rb +48 -2
  279. data/spec/mongoid/relations/targets/enumerable_spec.rb +108 -0
  280. data/spec/mongoid/relations/touchable_spec.rb +40 -0
  281. data/spec/mongoid/reloadable_spec.rb +51 -0
  282. data/spec/mongoid/scopable_spec.rb +13 -0
  283. data/spec/mongoid/serializable_spec.rb +0 -50
  284. data/spec/mongoid/threaded_spec.rb +68 -0
  285. data/spec/mongoid/validatable/presence_spec.rb +1 -1
  286. data/spec/mongoid/validatable/uniqueness_spec.rb +18 -9
  287. data/spec/mongoid/validatable_spec.rb +16 -0
  288. data/spec/rails/controller_extension/controller_runtime_spec.rb +110 -0
  289. data/spec/spec_helper.rb +101 -8
  290. data/spec/support/cluster_config.rb +158 -0
  291. data/spec/support/constraints.rb +101 -0
  292. data/spec/support/macros.rb +20 -0
  293. data/spec/support/session_registry.rb +50 -0
  294. data/spec/support/spec_config.rb +42 -0
  295. data.tar.gz.sig +0 -0
  296. metadata +163 -61
  297. metadata.gz.sig +0 -0
  298. data/lib/mongoid/clients/thread_options.rb +0 -19
  299. data/lib/mongoid/extensions/origin/regexp_raw.rb +0 -43
  300. data/lib/mongoid/railties/document.rb +0 -12
  301. data/spec/mongoid/railties/document_spec.rb +0 -24
@@ -8,20 +8,20 @@ module Mongoid
8
8
  # Does the supplied query match the attribute?
9
9
  #
10
10
  # @example Does this match?
11
- # matcher.matches?("$or" => [ { field => value } ])
11
+ # matcher._matches?("$or" => [ { field => value } ])
12
12
  #
13
13
  # @param [ Array ] conditions The or expression.
14
14
  #
15
15
  # @return [ true, false ] True if matches, false if not.
16
16
  #
17
17
  # @since 2.0.0.rc.7
18
- def matches?(conditions)
18
+ def _matches?(conditions)
19
19
  conditions.each do |condition|
20
20
  res = true
21
21
  condition.keys.each do |k|
22
22
  key = k
23
23
  value = condition[k]
24
- res &&= document.matches?(key => value)
24
+ res &&= document._matches?(key => value)
25
25
  break unless res
26
26
  end
27
27
  return res if res
@@ -7,15 +7,15 @@ module Mongoid
7
7
  # Does the supplied query match the attribute?
8
8
  #
9
9
  # @example Does this match?
10
- # matcher.matches?(/^Em/)
11
- # matcher.matches?(BSON::Regex::Raw.new("^Em"))
10
+ # matcher._matches?(/^Em/)
11
+ # matcher._matches?(BSON::Regex::Raw.new("^Em"))
12
12
  #
13
13
  # @param [ BSON::Regexp::Raw, Regexp ] regexp The regular expression object.
14
14
  #
15
15
  # @return [ true, false ] True if matches, false if not.
16
16
  #
17
17
  # @since 5.2.1
18
- def matches?(regexp)
18
+ def _matches?(regexp)
19
19
  if native_regexp = regexp.try(:compile)
20
20
  super(native_regexp)
21
21
  else
@@ -8,12 +8,12 @@ module Mongoid
8
8
  # Return true if the attribute size is equal to the first value.
9
9
  #
10
10
  # @example Do the values match?
11
- # matcher.matches?({ :key => 10 })
11
+ # matcher._matches?({ :key => 10 })
12
12
  #
13
13
  # @param [ Hash ] value The values to check.
14
14
  #
15
15
  # @return [ true, false ] If a value exists.
16
- def matches?(value)
16
+ def _matches?(value)
17
17
  @attribute.size == value.values.first
18
18
  end
19
19
  end
@@ -11,7 +11,9 @@ require "mongoid/matchable/lte"
11
11
  require "mongoid/matchable/ne"
12
12
  require "mongoid/matchable/nin"
13
13
  require "mongoid/matchable/or"
14
+ require "mongoid/matchable/nor"
14
15
  require "mongoid/matchable/size"
16
+ require "mongoid/matchable/elem_match"
15
17
  require "mongoid/matchable/regexp"
16
18
 
17
19
  module Mongoid
@@ -28,6 +30,7 @@ module Mongoid
28
30
  # @since 1.0.0
29
31
  MATCHERS = {
30
32
  "$all" => All,
33
+ "$elemMatch" => ElemMatch,
31
34
  "$and" => And,
32
35
  "$exists" => Exists,
33
36
  "$gt" => Gt,
@@ -38,6 +41,7 @@ module Mongoid
38
41
  "$ne" => Ne,
39
42
  "$nin" => Nin,
40
43
  "$or" => Or,
44
+ "$nor" => Nor,
41
45
  "$size" => Size
42
46
  }.with_indifferent_access.freeze
43
47
 
@@ -45,26 +49,26 @@ module Mongoid
45
49
  # MongoDB selector. Used for matching on embedded associations.
46
50
  #
47
51
  # @example Does the document match?
48
- # document.matches?(:title => { "$in" => [ "test" ] })
52
+ # document._matches?(:title => { "$in" => [ "test" ] })
49
53
  #
50
54
  # @param [ Hash ] selector The MongoDB selector.
51
55
  #
52
56
  # @return [ true, false ] True if matches, false if not.
53
57
  #
54
58
  # @since 1.0.0
55
- def matches?(selector)
59
+ def _matches?(selector)
56
60
  selector.each_pair do |key, value|
57
61
  if value.is_a?(Hash)
58
62
  value.each do |item|
59
63
  if item[0].to_s == "$not".freeze
60
64
  item = item[1]
61
- return false if matcher(self, key, item).matches?(item)
65
+ return false if matcher(self, key, item)._matches?(item)
62
66
  else
63
- return false unless matcher(self, key, Hash[*item]).matches?(Hash[*item])
67
+ return false unless matcher(self, key, Hash[*item])._matches?(Hash[*item])
64
68
  end
65
69
  end
66
70
  else
67
- return false unless matcher(self, key, value).matches?(value)
71
+ return false unless matcher(self, key, value)._matches?(value)
68
72
  end
69
73
  end
70
74
  true
@@ -122,6 +126,7 @@ module Mongoid
122
126
  case key.to_s
123
127
  when "$or" then Or.new(value, document)
124
128
  when "$and" then And.new(value, document)
129
+ when "$nor" then Nor.new(value, document)
125
130
  else Default.new(extract_attribute(document, key))
126
131
  end
127
132
  end
@@ -144,7 +149,7 @@ module Mongoid
144
149
  # @since 2.2.1
145
150
  def extract_attribute(document, key)
146
151
  if (key_string = key.to_s) =~ /.+\..+/
147
- key_string.split('.').inject(document.as_document) do |_attribs, _key|
152
+ key_string.split('.').inject(document.send(:as_attributes)) do |_attribs, _key|
148
153
  if _attribs.is_a?(::Array)
149
154
  if _key =~ /\A\d+\z/ && _attribs.none? {|doc| doc.is_a?(Hash)}
150
155
  _attribs.try(:[], _key.to_i)
@@ -156,7 +161,11 @@ module Mongoid
156
161
  end
157
162
  end
158
163
  else
159
- document.attributes[key_string]
164
+ if document.is_a?(Hash)
165
+ document[key_string]
166
+ else
167
+ document.attributes[key_string]
168
+ end
160
169
  end
161
170
  end
162
171
  end
@@ -42,7 +42,7 @@ module Mongoid
42
42
  #
43
43
  # @since 2.1.0
44
44
  def atomic_inserts
45
- { atomic_insert_modifier => { atomic_position => as_document }}
45
+ { atomic_insert_modifier => { atomic_position => as_attributes }}
46
46
  end
47
47
 
48
48
  # Insert the embedded document.
@@ -61,7 +61,9 @@ module Mongoid
61
61
  _parent.insert
62
62
  else
63
63
  selector = _parent.atomic_selector
64
- _root.collection.find(selector).update_one(positionally(selector, atomic_inserts))
64
+ _root.collection.find(selector).update_one(
65
+ positionally(selector, atomic_inserts),
66
+ session: _session)
65
67
  end
66
68
  end
67
69
 
@@ -76,7 +78,7 @@ module Mongoid
76
78
  #
77
79
  # @since 4.0.0
78
80
  def insert_as_root
79
- collection.insert_one(as_document)
81
+ collection.insert_one(as_attributes, session: _session)
80
82
  end
81
83
 
82
84
  # Post process an insert, which sets the new record attribute to false
@@ -62,7 +62,9 @@ module Mongoid
62
62
  _parent.remove_child(self) if notifying_parent?(options)
63
63
  if _parent.persisted?
64
64
  selector = _parent.atomic_selector
65
- _root.collection.find(selector).update_one(positionally(selector, atomic_deletes))
65
+ _root.collection.find(selector).update_one(
66
+ positionally(selector, atomic_deletes),
67
+ session: _session)
66
68
  end
67
69
  true
68
70
  end
@@ -78,7 +80,7 @@ module Mongoid
78
80
  #
79
81
  # @since 4.0.0
80
82
  def delete_as_root
81
- collection.find(atomic_selector).delete_one
83
+ collection.find(atomic_selector).delete_one(session: _session)
82
84
  true
83
85
  end
84
86
 
@@ -137,7 +139,7 @@ module Mongoid
137
139
  # @since 1.0.0
138
140
  def delete_all(conditions = {})
139
141
  selector = hereditary? ? conditions.merge(_type: name) : conditions
140
- collection.find(selector).delete_many.deleted_count
142
+ where(selector).delete
141
143
  end
142
144
  end
143
145
  end
@@ -48,11 +48,7 @@ module Mongoid
48
48
  #
49
49
  # @since 1.0.0
50
50
  def destroy_all(conditions = nil)
51
- selector = conditions || {}
52
- documents = where(selector)
53
- destroyed = documents.count
54
- documents.each { |doc| doc.destroy }
55
- destroyed
51
+ where(conditions || {}).destroy
56
52
  end
57
53
  end
58
54
  end
@@ -25,15 +25,15 @@ module Mongoid
25
25
 
26
26
  field_and_value_hash = hasherizer(field.split('.'), value)
27
27
  field = field_and_value_hash.keys.first.to_s
28
+ value = field_and_value_hash[field]
28
29
 
29
- if fields[field] && fields[field].type == Hash && attributes.key?(field)
30
+ if fields[field] && fields[field].type == Hash && attributes.key?(field) && Hash === value && !value.empty?
30
31
  merger = proc { |key, v1, v2| Hash === v1 && Hash === v2 ? v1.merge(v2, &merger) : v2 }
31
- value = attributes[field].merge(field_and_value_hash[field], &merger)
32
- process_attribute(field.to_s, value)
33
- else
34
- process_attribute(field.to_s, field_and_value_hash[field])
32
+ value = (attributes[field] || {}).merge(value, &merger)
35
33
  end
36
34
 
35
+ process_attribute(field.to_s, value)
36
+
37
37
  unless relations.include?(field.to_s)
38
38
  ops[atomic_attribute_name(field)] = attributes[field]
39
39
  end
@@ -24,17 +24,11 @@ module Mongoid
24
24
  #
25
25
  # @since 2.0.0
26
26
  def update_attribute(name, value)
27
- normalized = name.to_s
28
- unless attribute_writable?(normalized)
29
- raise Errors::ReadonlyAttribute.new(normalized, value)
27
+ as_writable_attribute!(name, value) do |access|
28
+ normalized = name.to_s
29
+ process_attribute(normalized, value)
30
+ save(validate: false)
30
31
  end
31
- setter = "#{normalized}="
32
- if respond_to?(setter)
33
- send(setter, value)
34
- else
35
- write_attribute(database_field_name(normalized), value)
36
- end
37
- save(validate: false)
38
32
  end
39
33
 
40
34
  # Update the document attributes in the database.
@@ -135,15 +129,14 @@ module Mongoid
135
129
  #
136
130
  # @since 1.0.0
137
131
  def update_document(options = {})
138
- raise Errors::ReadonlyDocument.new(self.class) if readonly?
139
132
  prepare_update(options) do
140
133
  updates, conflicts = init_atomic_updates
141
134
  unless updates.empty?
142
- coll = _root.collection
135
+ coll = collection(_root)
143
136
  selector = atomic_selector
144
- coll.find(selector).update_one(positionally(selector, updates))
137
+ coll.find(selector).update_one(positionally(selector, updates), session: _session)
145
138
  conflicts.each_pair do |key, value|
146
- coll.find(selector).update_one(positionally(selector, { key => value }))
139
+ coll.find(selector).update_one(positionally(selector, { key => value }), session: _session)
147
140
  end
148
141
  end
149
142
  end
@@ -21,7 +21,8 @@ module Mongoid
21
21
  # @since 3.0.0
22
22
  def upsert(options = {})
23
23
  prepare_upsert(options) do
24
- collection.find(atomic_selector).update_one(as_document, upsert: true)
24
+ collection.find(atomic_selector).update_one(
25
+ as_attributes, upsert: true, session: _session)
25
26
  end
26
27
  end
27
28
 
@@ -162,12 +162,10 @@ module Mongoid
162
162
  # @since 4.0.0
163
163
  def process_atomic_operations(operations)
164
164
  operations.each do |field, value|
165
- unless attribute_writable?(field)
166
- raise Errors::ReadonlyAttribute.new(field, value)
165
+ as_writable_attribute!(field, value) do |access|
166
+ yield(access, value)
167
+ remove_change(access)
167
168
  end
168
- normalized = database_field_name(field)
169
- yield(normalized, value)
170
- remove_change(normalized)
171
169
  end
172
170
  end
173
171
 
@@ -206,7 +204,7 @@ module Mongoid
206
204
  def persist_atomic_operations(operations)
207
205
  if persisted? && operations
208
206
  selector = atomic_selector
209
- _root.collection.find(selector).update_one(positionally(selector, operations))
207
+ _root.collection.find(selector).update_one(positionally(selector, operations), session: _session)
210
208
  end
211
209
  end
212
210
  end
@@ -0,0 +1,220 @@
1
+ module Mongoid
2
+
3
+ # Object encapsulating logic for setting/getting a collection and database name
4
+ # and a client with particular options to use when persisting models.
5
+ #
6
+ # @since 6.0.0
7
+ class PersistenceContext
8
+ extend Forwardable
9
+
10
+ # Delegate the cluster method to the client.
11
+ def_delegators :client, :cluster
12
+
13
+ # Delegate the storage options method to the object.
14
+ def_delegators :@object, :storage_options
15
+
16
+ # The options defining this persistence context.
17
+ #
18
+ # @return [ Hash ] The persistence context options.
19
+ #
20
+ # @since 6.0.0
21
+ attr_reader :options
22
+
23
+ # Extra options in addition to driver client options that determine the
24
+ # persistence context.
25
+ #
26
+ # @return [ Array<Symbol> ] The list of extra options besides client options
27
+ # that determine the persistence context.
28
+ #
29
+ # @since 6.0.0
30
+ EXTRA_OPTIONS = [ :client,
31
+ :collection
32
+ ].freeze
33
+
34
+ # The full list of valid persistence context options.
35
+ #
36
+ # @return [ Array<Symbol> ] The full list of options defining the persistence
37
+ # context.
38
+ #
39
+ # @since 6.0.0
40
+ VALID_OPTIONS = ( Mongo::Client::VALID_OPTIONS + EXTRA_OPTIONS ).freeze
41
+
42
+ # Initialize the persistence context object.
43
+ #
44
+ # @example Create a new persistence context.
45
+ # PersistenceContext.new(model, collection: 'other')
46
+ #
47
+ # @param [ Object ] object The class or model instance for which a persistence context
48
+ # should be created.
49
+ # @param [ Hash ] opts The persistence context options.
50
+ #
51
+ # @since 6.0.0
52
+ def initialize(object, opts = {})
53
+ @object = object
54
+ set_options!(opts)
55
+ end
56
+
57
+ # Get the collection for this persistence context.
58
+ #
59
+ # @example Get the collection for this persistence context.
60
+ # context.collection
61
+ #
62
+ # @param [ Object ] parent The parent object whose collection name is used
63
+ # instead of this persistence context's collection name.
64
+ #
65
+ # @return [ Mongo::Collection ] The collection for this persistence
66
+ # context.
67
+ #
68
+ # @since 6.0.0
69
+ def collection(parent = nil)
70
+ parent ? parent.collection.with(client_options) : client[collection_name.to_sym]
71
+ end
72
+
73
+ # Get the collection name for this persistence context.
74
+ #
75
+ # @example Get the collection name for this persistence context.
76
+ # context.collection_name
77
+ #
78
+ # @return [ String ] The collection name for this persistence
79
+ # context.
80
+ #
81
+ # @since 6.0.0
82
+ def collection_name
83
+ @collection_name ||= (__evaluate__(options[:collection] ||
84
+ storage_options[:collection]))
85
+ end
86
+
87
+ # Get the database name for this persistence context.
88
+ #
89
+ # @example Get the database name for this persistence context.
90
+ # context.database_name
91
+ #
92
+ # @return [ String ] The database name for this persistence
93
+ # context.
94
+ #
95
+ # @since 6.0.0
96
+ def database_name
97
+ __evaluate__(database_name_option) || client.database.name
98
+ end
99
+
100
+ # Get the client for this persistence context.
101
+ #
102
+ # @example Get the client for this persistence context.
103
+ # context.client
104
+ #
105
+ # @return [ Mongo::Client ] The client for this persistence
106
+ # context.
107
+ #
108
+ # @since 6.0.0
109
+ def client
110
+ client_options = send(:client_options)
111
+ if client_options[:read].is_a?(Symbol)
112
+ client_options = client_options.merge(read: {mode: client_options[:read]})
113
+ end
114
+ @client ||= (client = Clients.with_name(client_name)
115
+ client = client.use(database_name) if database_name_option
116
+ client.with(client_options))
117
+ end
118
+
119
+ # Determine if this persistence context is equal to another.
120
+ #
121
+ # @example Compare two persistence contexts.
122
+ # context == other_context
123
+ #
124
+ # @param [ Object ] other The object to be compared with this one.
125
+ #
126
+ # @return [ true, false ] Whether the two persistence contexts are equal.
127
+ #
128
+ # @since 6.0.0
129
+ def ==(other)
130
+ return false unless other.is_a?(PersistenceContext)
131
+ options == other.options
132
+ end
133
+
134
+ private
135
+
136
+ def client_name
137
+ @client_name ||= options[:client] ||
138
+ Threaded.client_override ||
139
+ storage_options && __evaluate__(storage_options[:client])
140
+ end
141
+
142
+ def set_options!(opts)
143
+ @options ||= opts.each.reduce({}) do |_options, (key, value)|
144
+ unless VALID_OPTIONS.include?(key.to_sym)
145
+ raise Errors::InvalidPersistenceOption.new(key.to_sym, VALID_OPTIONS)
146
+ end
147
+ value ? _options.merge!(key => value) : _options
148
+ end
149
+ end
150
+
151
+ def __evaluate__(name)
152
+ return nil unless name
153
+ name.respond_to?(:call) ? name.call.to_sym : name.to_sym
154
+ end
155
+
156
+ def client_options
157
+ @client_options ||= options.select do |k, v|
158
+ Mongo::Client::VALID_OPTIONS.include?(k.to_sym)
159
+ end
160
+ end
161
+
162
+ def database_name_option
163
+ @database_name_option ||= options[:database] ||
164
+ Threaded.database_override ||
165
+ storage_options && storage_options[:database]
166
+ end
167
+
168
+ class << self
169
+
170
+ # Set the persistence context for a particular class or model instance.
171
+ #
172
+ # @example Set the persistence context for a class or model instance.
173
+ # PersistenceContext.set(model)
174
+ #
175
+ # @param [ Object ] object The class or model instance.
176
+ # @param [ Hash, Mongoid::PersistenceContext ] options_or_context The persistence
177
+ # options or a persistence context object.
178
+ #
179
+ # @return [ Mongoid::PersistenceContext ] The persistence context for the object.
180
+ #
181
+ # @since 6.0.0
182
+ def set(object, options_or_context)
183
+ context = PersistenceContext.new(object, options_or_context.is_a?(PersistenceContext) ?
184
+ options_or_context.options : options_or_context)
185
+ Thread.current["[mongoid][#{object.object_id}]:context"] = context
186
+ end
187
+
188
+ # Get the persistence context for a particular class or model instance.
189
+ #
190
+ # @example Get the persistence context for a class or model instance.
191
+ # PersistenceContext.get(model)
192
+ #
193
+ # @param [ Object ] object The class or model instance.
194
+ #
195
+ # @return [ Mongoid::PersistenceContext ] The persistence context for the object.
196
+ #
197
+ # @since 6.0.0
198
+ def get(object)
199
+ Thread.current["[mongoid][#{object.object_id}]:context"]
200
+ end
201
+
202
+ # Clear the persistence context for a particular class or model instance.
203
+ #
204
+ # @example Clear the persistence context for a class or model instance.
205
+ # PersistenceContext.clear(model)
206
+ #
207
+ # @param [ Class, Object ] object The class or model instance.
208
+ # @param [ Mongo::Cluster ] cluster The original cluster before this context was used.
209
+ #
210
+ # @since 6.0.0
211
+ def clear(object, cluster = nil)
212
+ if context = get(object)
213
+ context.client.close unless (context.cluster.equal?(cluster) || cluster.nil?)
214
+ end
215
+ ensure
216
+ Thread.current["[mongoid][#{object.object_id}]:context"] = nil
217
+ end
218
+ end
219
+ end
220
+ end
@@ -159,11 +159,14 @@ module Mongoid
159
159
  private
160
160
 
161
161
  def process(result)
162
- @remaining -= result.returned_count if limited?
163
- @cursor_id = result.cursor_id
164
- @coll_name ||= result.namespace.sub("#{database.name}.", '') if result.namespace
165
- documents = result.documents
166
- (@cached_documents ||= []).concat(documents)
162
+ documents = super
163
+
164
+ if @cursor_id.zero? && !@after_first_batch
165
+ @cached_documents ||= []
166
+ @cached_documents.concat(documents)
167
+ end
168
+
169
+ @after_first_batch = true
167
170
  documents
168
171
  end
169
172
  end
@@ -183,7 +186,8 @@ module Mongoid
183
186
  end
184
187
  CODE
185
188
 
186
- alias_method_chain method_name, :clear_cache
189
+ alias_method "#{method_name}_without_clear_cache", method_name
190
+ alias_method method_name, "#{method_name}_with_clear_cache"
187
191
  end
188
192
  end
189
193
  end
@@ -217,39 +221,73 @@ module Mongoid
217
221
  #
218
222
  # @since 5.0.0
219
223
  def each
220
- if system_collection? || !QueryCache.enabled?
224
+ if system_collection? || !QueryCache.enabled? || (respond_to?(:write?, true) && write?)
221
225
  super
222
226
  else
223
- unless cursor = cached_cursor
224
- server = read_or_server_selector.select_server(cluster)
225
- cursor = CachedCursor.new(view, send_initial_query(server), server)
226
- QueryCache.cache_table[cache_key] = cursor
227
+ @cursor = nil
228
+ unless @cursor = cached_cursor
229
+
230
+ if driver_supports_cursor_sessions?
231
+ session = client.send(:get_session, @options)
232
+ read_with_retry(session, server_selector) do |server|
233
+ result = send_initial_query(server, session)
234
+ @cursor = get_cursor(result, server, session)
235
+ end
236
+ else
237
+ read_with_retry do
238
+ server = server_selector.select_server(cluster)
239
+ result = send_initial_query(server)
240
+ @cursor = get_cursor(result, server)
241
+ end
242
+ end
243
+ end
244
+
245
+ if block_given?
246
+ if limit && limit != -1
247
+ @cursor.to_a[0...limit].each do |doc|
248
+ yield doc
249
+ end
250
+ else
251
+ @cursor.each do |doc|
252
+ yield doc
253
+ end
254
+ end
255
+ else
256
+ @cursor.to_enum
227
257
  end
228
- cursor.each do |doc|
229
- yield doc
230
- end if block_given?
231
- cursor
232
258
  end
233
259
  end
234
260
 
235
261
  private
236
262
 
237
- def read_or_server_selector
238
- respond_to?(:server_selector, true) ? server_selector : read
239
- end
240
-
241
263
  def cached_cursor
242
264
  if limit
243
265
  key = [ collection.namespace, selector, nil, skip, sort, projection, collation ]
244
266
  cursor = QueryCache.cache_table[key]
245
- if cursor
246
- limited_docs = cursor.to_a[0...limit.abs]
247
- cursor.instance_variable_set(:@cached_documents, limited_docs)
248
- end
249
267
  end
250
268
  cursor || QueryCache.cache_table[cache_key]
251
269
  end
252
270
 
271
+ def get_cursor(result, server, session = nil)
272
+ if result.cursor_id == 0 || result.cursor_id.nil?
273
+ cursor = if session
274
+ CachedCursor.new(view, result, server, session: session)
275
+ else
276
+ CachedCursor.new(view, result, server)
277
+ end
278
+
279
+ QueryCache.cache_table[cache_key] = cursor
280
+ else
281
+ cursor = if session
282
+ Mongo::Cursor.new(view, result, server, session: session)
283
+ else
284
+ Mongo::Cursor.new(view, result, server)
285
+ end
286
+ end
287
+
288
+ cursor
289
+ end
290
+
253
291
  def cache_key
254
292
  [ collection.namespace, selector, limit, skip, sort, projection, collation ]
255
293
  end
@@ -257,6 +295,12 @@ module Mongoid
257
295
  def system_collection?
258
296
  collection.namespace =~ /^system./
259
297
  end
298
+
299
+ def driver_supports_cursor_sessions?
300
+ # Driver versions 2.9 and newer support passing in a session to the
301
+ # cursor object.
302
+ (Mongo::VERSION.split('.').map(&:to_i) <=> [2, 9, 0]) > 0
303
+ end
260
304
  end
261
305
 
262
306
  # Adds behaviour to the query cache for collections.