mongoid 5.4.1 → 6.1.1

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 (260) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +3 -3
  3. data/lib/config/locales/en.yml +19 -0
  4. data/lib/mongoid.rb +4 -4
  5. data/lib/mongoid/atomic.rb +2 -2
  6. data/lib/mongoid/atomic/modifiers.rb +8 -12
  7. data/lib/mongoid/attributes.rb +22 -21
  8. data/lib/mongoid/attributes/readonly.rb +22 -0
  9. data/lib/mongoid/cacheable.rb +36 -0
  10. data/lib/mongoid/changeable.rb +36 -0
  11. data/lib/mongoid/clients.rb +8 -63
  12. data/lib/mongoid/clients/options.rb +55 -250
  13. data/lib/mongoid/clients/storage_options.rb +1 -69
  14. data/lib/mongoid/composable.rb +29 -3
  15. data/lib/mongoid/config.rb +1 -0
  16. data/lib/mongoid/contextual/atomic.rb +5 -8
  17. data/lib/mongoid/contextual/map_reduce.rb +0 -4
  18. data/lib/mongoid/contextual/memory.rb +2 -2
  19. data/lib/mongoid/contextual/mongo.rb +40 -22
  20. data/lib/mongoid/contextual/none.rb +12 -0
  21. data/lib/mongoid/copyable.rb +13 -6
  22. data/lib/mongoid/criteria.rb +5 -2
  23. data/lib/mongoid/criteria/marshalable.rb +2 -2
  24. data/lib/mongoid/criteria/modifiable.rb +17 -1
  25. data/lib/mongoid/criteria/options.rb +25 -0
  26. data/lib/mongoid/criteria/queryable.rb +87 -0
  27. data/lib/mongoid/criteria/queryable/aggregable.rb +120 -0
  28. data/lib/mongoid/criteria/queryable/extensions.rb +28 -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/forwardable.rb +65 -0
  46. data/lib/mongoid/criteria/queryable/key.rb +103 -0
  47. data/lib/mongoid/criteria/queryable/macroable.rb +27 -0
  48. data/lib/mongoid/criteria/queryable/mergeable.rb +271 -0
  49. data/lib/mongoid/criteria/queryable/optional.rb +429 -0
  50. data/lib/mongoid/criteria/queryable/options.rb +153 -0
  51. data/lib/mongoid/criteria/queryable/pipeline.rb +111 -0
  52. data/lib/mongoid/criteria/queryable/selectable.rb +662 -0
  53. data/lib/mongoid/criteria/queryable/selector.rb +212 -0
  54. data/lib/mongoid/criteria/queryable/smash.rb +104 -0
  55. data/lib/mongoid/document.rb +30 -37
  56. data/lib/mongoid/errors.rb +2 -0
  57. data/lib/mongoid/errors/ambiguous_relationship.rb +1 -1
  58. data/lib/mongoid/errors/in_memory_collation_not_supported.rb +1 -1
  59. data/lib/mongoid/errors/invalid_field.rb +2 -2
  60. data/lib/mongoid/errors/invalid_persistence_option.rb +29 -0
  61. data/lib/mongoid/errors/invalid_relation.rb +66 -0
  62. data/lib/mongoid/evolvable.rb +1 -1
  63. data/lib/mongoid/extensions.rb +0 -4
  64. data/lib/mongoid/extensions/big_decimal.rb +17 -8
  65. data/lib/mongoid/extensions/date.rb +4 -1
  66. data/lib/mongoid/extensions/decimal128.rb +3 -3
  67. data/lib/mongoid/extensions/hash.rb +1 -0
  68. data/lib/mongoid/extensions/string.rb +4 -3
  69. data/lib/mongoid/extensions/time.rb +4 -1
  70. data/lib/mongoid/fields/validators/macro.rb +18 -0
  71. data/lib/mongoid/findable.rb +2 -2
  72. data/lib/mongoid/indexable.rb +15 -13
  73. data/lib/mongoid/interceptable.rb +5 -22
  74. data/lib/mongoid/matchable.rb +13 -7
  75. data/lib/mongoid/matchable/all.rb +2 -2
  76. data/lib/mongoid/matchable/and.rb +3 -3
  77. data/lib/mongoid/matchable/default.rb +2 -2
  78. data/lib/mongoid/matchable/elem_match.rb +28 -0
  79. data/lib/mongoid/matchable/exists.rb +2 -2
  80. data/lib/mongoid/matchable/gt.rb +4 -2
  81. data/lib/mongoid/matchable/gte.rb +4 -2
  82. data/lib/mongoid/matchable/in.rb +2 -2
  83. data/lib/mongoid/matchable/lt.rb +4 -2
  84. data/lib/mongoid/matchable/lte.rb +4 -2
  85. data/lib/mongoid/matchable/ne.rb +2 -2
  86. data/lib/mongoid/matchable/nin.rb +2 -2
  87. data/lib/mongoid/matchable/or.rb +3 -3
  88. data/lib/mongoid/matchable/regexp.rb +3 -3
  89. data/lib/mongoid/matchable/size.rb +2 -2
  90. data/lib/mongoid/persistable.rb +3 -5
  91. data/lib/mongoid/persistable/creatable.rb +2 -2
  92. data/lib/mongoid/persistable/deletable.rb +1 -1
  93. data/lib/mongoid/persistable/settable.rb +1 -1
  94. data/lib/mongoid/persistable/updatable.rb +5 -12
  95. data/lib/mongoid/persistable/upsertable.rb +1 -1
  96. data/lib/mongoid/persistence_context.rb +215 -0
  97. data/lib/mongoid/query_cache.rb +3 -6
  98. data/lib/mongoid/relations/accessors.rb +3 -0
  99. data/lib/mongoid/relations/auto_save.rb +12 -4
  100. data/lib/mongoid/relations/bindings/referenced/many_to_many.rb +4 -4
  101. data/lib/mongoid/relations/counter_cache.rb +15 -5
  102. data/lib/mongoid/relations/eager.rb +6 -11
  103. data/lib/mongoid/relations/eager/base.rb +3 -3
  104. data/lib/mongoid/relations/eager/has_and_belongs_to_many.rb +2 -2
  105. data/lib/mongoid/relations/eager/has_many.rb +1 -1
  106. data/lib/mongoid/relations/embedded/batchable.rb +12 -36
  107. data/lib/mongoid/relations/embedded/in.rb +13 -1
  108. data/lib/mongoid/relations/embedded/many.rb +28 -10
  109. data/lib/mongoid/relations/embedded/one.rb +14 -1
  110. data/lib/mongoid/relations/macros.rb +9 -1
  111. data/lib/mongoid/relations/metadata.rb +3 -3
  112. data/lib/mongoid/relations/options.rb +2 -2
  113. data/lib/mongoid/relations/proxy.rb +1 -31
  114. data/lib/mongoid/relations/referenced/in.rb +19 -10
  115. data/lib/mongoid/relations/referenced/many.rb +23 -17
  116. data/lib/mongoid/relations/referenced/many_to_many.rb +20 -13
  117. data/lib/mongoid/relations/referenced/one.rb +15 -1
  118. data/lib/mongoid/relations/synchronization.rb +11 -11
  119. data/lib/mongoid/relations/touchable.rb +6 -3
  120. data/lib/mongoid/reloadable.rb +1 -1
  121. data/lib/mongoid/serializable.rb +1 -1
  122. data/lib/mongoid/traversable.rb +1 -1
  123. data/lib/mongoid/validatable/uniqueness.rb +1 -2
  124. data/lib/mongoid/version.rb +1 -1
  125. data/lib/rails/generators/mongoid/config/templates/mongoid.yml +14 -3
  126. data/spec/app/models/album.rb +5 -1
  127. data/spec/app/models/artist.rb +21 -0
  128. data/spec/app/models/book.rb +2 -1
  129. data/spec/app/models/dokument.rb +1 -0
  130. data/spec/app/models/ordered_post.rb +5 -0
  131. data/spec/app/models/oscar.rb +1 -2
  132. data/spec/app/models/page.rb +1 -1
  133. data/spec/app/models/person.rb +3 -3
  134. data/spec/app/models/princess.rb +2 -0
  135. data/spec/app/models/record.rb +1 -0
  136. data/spec/app/models/subscription.rb +1 -0
  137. data/spec/app/models/thing.rb +1 -1
  138. data/spec/config/mongoid.yml +15 -0
  139. data/spec/mongoid/atomic/modifiers_spec.rb +17 -17
  140. data/spec/mongoid/atomic_spec.rb +17 -17
  141. data/spec/mongoid/attributes/nested_spec.rb +14 -14
  142. data/spec/mongoid/attributes/readonly_spec.rb +87 -44
  143. data/spec/mongoid/attributes_spec.rb +90 -5
  144. data/spec/mongoid/cacheable_spec.rb +112 -0
  145. data/spec/mongoid/changeable_spec.rb +58 -0
  146. data/spec/mongoid/clients/factory_spec.rb +31 -3
  147. data/spec/mongoid/clients/options_spec.rb +382 -96
  148. data/spec/mongoid/clients_spec.rb +243 -101
  149. data/spec/mongoid/composable_spec.rb +7 -0
  150. data/spec/mongoid/config_spec.rb +67 -11
  151. data/spec/mongoid/contextual/atomic_spec.rb +3 -3
  152. data/spec/mongoid/contextual/mongo_spec.rb +165 -20
  153. data/spec/mongoid/contextual/none_spec.rb +15 -0
  154. data/spec/mongoid/copyable_spec.rb +13 -4
  155. data/spec/mongoid/criteria/modifiable_spec.rb +239 -7
  156. data/spec/mongoid/criteria/options_spec.rb +29 -0
  157. data/spec/mongoid/criteria/queryable/aggregable_spec.rb +370 -0
  158. data/spec/mongoid/criteria/queryable/extensions/array_spec.rb +523 -0
  159. data/spec/mongoid/criteria/queryable/extensions/big_decimal_spec.rb +59 -0
  160. data/spec/mongoid/criteria/queryable/extensions/bignum_spec.rb +58 -0
  161. data/spec/mongoid/criteria/queryable/extensions/boolean_spec.rb +213 -0
  162. data/spec/mongoid/criteria/queryable/extensions/date_spec.rb +330 -0
  163. data/spec/mongoid/criteria/queryable/extensions/date_time_spec.rb +405 -0
  164. data/spec/mongoid/criteria/queryable/extensions/fixnum_spec.rb +58 -0
  165. data/spec/mongoid/criteria/queryable/extensions/float_spec.rb +65 -0
  166. data/spec/mongoid/criteria/queryable/extensions/hash_spec.rb +327 -0
  167. data/spec/mongoid/criteria/queryable/extensions/integer_spec.rb +65 -0
  168. data/spec/mongoid/criteria/queryable/extensions/nil_class_spec.rb +77 -0
  169. data/spec/mongoid/criteria/queryable/extensions/object_spec.rb +108 -0
  170. data/spec/mongoid/criteria/queryable/extensions/range_spec.rb +309 -0
  171. data/spec/mongoid/{extensions/origin → criteria/queryable/extensions}/regexp_raw_spec.rb +2 -2
  172. data/spec/mongoid/criteria/queryable/extensions/regexp_spec.rb +90 -0
  173. data/spec/mongoid/criteria/queryable/extensions/set_spec.rb +39 -0
  174. data/spec/mongoid/criteria/queryable/extensions/string_spec.rb +302 -0
  175. data/spec/mongoid/criteria/queryable/extensions/symbol_spec.rb +167 -0
  176. data/spec/mongoid/criteria/queryable/extensions/time_spec.rb +376 -0
  177. data/spec/mongoid/criteria/queryable/extensions/time_with_zone_spec.rb +347 -0
  178. data/spec/mongoid/criteria/queryable/forwardable_spec.rb +87 -0
  179. data/spec/mongoid/criteria/queryable/key_spec.rb +52 -0
  180. data/spec/mongoid/criteria/queryable/mergeable_spec.rb +49 -0
  181. data/spec/mongoid/criteria/queryable/optional_spec.rb +1799 -0
  182. data/spec/mongoid/criteria/queryable/options_spec.rb +360 -0
  183. data/spec/mongoid/criteria/queryable/pipeline_spec.rb +200 -0
  184. data/spec/mongoid/criteria/queryable/queryable_spec.rb +137 -0
  185. data/spec/mongoid/criteria/queryable/selectable_spec.rb +4174 -0
  186. data/spec/mongoid/criteria/queryable/selector_spec.rb +844 -0
  187. data/spec/mongoid/criteria/queryable/smash_spec.rb +30 -0
  188. data/spec/mongoid/criteria_spec.rb +152 -21
  189. data/spec/mongoid/document_spec.rb +37 -88
  190. data/spec/mongoid/errors/invalid_relation_spec.rb +37 -0
  191. data/spec/mongoid/errors/mongoid_error_spec.rb +6 -3
  192. data/spec/mongoid/extensions/big_decimal_spec.rb +320 -18
  193. data/spec/mongoid/extensions/boolean_spec.rb +14 -0
  194. data/spec/mongoid/extensions/date_spec.rb +2 -6
  195. data/spec/mongoid/extensions/date_time_spec.rb +2 -6
  196. data/spec/mongoid/extensions/decimal128_spec.rb +1 -1
  197. data/spec/mongoid/extensions/float_spec.rb +8 -1
  198. data/spec/mongoid/extensions/hash_spec.rb +15 -0
  199. data/spec/mongoid/extensions/integer_spec.rb +8 -1
  200. data/spec/mongoid/extensions/object_spec.rb +11 -0
  201. data/spec/mongoid/extensions/string_spec.rb +21 -0
  202. data/spec/mongoid/extensions/time_spec.rb +2 -6
  203. data/spec/mongoid/extensions/time_with_zone_spec.rb +2 -6
  204. data/spec/mongoid/findable_spec.rb +46 -1
  205. data/spec/mongoid/indexable_spec.rb +15 -3
  206. data/spec/mongoid/interceptable_spec.rb +68 -10
  207. data/spec/mongoid/matchable/all_spec.rb +4 -4
  208. data/spec/mongoid/matchable/and_spec.rb +10 -10
  209. data/spec/mongoid/matchable/default_spec.rb +12 -12
  210. data/spec/mongoid/matchable/elem_match_spec.rb +86 -0
  211. data/spec/mongoid/matchable/exists_spec.rb +5 -5
  212. data/spec/mongoid/matchable/gt_spec.rb +18 -7
  213. data/spec/mongoid/matchable/gte_spec.rb +17 -7
  214. data/spec/mongoid/matchable/in_spec.rb +5 -5
  215. data/spec/mongoid/matchable/lt_spec.rb +18 -7
  216. data/spec/mongoid/matchable/lte_spec.rb +18 -7
  217. data/spec/mongoid/matchable/ne_spec.rb +5 -5
  218. data/spec/mongoid/matchable/nin_spec.rb +5 -5
  219. data/spec/mongoid/matchable/or_spec.rb +7 -7
  220. data/spec/mongoid/matchable/regexp_spec.rb +5 -5
  221. data/spec/mongoid/matchable/size_spec.rb +3 -3
  222. data/spec/mongoid/matchable_spec.rb +173 -53
  223. data/spec/mongoid/persistable/creatable_spec.rb +7 -2
  224. data/spec/mongoid/persistable/deletable_spec.rb +16 -1
  225. data/spec/mongoid/persistable/destroyable_spec.rb +6 -2
  226. data/spec/mongoid/persistable/savable_spec.rb +35 -30
  227. data/spec/mongoid/persistable/settable_spec.rb +45 -29
  228. data/spec/mongoid/persistable/updatable_spec.rb +184 -5
  229. data/spec/mongoid/persistence_context_spec.rb +680 -0
  230. data/spec/mongoid/positional_spec.rb +10 -10
  231. data/spec/mongoid/query_cache_spec.rb +89 -0
  232. data/spec/mongoid/relations/accessors_spec.rb +1 -1
  233. data/spec/mongoid/relations/auto_save_spec.rb +39 -6
  234. data/spec/mongoid/relations/bindings/referenced/many_to_many_spec.rb +4 -4
  235. data/spec/mongoid/relations/builders_spec.rb +37 -10
  236. data/spec/mongoid/relations/counter_cache_spec.rb +64 -3
  237. data/spec/mongoid/relations/eager/has_and_belongs_to_many_spec.rb +16 -0
  238. data/spec/mongoid/relations/eager_spec.rb +40 -0
  239. data/spec/mongoid/relations/embedded/many_spec.rb +63 -47
  240. data/spec/mongoid/relations/embedded/one_spec.rb +2 -1
  241. data/spec/mongoid/relations/macros_spec.rb +395 -7
  242. data/spec/mongoid/relations/metadata_spec.rb +15 -1
  243. data/spec/mongoid/relations/proxy_spec.rb +27 -1
  244. data/spec/mongoid/relations/referenced/in_spec.rb +41 -1
  245. data/spec/mongoid/relations/referenced/many_spec.rb +13 -25
  246. data/spec/mongoid/relations/referenced/many_to_many_spec.rb +14 -26
  247. data/spec/mongoid/relations/synchronization_spec.rb +48 -2
  248. data/spec/mongoid/relations/touchable_spec.rb +40 -0
  249. data/spec/mongoid/reloadable_spec.rb +51 -0
  250. data/spec/mongoid/serializable_spec.rb +0 -50
  251. data/spec/mongoid/validatable/presence_spec.rb +1 -1
  252. data/spec/mongoid/validatable/uniqueness_spec.rb +18 -9
  253. data/spec/mongoid/validatable_spec.rb +16 -0
  254. data/spec/spec_helper.rb +20 -11
  255. metadata +524 -469
  256. checksums.yaml.gz.sig +0 -0
  257. data.tar.gz.sig +0 -0
  258. data/lib/mongoid/clients/thread_options.rb +0 -19
  259. data/lib/mongoid/extensions/origin/regexp_raw.rb +0 -43
  260. metadata.gz.sig +0 -0
