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
@@ -4,241 +4,85 @@ module Mongoid
4
4
  module Options
5
5
  extend ActiveSupport::Concern
6
6
 
7
- # Tell the next persistence operation to store in a specific collection,
8
- # database or client.
7
+ # Change the persistence context for this object during the block.
9
8
  #
10
9
  # @example Save the current document to a different collection.
11
- # model.with(collection: "secondary").save
10
+ # model.with(collection: "secondary") do |m|
11
+ # m.save
12
+ # end
12
13
  #
13
- # @example Save the current document to a different database.
14
- # model.with(database: "secondary").save
15
- #
16
- # @example Save the current document to a different client.
17
- # model.with(client: "replica_set").save
18
- #
19
- # @example Save with a combination of options.
20
- # model.with(client: "sharded", database: "secondary").save
21
- #
22
- # @note This method will instantiate a new client under the covers and
23
- # can be expensive. It is also recommended that the user manually
24
- # closes the extra client after using it, otherwise an excessive amount
25
- # of connections to the server will be eventually opened.
26
- #
27
- # @param [ Hash ] options The storage options.
14
+ # @param [ Hash, Mongoid::PersistenceContext ] options_or_context
15
+ # The storage options or a persistence context.
28
16
  #
29
17
  # @option options [ String, Symbol ] :collection The collection name.
30
18
  # @option options [ String, Symbol ] :database The database name.
31
19
  # @option options [ String, Symbol ] :client The client name.
32
20
  #
33
- # @return [ Document ] The current document.
34
- #
35
- # @since 3.0.0
36
- def with(options)
37
- @persistence_options = options
38
- self
21
+ # @since 6.0.0
22
+ def with(options_or_context, &block)
23
+ original_cluster = persistence_context.cluster
24
+ set_persistence_context(options_or_context)
25
+ yield self
26
+ ensure
27
+ clear_persistence_context(original_cluster)
39
28
  end
40
29
 
41
- def persistence_options
42
- @persistence_options
43
- end
44
-
45
- def mongo_client
46
- tmp = persistence_options
47
- if (opts = tmp && !tmp.empty? && tmp.dup)
48
- if opts[:client]
49
- client = Clients.with_name(opts[:client])
50
- else
51
- client = Clients.with_name(self.class.client_name)
52
- client = client.use(self.class.database_name)
53
- end
54
- client.with(opts.reject{ |k, v| k == :collection || k == :client })
55
- end
30
+ def collection(parent = nil)
31
+ persistence_context.collection(parent)
56
32
  end
57
33
 
58
34
  def collection_name
59
- if persistence_options && v = persistence_options[:collection]
60
- return v.to_sym
61
- end
35
+ persistence_context.collection_name
62
36
  end
63
37
 
64
- module Threaded
65
-
66
- # Get the persistence options for the current thread.
67
- #
68
- # @example Get the persistence options.
69
- # Threaded.persistence_options(Band)
70
- #
71
- # @param [ Class ] klass The model class.
72
- #
73
- # @return [ Hash ] The current persistence options.
74
- #
75
- # @since 4.0.0
76
- def persistence_options(klass = self)
77
- Thread.current["[mongoid][#{klass}]:persistence-options"]
78
- end
79
-
80
- # Get the client with special options for the current thread.
81
- #
82
- # @example Get the client with options.
83
- # Threaded.client_with_options(Band)
84
- #
85
- # @param [ Class ] klass The model class.
86
- #
87
- # @return [ Mongo::Client ] The client.
88
- #
89
- # @since 5.1.0
90
- def client_with_options(klass = self)
91
- Thread.current["[mongoid][#{klass}]:mongo-client"]
92
- end
93
-
94
- private
95
- # Set the persistence options on the current thread.
96
- #
97
- # @api private
98
- #
99
- # @example Set the persistence options.
100
- # Threaded.set_persistence_options(Band, { write: { w: 3 }})
101
- #
102
- # @param [ Class ] klass The model class.
103
- # @param [ Hash ] options The persistence options.
104
- #
105
- # @return [ Hash ] The persistence options.
106
- #
107
- # @since 4.0.0
108
- def set_persistence_options(klass, options)
109
- Thread.current["[mongoid][#{klass}]:persistence-options"] = options
110
- end
111
-
112
- # Unset the persistence options on the current thread.
113
- #
114
- # @api private
115
- #
116
- # @example Unset the persistence options.
117
- # Threaded.unset_persistence_options(Band)
118
- #
119
- # @param [ Class ] klass The model class.
120
- #
121
- # @return [ nil ] nil.
122
- #
123
- # @since 5.1.0
124
- def unset_persistence_options(klass)
125
- Thread.current["[mongoid][#{klass}]:persistence-options"] = nil
126
- end
127
-
128
- # Set the persistence options and client with those options on the current thread.
129
- # Note that a client will only be set if its cluster differs from the cluster of the
130
- # original client.
131
- #
132
- # @api private
133
- #
134
- # @example Set the persistence options and client with those options on the current thread.
135
- # Threaded.set_options(Band, { write: { w: 3 }})
136
- #
137
- # @param [ Class ] klass The model class.
138
- # @param [ Mongo::Client ] options The options.
139
- #
140
- # @return [ Mongo::Client, nil ] The client or nil if the cluster does not change.
141
- #
142
- # @since 5.1.0
143
- def set_options(klass, options)
144
- original_cluster = mongo_client.cluster
145
- set_persistence_options(klass, options)
146
- m = mongo_client
147
- set_client_with_options(klass, m) unless m.cluster.equal?(original_cluster)
148
- end
38
+ def mongo_client
39
+ persistence_context.client
40
+ end
41
+
42
+ def persistence_context
43
+ PersistenceContext.get(self) ||
44
+ PersistenceContext.get(self.class) ||
45
+ PersistenceContext.new(self.class)
46
+ end
149
47
 
