mongoid 5.4.0 → 6.4.8

Sign up to get free protection for your applications and to get access to all the features.
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