@@ -0,0 +1,112 @@
1
+ require "spec_helper"
2
+
3
+ describe Mongoid::Cacheable do
4
+
5
+ describe ".included" do
6
+
7
+ let(:klass) do
8
+ Class.new do
9
+ include Mongoid::Cacheable
10
+ end
11
+ end
12
+
13
+ it "adds an cache_timestamp_format accessor" do
14
+ expect(klass).to respond_to(:cache_timestamp_format)
15
+ end
16
+
17
+ it "defaults cache_timestamp_format to :nsec" do
18
+ expect(klass.cache_timestamp_format).to be(:nsec)
19
+ end
20
+ end
21
+
22
+ describe "#cache_key" do
23
+
24
+ let(:document) do
25
+ Dokument.new
26
+ end
27
+
28
+ context "when the document is new" do
29
+
30
+ it "has a new key name" do
31
+ expect(document.cache_key).to eq("dokuments/new")
32
+ end
33
+ end
34
+
35
+ context "when persisted" do
36
+
37
+ before do
38
+ document.save
39
+ end
40
+
41
+ context "with updated_at" do
42
+
43
+ context "with the default cache_timestamp_format" do
44
+
45
+ let!(:updated_at) do
46
+ document.updated_at.utc.to_s(:nsec)
47
+ end
48
+
49
+ it "has the id and updated_at key name" do
50
+ expect(document.cache_key).to eq("dokuments/#{document.id}-#{updated_at}")
51
+ end
52
+ end
53
+
54
+ context "with a different cache_timestamp_format" do
55
+
56
+ before do
57
+ Dokument.cache_timestamp_format = :number
58
+ end
59
+
60
+ after do
61
+ Dokument.cache_timestamp_format = :nsec
62
+ end
63
+
64
+ let!(:updated_at) do
65
+ document.updated_at.utc.to_s(:number)
66
+ end
67
+
68
+ it "has the id and updated_at key name" do
69
+ expect(document.cache_key).to eq("dokuments/#{document.id}-#{updated_at}")
70
+ end
71
+ end
72
+ end
73
+
74
+ context "without updated_at, with Timestamps" do
75
+
76
+ before do
77
+ document.updated_at = nil
78
+ end
79
+
80
+ it "has the id key name" do
81
+ expect(document.cache_key).to eq("dokuments/#{document.id}")
82
+ end
83
+ end
84
+ end
85
+
86
+ context "when model dont have Timestamps" do
87
+
88
+ let(:artist) do
89
+ Artist.create!
90
+ end
91
+
92
+ it "should have the id key name" do
93
+ expect(artist.cache_key).to eq("artists/#{artist.id}")
94
+ end
95
+ end
96
+
97
+ context "when model has Short Timestamps" do
98
+
99
+ let(:agent) do
100
+ ShortAgent.create!
101
+ end
102
+
103
+ let!(:updated_at) do
104
+ agent.updated_at.utc.to_s(:nsec)
105
+ end
106
+
107
+ it "has the id and updated_at key name" do
108
+ expect(agent.cache_key).to eq("short_agents/#{agent.id}-#{updated_at}")
109
+ end
110
+ end
111
+ end
112
+ end
@@ -1289,6 +1289,64 @@ describe Mongoid::Changeable do
1289
1289
  end
