mongoid 5.4.1 → 6.1.1

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