150
- # Set the client with special options on the current thread.
151
- #
152
- # @api private
153
- #
154
- # @example Set the client with options.
155
- # Threaded.set_client_with_options(Band, client)
156
- #
157
- # @param [ Class ] klass The model class.
158
- # @param [ Mongo::Client ] client The client with options.
159
- #
160
- # @return [ Mongo::Client ] The client.
161
- #
162
- # @since 5.1.0
163
- def set_client_with_options(klass, client)
164
- Thread.current["[mongoid][#{klass}]:mongo-client"] = client
165
- end
48
+ private
166
49
 
167
- # Unset the client with special options on the current thread.
168
- #
169
- # @api private
170
- #
171
- # @example Unset the client with options.
172
- # Threaded.unset_client_with_options(Band)
173
- #
174
- # @param [ Class ] klass The model class.
175
- #
176
- # @return [ nil ] nil.
177
- #
178
- # @since 5.1.0
179
- def unset_client_with_options(klass)
180
- if client = Thread.current["[mongoid][#{klass}]:mongo-client"]
181
- client.close
182
- Thread.current["[mongoid][#{klass}]:mongo-client"] = nil
183
- end
184
- end
50
+ def set_persistence_context(options_or_context)
51
+ PersistenceContext.set(self, options_or_context)
52
+ end
185
53
 
186
- # Unset the persistence options and client with special options on the current thread.
187
- #
188
- # @api private
189
- #
190
- # @example Unset the persistence options and client with options.
191
- # Threaded.unset_options(Band)
192
- #
193
- # @param [ Class ] klass The model class.
194
- #
195
- # @return [ nil ] nil.
196
- #
197
- # @since 5.1.0
198
- def unset_options(klass)
199
- unset_persistence_options(klass)
200
- unset_client_with_options(klass)
201
- end
54
+ def clear_persistence_context(original_cluster = nil)
55
+ PersistenceContext.clear(self, original_cluster)
202
56
  end
203
57
 
204
58
  module ClassMethods
205
- include Threaded
206
59
 
207
60
  def client_name
208
- if persistence_options && v = persistence_options[:client]
209
- return v.to_sym
210
- end
211
- super
61
+ persistence_context.client_name
212
62
  end
213
63
 
214
64
  def collection_name
215
- if persistence_options && v = persistence_options[:collection]
216
- return v.to_sym
217
- end
218
- super
65
+ persistence_context.collection_name
219
66
  end
220
67
 
221
68
  def database_name
222
- if persistence_options && v = persistence_options[:database]
223
- return v.to_sym
224
- end
225
- super
69
+ persistence_context.database_name
226
70
  end
227
71
 