1290
1290
  end
1291
1291
 
1292
+ describe '#previously_changed?' do
1293
+
1294
+ let(:person) do
1295
+ Person.new(title: "Grand Poobah")
1296
+ end
1297
+
1298
+ before do
1299
+ person.title = "Captain Obvious"
1300
+ end
1301
+
1302
+ context "when the document has been saved" do
1303
+
1304
+ before do
1305
+ person.save!
1306
+ end
1307
+
1308
+ it "returns true" do
1309
+ expect(person.title_previously_changed?).to be(true)
1310
+ end
1311
+ end
1312
+
1313
+ context "when the document has not been saved" do
1314
+
1315
+ it "returns false" do
1316
+ expect(person.title_previously_changed?).to be(false)
1317
+ end
1318
+ end
1319
+ end
1320
+
1321
+ describe '#previous_change' do
1322
+
1323
+ let(:person) do
1324
+ Person.new(title: "Grand Poobah")
1325
+ end
1326
+
1327
+ before do
1328
+ person.title = "Captain Obvious"
1329
+ end
1330
+
1331
+ context "when the document has been saved" do
1332
+
1333
+ before do
1334
+ person.save!
1335
+ end
1336
+
1337
+ it "returns the changes" do
1338
+ expect(person.title_previous_change).to eq([ nil, "Captain Obvious" ])
1339
+ end
1340
+ end
1341
+
1342
+ context "when the document has not been saved" do
1343
+
1344
+ it "returns no changes" do
1345
+ expect(person.title_previous_change).to eq(nil)
1346
+ end
1347
+ end
1348
+ end
1349
+
1292
1350
  context "when fields have been defined pre-dirty inclusion" do
1293
1351
 
1294
1352
  let(:document) do
@@ -21,6 +21,10 @@ describe Mongoid::Clients::Factory do
21
21
  Mongoid::Config.send(:clients=, config)
22
22
  end
23
23
 
24
+ after do
25
+ client.close
26
+ end
27
+
24
28
  let(:client) do
25
29
  described_class.create(:secondary)
26
30
  end
@@ -55,6 +59,10 @@ describe Mongoid::Clients::Factory do
55
59
  Mongoid::Config.send(:clients=, config)
56
60
  end
57
61
 
62
+ after do
63
+ client.close
64
+ end
65
+
58
66
  let(:client) do
59
67
  described_class.create(:secondary)
60
68
  end
@@ -95,6 +103,10 @@ describe Mongoid::Clients::Factory do
95
103
  Mongoid::Config.send(:clients=, config)
96
104
  end
97
105
 
106
+ after do
107
+ client.close
108
+ end
109
+
98
110
  let(:client) do
99
111
  described_class.create(:secondary)
100
112
  end
@@ -120,8 +132,8 @@ describe Mongoid::Clients::Factory do
120
132
 
121
133
  let(:config) do
122
134
  {
123
- default: { hosts: [ "127.0.0.1:30000" ], database: database_id },
124
- secondary: { uri: "mongodb://127.0.0.1:30000,127.0.0.1:30001/mongoid_test" }
135
+ default: { hosts: [ "127.0.0.1:27017" ], database: database_id },
136
+ secondary: { uri: "mongodb://127.0.0.1:27017,127.0.0.1:27018/mongoid_test" }
125
137
  }