228
- # Tell the next persistence operation to store in a specific collection,
229
- # database or client.
230
- #
231
- # @example Create a document in a different collection.
232
- # Model.with(collection: "secondary").create(name: "test")
233
- #
234
- # @example Create a document in a different database.
235
- # Model.with(database: "secondary").create(name: "test")
236
- #
237
- # @example Create a document in a different client.
238
- # Model.with(client: "secondary").create(name: "test")
72
+ def collection
73
+ persistence_context.collection
74
+ end
75
+
76
+ def mongo_client
77
+ persistence_context.client
78
+ end
79
+
80
+ # Change the persistence context for this class during the block.
239
81
  #
240
- # @example Create with a combination of options.
241
- # Model.with(client: "sharded", database: "secondary").create
82
+ # @example Save the current document to a different collection.
83
+ # Model.with(collection: "secondary") do |m|
84
+ # m.create
85
+ # end
242
86
  #
243
87
  # @param [ Hash ] options The storage options.
244
88
  #
@@ -246,56 +90,17 @@ module Mongoid
246
90
  # @option options [ String, Symbol ] :database The database name.
247
91
  # @option options [ String, Symbol ] :client The client name.
248
92
  #
249
- # @return [ Class ] The model class.
250
- #
251
- # @since 3.0.0
252
- def with(options)
253
- if block_given?
254
- set_options(self, options)
255
- result = yield self
256
- unset_options(self)
257
- result
258
- else
259
- Proxy.new(self, (persistence_options || {}).merge(options))
260
- end
261
- end
262
- end
263
-
264
- class Proxy < BasicObject
265
- include Threaded
266
-
267
- undef_method :==
268
-
269
- def initialize(target, options)
270
- @target = target
271
- @options = options
272
- end
273
-
274
- def persistence_options
275
- @options
276
- end
277
-
278
- def respond_to?(*args)
279
- @target.respond_to?(*args)
280
- end
281
-
282
- def method_missing(name, *args, &block)
283
- set_persistence_options(@target, @options)
284
- ret = @target.send(name, *args, &block)
285
- if Mongoid::Criteria == ret.class
286
- ret.with @options
287
- end
288
- ret
93
+ # @since 6.0.0
94
+ def with(options, &block)
95
+ original_cluster = persistence_context.cluster
96
+ PersistenceContext.set(self, options)
97
+ yield self
289
98
  ensure
290
- unset_persistence_options(@target)
291
- end
292
-
293
- def send(symbol, *args)
294
- __send__(symbol, *args)
99
+ PersistenceContext.clear(self, original_cluster)
295
100
  end
296
101
 
297
- def self.const_missing(name)
298
- ::Object.const_get(name)
102
+ def persistence_context
103
+ PersistenceContext.get(self) || PersistenceContext.new(self)
299
104
  end
300
105
  end
301
106
  end