126
138
  end
127
139
 
@@ -129,6 +141,10 @@ describe Mongoid::Clients::Factory do
129
141
  Mongoid::Config.send(:clients=, config)
130
142
  end
131
143
 
144
+ after do
145
+ client.close
146
+ end
147
+
132
148
  let(:client) do
133
149
  described_class.create(:secondary)
134
150
  end
@@ -146,7 +162,7 @@ describe Mongoid::Clients::Factory do
146
162
  end
147
163
 
148
164
  it "sets the cluster's seeds" do
149
- expect(seeds).to eq([ "127.0.0.1:30000", "127.0.0.1:30001" ])
165
+ expect(seeds).to eq([ "127.0.0.1:27017", "127.0.0.1:27018" ])
150
166
  end
151
167
  end
152
168
  end
@@ -172,6 +188,10 @@ describe Mongoid::Clients::Factory do
172
188
  Mongoid::Config.send(:clients=, config)
173
189
  end
174
190
 
191
+ after do
192
+ client.close
193
+ end
194
+
175
195
  let(:client) do
176
196
  described_class.create
177
197
  end
@@ -217,6 +237,10 @@ describe Mongoid::Clients::Factory do
217
237
  Mongoid::Config.send(:clients=, config)
218
238
  end
219
239
 
240
+ after do
241
+ client.close
242
+ end
243
+
220
244
  let(:client) do
221
245
  described_class.default
222
246
  end
@@ -257,6 +281,10 @@ describe Mongoid::Clients::Factory do
257
281
  Mongoid::Config.send(:clients=, config)
258
282
  end
259
283
 
284
+ after do
285
+ client.close
286
+ end
287
+
260
288
  let(:client) do
261
289
  described_class.default
262
290
  end
@@ -2,185 +2,471 @@ require "spec_helper"
2
2
 
3
3
  describe Mongoid::Clients::Options do
4
4
 
5
- describe "#with", if: non_legacy_server? do
5
+ describe '#with', if: non_legacy_server? do
6
6
 
7
- context "when passing some options" do
7
+ context 'when passing some options' do
8
8
 
9
- let(:options) { { database: 'test' } }
10
-
11
- let!(:cluster) do
12
- Band.mongo_client.cluster
9
+ let(:persistence_context) do
10
+ Band.with(options) do |klass|
11
+ klass.persistence_context
12
+ end
13
13
  end
14
14
 
15
- let!(:klass) do
16
- Band.with(options)
15
+ let(:options) { { database: 'other' } }
16
+
17
+ it 'sets the options on the client' do
18
+ expect(persistence_context.client.options['database']).to eq(options[:database])
17
19
  end
18
20
 
19
- it "sets the options into the class" do
20
- expect(klass.persistence_options).to eq(options)
21
+ it 'does not set the options on class level' do
22
+ expect(Band.persistence_context.client.options['database']).to eq('mongoid_test')
21
23
  end
22
24
 
23
- it "sets the options into the instance" do
24
- expect(klass.new.persistence_options).to eq(options)
25
+ context 'when the options are not valid mongo client options' do
26
+
27
+ let(:persistence_context) do
28
+ Band.with(invalid_options) do |klass|
29
+ klass.persistence_context
30
+ end
31
+ end
32
+
33
+ let(:invalid_options) { { bad: 'option' } }
34
+
35
+ it 'raises an error' do
36
+ expect {
37
+ persistence_context
38
+ }.to raise_exception(Mongoid::Errors::InvalidPersistenceOption)
39
+ end
40
+
41
+ it 'clears the persistence context' do
42
+ begin; persistence_context; rescue Mongoid::Errors::InvalidPersistenceOption; end
43
+ expect(Band.persistence_context).to eq(Mongoid::PersistenceContext.new(Band))
44
+ end
25
45
  end
26
46
 
27
- it "doesnt set the options on class level" do
28
- expect(Band.new.persistence_options).to be_nil
47
+ context 'when the options include a collection' do
48
+
49
+ let(:options) { { collection: 'another-collection' } }
50
+
51
+ it 'uses the collection' do
52
+ expect(persistence_context.collection_name).to eq(options[:collection].to_sym)
53
+ expect(persistence_context.collection.name).to eq(options[:collection])
54
+ end
55
+
56
+ it 'does not raise an error' do
57
+ expect(persistence_context.client).to be_a(Mongo::Client)
58
+ end
59
+
60
+ it 'does not include the collection option in the client options' do
61
+ expect(persistence_context.client.options[:collection]).to be_nil
62
+ expect(persistence_context.client.options['collection']).to be_nil
63
+ end
29
64
  end
30
65
 
31
- context 'when passed a block', if: testing_locally? do
66
+ context 'when passing a block', if: testing_locally? do
32
67
 
33
68
  let!(:connections_before) do
34
69
  Band.mongo_client.database.command(serverStatus: 1).first['connections']['current']
35
70
  end
36
71
 
37
- it "can return results" do
38
- Band.create(name: 'emily')
39
- result = Band.with(:read => {:mode => :secondary_preferred}) do |klass|
72
+ let!(:connections_and_cluster_during) do
73
+ connections = nil
74
+ cluster = Band.with(options) do |klass|
40
75
  klass.where(name: 'emily').to_a
76
+ connections = Band.mongo_client.database.command(serverStatus: 1).first['connections']['current']
41
77
  end
42
- expect(result.length).to eq(1)
43
- expect(result.first.name).to eq('emily')
78
+ [ connections, cluster ]
44
79
  end
45
80
 
46
- before do
47
- Band.with(options) do |klass|
48
- klass.where(name: 'emily').to_a
49
- end
81
+ let(:connections_during) do
82
+ connections_and_cluster_during[0]
83
+ end
84
+
85
+ let(:cluster_during) do
86
+ connections_and_cluster_during[1]
50
87
  end
51
88
 
52
89
  let(:connections_after) do
53
90
  Band.mongo_client.database.command(serverStatus: 1).first['connections']['current']
54
91
  end
55
92
 
56
- context 'when a new cluster is created by the driver' do
93
+ let!(:cluster_before) do
94
+ Band.persistence_context.cluster
95
+ end
96
+
97
+ let(:cluster_after) do
98
+ Band.persistence_context.cluster
99
+ end
57
100
 
58
- let(:options) { { connect_timeout: 2 } }
101
+ context 'when the options create a new cluster' do
59
102
 
60
- it 'disconnects the new cluster' do
61
- expect(connections_after).to eq(connections_before)
103
+ let(:options) do
104
+ { connect_timeout: 2 }
105
+ end
106
+
107
+ it 'creates a new cluster' do
108
+ expect(connections_before).to be <(connections_during)
109
+ expect(cluster_before).not_to be(cluster_during)
110
+ end
111
+
112
+ it 'disconnects the new cluster when the block exits' do
113
+ expect(connections_before).to eq(connections_after)
62
114
  end
63
115
  end
64
116
 
65
- context 'when the same cluster is used by the new client' do
117
+ context 'when the options do not create a new cluster' do
66
118
 
67
- let(:options) { { database: 'same-cluster' } }
119
+ let(:options) do
120
+ { database: 'same-cluster' }
121
+ end
122
+
123
+ it 'does not create a new cluster' do
124
+ expect(connections_during).to eq(connections_before)
125
+ end
68
126
 
69
127
  it 'does not disconnect the original cluster' do
70
128
  expect(connections_after).to eq(connections_before)
129
+ expect(cluster_before).to be(cluster_after)
130
+ end
131
+ end
132
+
133
+ context 'when the client options were configured using a uri' do
134
+
135
+ let(:config) do
136
+ {
137
+ default: { hosts: [ "127.0.0.1:27017" ], database: database_id },
138
+ secondary: { uri: "mongodb://127.0.0.1:27017/secondary-db?connectTimeoutMS=3000" }
139
+ }
140
+ end
141
+
142
+ before do
143
+ Mongoid::Config.send(:clients=, config)
144
+ end
145
+
146
+ after do
147
+ persistence_context.client.close
148
+ end
149
+
150
+ let(:persistence_context) do
151
+ Band.with(client: :secondary) do |klass|
152
+ klass.persistence_context
153
+ end
154
+ end
155
+
156
+ it 'uses the database specified in the uri' do
157
+ expect(persistence_context.database_name).to eq('secondary-db')
158
+ expect(persistence_context.client.database.name).to eq('secondary-db')
159
+ end
160
+
161
+ it 'uses the options specified in the uri' do
162
+ expect(persistence_context.client.options[:connect_timeout]).to eq(3)
71
163
  end
72
164
  end
73
165
  end
74
166
 
75
- context "when calling .collection method" do
167
+ context 'when changing the collection' do
76
168
 
77
- before do
78
- klass.collection
169
+ let(:options) do
170
+ { collection: 'other' }
79
171
  end
80
172
 