@@ -0,0 +1,113 @@
1
+ module Mongoid
2
+ module Clients
3
+
4
+ # Encapsulates behavior for getting a session from the client of a model class or instance,
5
+ # setting the session on the current thread, and yielding to a block.
6
+ # The session will be closed after the block completes or raises an error.
7
+ #
8
+ # @since 6.4.0
9
+ module Sessions
10
+
11
+ # Execute a block within the context of a session.
12
+ #
13
+ # @example Execute some operations in the context of a session.
14
+ # band.with_session(causal_consistency: true) do
15
+ # band.records << Record.create
16
+ # band.name = 'FKA Twigs'
17
+ # band.save
18
+ # band.reload
19
+ # end
20
+ #
21
+ # @param [ Hash ] options The session options. Please see the driver
22
+ # documentation for the available session options.
23
+ #
24
+ # @note You cannot do any operations in the block using models or objects
25
+ # that use a different client; the block will execute all operations
26
+ # in the context of the implicit session and operations on any models using
27
+ # another client will fail. For example, if you set a client using store_in on a
28
+ # particular model and execute an operation on it in the session context block,
29
+ # that operation can't use the block's session and an error will be raised.
30
+ # An error will also be raised if sessions are nested.
31
+ #
32
+ # @raise [ Errors::InvalidSessionUse ] If an operation is attempted on a model using another
33
+ # client from which the session was started or if sessions are nested.
34
+ #
35
+ # @return [ Object ] The result of calling the block.
36
+ #
37
+ # @yieldparam [ Mongo::Session ] The session being used for the block.
38
+ #
39
+ # @since 6.4.0
40
+ def with_session(options = {})
41
+ raise Mongoid::Errors::InvalidSessionUse.new(:invalid_session_nesting) if Threaded.get_session
42
+ session = persistence_context.client.start_session(options)
43
+ Threaded.set_session(session)
44
+ yield(session)
45
+ rescue Mongo::Error::InvalidSession => ex
46
+ if ex.message == Mongo::Session::SESSIONS_NOT_SUPPORTED
47
+ raise Mongoid::Errors::InvalidSessionUse.new(:sessions_not_supported)
48
+ end
49
+ raise Mongoid::Errors::InvalidSessionUse.new(:invalid_session_use)
50
+ ensure
51
+ Threaded.clear_session
52
+ end
53
+
54
+ private
55
+
56
+ def _session
57
+ Threaded.get_session
58
+ end
59
+
60
+ module ClassMethods
61
+
62
+ # Execute a block within the context of a session.
63
+ #
64
+ # @example Execute some operations in the context of a session.
65
+ # Band.with_session(causal_consistency: true) do
66
+ # band = Band.create
67
+ # band.records << Record.new
68
+ # band.save
69
+ # band.reload.records
70
+ # end
71
+ #
72
+ # @param [ Hash ] options The session options. Please see the driver
73
+ # documentation for the available session options.
74
+ #
75
+ # @note You cannot do any operations in the block using models or objects
76
+ # that use a different client; the block will execute all operations
77
+ # in the context of the implicit session and operations on any models using
78
+ # another client will fail. For example, if you set a client using store_in on a
79
+ # particular model and execute an operation on it in the session context block,
80
+ # that operation can't use the block's session and an error will be raised.
81
+ # You also cannot nest sessions.
82
+ #
83
+ # @raise [ Errors::InvalidSessionUse ] If an operation is attempted on a model using another
84
+ # client from which the session was started or if sessions are nested.
85
+ #
86
+ # @return [ Object ] The result of calling the block.
87
+ #
88
+ # @yieldparam [ Mongo::Session ] The session being used for the block.
89
+ #
90
+ # @since 6.4.0
91
+ def with_session(options = {})
92
+ raise Mongoid::Errors::InvalidSessionUse.new(:invalid_session_nesting) if Threaded.get_session
93
+ session = persistence_context.client.start_session(options)
94
+ Threaded.set_session(session)
95
+ yield(session)
96
+ rescue Mongo::Error::InvalidSession => ex
97
+ if ex.message == Mongo::Session::SESSIONS_NOT_SUPPORTED
98
+ raise Mongoid::Errors::InvalidSessionUse.new(:sessions_not_supported)
99
+ end
100
+ raise Mongoid::Errors::InvalidSessionUse.new(:invalid_session_use)
101
+ ensure
102
+ Threaded.clear_session
103
+ end
104
+
105
+ private
106
+
107
+ def _session
108
+ Threaded.get_session
109
+ end
110
+ end
111
+ end
112
+ end
113
+ end
@@ -61,6 +61,7 @@ module Mongoid
61
61
  # @since 4.0.0
62
62
  def reset_storage_options!
63
63
  self.storage_options = storage_options_defaults.dup
64
+ PersistenceContext.clear(self)
64
65
  end
65
66
 
66
67
  # Get the default storage options.
@@ -74,77 +75,9 @@ module Mongoid
74
75
  def storage_options_defaults
75
76
  {
76
77
  collection: name.collectionize.to_sym,
77
- client: :default,
78
- database: -> { configured_database }
78
+ client: :default
79
79
  }
80
80
  end
81
-
82
- # Get the name of the collection this model persists to.
83
- #
84
- # @example Get the collection name.
85
- # Model.collection_name
86
- #
87
- # @return [ Symbol ] The name of the collection.
88
- #
89
- # @since 3.0.0
90
- def collection_name
91
- __evaluate__(storage_options[:collection])
92
- end
93
-
94
- # Get the client name for the model.
95
- #
96
- # @example Get the client name.
97
- # Model.client_name
98
- #
99
- # @return [ Symbol ] The name of the client.
100
- #
101
- # @since 3.0.0
102
- def client_name
103
- __evaluate__(storage_options[:client])
104
- end
105
-
106
- # Get the database name for the model.
107
- #
108
- # @example Get the database name.
109
- # Model.database_name
110
- #
111
- # @return [ Symbol ] The name of the client.
112
- #
113
- # @since 4.0.0
114
- def database_name
115
- __evaluate__(storage_options[:database])
116
- end
117
-
118
- private
119
-
120
- # Eval the provided value, either byt calling it if it responds to call
121
- # or returning the value itself.
122
- #
123
- # @api private
124
- #
125
- # @example Evaluate the name.
126
- # Model.__evaluate__(:name)
127
- #
128
- # @param [ String, Symbol, Proc ] name The name.
129
- #
130
- # @return [ Symbol ] The value as a symbol.
131
- #
132
- # @since 3.1.0
133
- def __evaluate__(name)
134
- return nil unless name
135
- name.respond_to?(:call) ? name.call.to_sym : name.to_sym
136
- end
137
-
138
- def configured_database
139
- client = Mongoid.clients[client_name]
140
- if db = client[:database]
141
- db
142
- elsif uri = client[:uri]
143
- client[:database] = Mongo::URI.new(uri).database
144
- else
145
- nil
146
- end
147
- end
148
81
  end