81
- it "keeps the options" do
82
- expect(klass.persistence_options).to eq(options)
173
+ it 'uses that collection' do
174
+ expect(persistence_context.collection.name).to eq(options[:collection])
83
175
  end
176
+ end
84
177
 
85
- context 'when changing the collection' do
178
+ context 'when returning a criteria' do
86
179
 
87
- let(:options) do
88
- { collection: 'other' }
180
+ let(:context_and_criteria) do
181
+ collection = nil
182
+ cxt = Band.with(read: :secondary) do |klass|
183
+ collection = klass.all.collection
184
+ klass.persistence_context
89
185
  end
186
+ [ cxt, collection ]
187
+ end
90
188
 
91
- it 'uses that collection' do
92
- expect(klass.collection.name).to eq(options[:collection])
93
- end
189
+ let(:persistence_context) do
190
+ context_and_criteria[0]
191
+ end
192
+
193
+ let(:client) do
194
+ context_and_criteria[1].client
195
+ end
196
+
197
+ it 'applies the options to the criteria client' do
198
+ expect(client.options['read']).to eq(:secondary)
94
199
  end
95
200
  end
96
201
 
97
- context "when returning a criteria" do
202
+ context 'when the object is shared between threads' do
98
203
 
99
- let(:criteria) do
100
- klass.all
204
+ before do
205
+ threads = []
206
+ 100.times do |i|
207
+ threads << Thread.new do
208
+ if i % 2 == 0
209
+ Band.with(collection: 'British') do |klass|
210
+ klass.create(name: 'realised')
211
+ end
212
+ else
213
+ Band.with(collection: 'American') do |klass|
214
+ klass.create(name: 'realized')
215
+ end
216
+ end
217
+ end
218
+ end
219
+ threads.collect { |t| t.value }
101
220
  end
102
221
 
103
- it "sets the options into the criteria object" do
104
- expect(criteria.persistence_options).to eq(options)
222
+ let(:british_count) do
223
+ Band.with(collection: 'British') do |klass|
224
+ klass.all.count
225
+ end
105
226
  end
106
227
 
107
- it "doesnt set the options on class level" do
108
- expect(Band.new.persistence_options).to be_nil
228
+ let(:american_count) do
229
+ Band.with(collection: 'American') do |klass|
230
+ klass.all.count
231
+ end
232
+ end
233
+
234
+ it "does not share the persistence options" do
235
+ expect(british_count).to eq(50)
236
+ expect(american_count).to eq(50)
109
237
  end
110
238
  end
111
239
  end
112
- end
113
240
 
114
- describe ".with", if: non_legacy_server? do
241
+ context 'when passing a persistence context' do
115
242
 
116
- let(:options) { { database: 'test' } }
243
+ let(:instance) do
244
+ Band.new
245
+ end
117
246
 
118
- let(:instance) do
119
- Band.new.with(options)
120
- end
247
+ let(:persistence_context) do
248
+ instance.with(options) do |inst|
249
+ inst.persistence_context
250
+ end
251
+ end
121
252
 
122
- it "sets the options into" do
123
- expect(instance.persistence_options).to eq(options)
124
- end
253
+ let(:options) { { database: 'other' } }
125
254
 
126
- it "passes down the options to collection" do
127
- expect(instance.collection.database.name).to eq('test')
255
+ it 'sets the persistence context on the object' do
256
+ Band.new.with(persistence_context) do |band_instance|
257
+ expect(band_instance.persistence_context.options).to eq(persistence_context.options)
258
+ end
259
+ end
128
260
  end
261
+ end
129
262
 
130
- context "when the object is shared between threads" do
131
-
132
- before do
133
- threads = []
134
- doc = Band.create(name: "Beatles")
135
- 100.times do |i|
136
- threads << Thread.new do
137
- if i % 2 == 0
138
- doc.with(nil).set(name: "Rolling Stones")
139
- else
140
- doc.with(options).set(name: "Beatles")
141
- end
263
+ describe '.with', if: non_legacy_server? do
264
+
265
+ context 'when passing some options' do
266
+
267
+ let(:options) do
268
+ { database: 'other' }
269
+ end
270
+
271
+ let(:band) do
272
+ Band.create
273
+ end
274
+
275
+ let(:persistence_context) do
276
+ band.with(options) do |object|
277
+ object.persistence_context
278
+ end
279
+ end
280
+
281
+ it 'sets the options on the client' do
282
+ expect(persistence_context.client.options['database']).to eq(options[:database])
283
+ end
284
+
285
+ it 'does not set the options on instance level' do
286
+ expect(band.persistence_context.client.database.name).to eq('mongoid_test')
287
+ end
288
+
289
+ context 'when the options are not valid mongo client options' do
290
+
291
+ let(:persistence_context) do
292
+ band.with(invalid_options) do |object|
293
+ object.persistence_context
142
294
  end
143
295
  end
144
- threads.join
296
+
297
+ let(:invalid_options) { { bad: 'option' } }
298
+
299
+ it 'raises an error' do
300
+ expect {
301
+ persistence_context
302
+ }.to raise_exception(Mongoid::Errors::InvalidPersistenceOption)
303
+ end
304
+
305
+ it 'clears the persistence context' do
306
+ begin; persistence_context; rescue Mongoid::Errors::InvalidPersistenceOption; end
307
+ expect(band.persistence_context).to eq(Mongoid::PersistenceContext.new(band))
308
+ end
145
309
  end
146
310
 
147
- it "does not share the persistence options" do
148
- expect(Band.persistence_options).to eq(nil)
311
+ context 'when the client options were configured using a uri' do
312
+
313
+ let(:config) do
314
+ {
315
+ default: { hosts: [ "127.0.0.1:27017" ], database: database_id },
316
+ secondary: { uri: "mongodb://127.0.0.1:27017/secondary-db" }
317
+ }
318
+ end
319
+
320
+ before do
321
+ Mongoid::Config.send(:clients=, config)
322
+ end
323
+
324
+ let(:persistence_context) do
325
+ band.with(client: :secondary) do |object|
326
+ object.persistence_context
327
+ end
328
+ end
329
+
330
+ it 'uses the database specified in the uri' do
331
+ expect(persistence_context.database_name).to eq('secondary-db')
332
+ expect(persistence_context.client.database.name).to eq('secondary-db')
333
+ end
149
334
  end
150
- end
151
- end
152
335
 
153
- describe "#persistence_options" do
336
+ context 'when passing a block', if: testing_locally? do
154
337
 
155
- it "touches the thread local" do
156
- expect(Thread.current).to receive(:[]).with("[mongoid][Band]:persistence-options").and_return({foo: :bar})
157
- expect(Band.persistence_options).to eq({foo: :bar})
158
- end
338
+ let!(:connections_before) do
339
+ band.mongo_client.database.command(serverStatus: 1).first['connections']['current']
340
+ end
159
341
 
160
- it "cannot force a value on thread local" do
161
- expect {
162
- Band.set_persistence_options(Band, {})
163
- }.to raise_error(NoMethodError)
164
- end
165
- end
342
+ let!(:connections_and_cluster_during) do
343
+ connections = nil
344
+ cluster = band.with(options) do |b|
345
+ b.reload
346
+ connections = band.mongo_client.database.command(serverStatus: 1).first['connections']['current']
347
+ b.persistence_context.cluster
348
+ end
349
+ [ connections, cluster ]
350
+ end
351
+
352
+ let(:connections_during) do
353
+ connections_and_cluster_during[0]
354
+ end
355
+
356
+ let(:cluster_during) do
357
+ connections_and_cluster_during[1]
358
+ end
359
+
360
+ let(:connections_after) do
361
+ band.mongo_client.database.command(serverStatus: 1).first['connections']['current']
362
+ end
363
+
364
+ let!(:cluster_before) do
365
+ band.persistence_context.cluster
366
+ end
166
367
 
167
- describe ".persistence_options" do
368
+ let(:cluster_after) do
369
+ band.persistence_context.cluster
370
+ end
371
+
372
+ context 'when the options create a new cluster' do
373
+
374
+ let(:options) do
375
+ { connect_timeout: 2 }
376
+ end
377
+
378
+ it 'creates a new cluster' do
379
+ expect(connections_before).to be <(connections_during)
380
+ expect(cluster_before).not_to be(cluster_during)
381
+ end
382
+
383
+ it 'disconnects the new cluster when the block exits' do
384
+ expect(connections_before).to eq(connections_after)
385
+ end
386
+ end
387
+
388
+ context 'when the options do not create a new cluster' do
168
389
 
169
- context "when options exist on the current thread" do
390
+ let(:options) { { read: :secondary } }
170
391
 
171
- let(:klass) do
172
- Band.with(write: { w: 2 })
392
+ it 'does not create a new cluster' do
393
+ expect(connections_during).to eq(connections_before)
394
+ end
395
+
396
+ it 'does not disconnect the original cluster' do
397
+ expect(connections_after).to eq(connections_before)
398
+ expect(cluster_before).to be(cluster_after)
399
+ end
400
+ end
173
401
  end
174
402
 
175
- it "returns the options" do
176
- expect(klass.persistence_options).to eq(write: { w: 2 })
403
+ context 'when changing the collection' do
404
+
405
+ let(:options) do
406
+ { collection: 'other' }
407
+ end
408
+
409
+ it 'uses that collection' do
410
+ expect(persistence_context.collection.name).to eq(options[:collection])
411
+ end
412
+ end
413
+
414
+ context 'when the object is shared between threads' do
415
+
416
+ before do
417
+ threads = []
418
+ 100.times do |i|
419
+ band = Band.create
420
+ threads << Thread.new do
421
+ if i % 2 == 0
422
+ band.with(collection: 'British') do |b|
423
+ b.name = 'realised'
424
+ b.upsert
425
+ end
426
+ else
427
+ band.with(collection: 'American') do |b|
428
+ b.name = 'realized'
429
+ b.upsert
430
+ end
431
+ end
432
+ end
433
+ end
434
+ threads.collect { |t| t.value }
435
+ end
436
+
437
+ let(:british_count) do
438
+ Band.with(collection: 'British') do |klass|
439
+ klass.all.count
440
+ end
441
+ end
442
+
443
+ let(:american_count) do
444
+ Band.with(collection: 'British') do |klass|
445
+ klass.all.count
446
+ end
447
+ end
448
+
449
+ it 'does not share the persistence options' do
450
+ expect(british_count).to eq(50)
451
+ expect(american_count).to eq(50)
452
+ end
177
453
  end
178
454
  end
179
455
 
180
- context "when there are no options on the current thread" do
456
+ context 'when passing a persistence context' do
181
457
 
182
- it "returns nil" do
183
- expect(Band.persistence_options).to be_nil
458
+ let(:persistence_context) do
459
+ Band.with(options) do |klass|
460
+ klass.persistence_context
461
+ end
462
+ end
463
+
464
+ let(:options) { { database: 'other' } }
465
+
466
+ it 'sets the persistence context on the object' do
467
+ Band.with(persistence_context) do |band_class|
468
+ expect(band_class.persistence_context.options).to eq(persistence_context.options)
469
+ end
184
470
  end
185
471
  end
186
472
  end