149
82
  end
150
83
  end
@@ -2,15 +2,15 @@
2
2
  require "mongoid/clients/factory"
3
3
  require "mongoid/clients/validators"
4
4
  require "mongoid/clients/storage_options"
5
- require "mongoid/clients/thread_options"
6
5
  require "mongoid/clients/options"
6
+ require "mongoid/clients/sessions"
7
7
 
8
8
  module Mongoid
9
9
  module Clients
10
10
  extend ActiveSupport::Concern
11
11
  include StorageOptions
12
- include ThreadOptions
13
12
  include Options
13
+ include Sessions
14
14
 
15
15
  class << self
16
16
 
@@ -35,7 +35,7 @@ module Mongoid
35
35
  #
36
36
  # @since 3.0.0
37
37
  def default
38
- clients[:default] ||= Clients::Factory.default
38
+ with_name(:default)
39
39
  end
40
40
 
41
41
  # Disconnect all active clients.
@@ -63,7 +63,11 @@ module Mongoid
63
63
  #
64
64
  # @since 3.0.0
65
65
  def with_name(name)
66
- clients[name.to_sym] ||= Clients::Factory.create(name)
66
+ name_as_symbol = name.to_sym
67
+ return clients[name_as_symbol] if clients[name_as_symbol]
68
+ CREATE_LOCK.synchronize do
69
+ clients[name_as_symbol] ||= Clients::Factory.create(name)
70
+ end
67
71
  end
68
72
 
69
73
  def set(name, client)
@@ -73,67 +77,10 @@ module Mongoid
73
77
  def clients
74
78
  @clients ||= {}
75
79
  end
76
- end
77
-
78
- # Get the collection for this model from the client. Will check for an
79
- # overridden collection name from the store_in macro or the collection
80
- # with a pluralized model name.
81
- #
82
- # @example Get the model's collection.
83
- # Model.collection
84
- #
85
- # @return [ Mongo::Collection ] The collection.
86
- #
87
- # @since 3.0.0
88
- def collection
89
- mongo_client[collection_name]
90
- end
91
80
 
92
- def mongo_client
93
- super || self.class.mongo_client
94
- end
81
+ private
95
82
 
96
- def collection_name
97
- super || self.class.collection_name
98
- end
99
-
100
- module ClassMethods
101
-
102
- # Get the client for this model. This is determined in the following order:
103
- #
104
- # 1. Any custom configuration provided by the 'store_in' macro.
105
- # 2. The 'default' client as provided in the mongoid.yml
106
- #
107
- # @example Get the client.
108
- # Model.mongo_client
109
- #
110
- # @return [ Mongo::Client ] The default mongo client.
111
- #
112
- # @since 3.0.0
113
- def mongo_client
114
- return client_with_options if client_with_options
115
- client = Clients.with_name(client_name)
116
- opts = self.persistence_options ? self.persistence_options.dup : {}
117
- if defined?(Mongo::Client::VALID_OPTIONS)
118
- opts.reject! { |k, v| !Mongo::Client::VALID_OPTIONS.include?(k.to_sym) }
119
- end
120
- opts.merge!(database: database_name) unless client.database.name.to_sym == database_name.to_sym
121
- client.with(opts)
122
- end
123
-
124
- # Get the collection for this model from the client. Will check for an
125
- # overridden collection name from the store_in macro or the collection
126
- # with a pluralized model name.
127
- #
128
- # @example Get the model's collection.
129
- # Model.collection
130
- #
131
- # @return [ Mongo::Collection ] The collection.
132
- #
133
- # @since 3.0.0
134
- def collection
135
- mongo_client[collection_name]
136
- end
83
+ CREATE_LOCK = Mutex.new
137
84
  end
138
85
  end
139
86
  end