mongoid 4.0.2 → 5.0.0.beta

Sign up to get free protection for your applications and to get access to all the features.
Files changed (177) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +66 -1
  3. data/README.md +14 -13
  4. data/lib/config/locales/en.yml +28 -28
  5. data/lib/mongoid.rb +28 -21
  6. data/lib/mongoid/atomic.rb +2 -4
  7. data/lib/mongoid/attributes.rb +7 -7
  8. data/lib/mongoid/attributes/processing.rb +4 -1
  9. data/lib/mongoid/attributes/readonly.rb +2 -2
  10. data/lib/mongoid/changeable.rb +4 -6
  11. data/lib/mongoid/clients.rb +142 -0
  12. data/lib/mongoid/clients/factory.rb +78 -0
  13. data/lib/mongoid/{sessions → clients}/options.rb +30 -19
  14. data/lib/mongoid/{sessions → clients}/storage_options.rb +27 -13
  15. data/lib/mongoid/{sessions → clients}/thread_options.rb +6 -3
  16. data/lib/mongoid/clients/validators.rb +2 -0
  17. data/lib/mongoid/{sessions → clients}/validators/storage.rb +5 -2
  18. data/lib/mongoid/composable.rb +3 -3
  19. data/lib/mongoid/config.rb +39 -41
  20. data/lib/mongoid/config/environment.rb +1 -1
  21. data/lib/mongoid/config/validators.rb +1 -1
  22. data/lib/mongoid/config/validators/{session.rb → client.rb} +31 -28
  23. data/lib/mongoid/contextual/aggregable/mongo.rb +1 -1
  24. data/lib/mongoid/contextual/atomic.rb +11 -11
  25. data/lib/mongoid/contextual/command.rb +9 -6
  26. data/lib/mongoid/contextual/geo_near.rb +17 -1
  27. data/lib/mongoid/contextual/map_reduce.rb +12 -11
  28. data/lib/mongoid/contextual/memory.rb +2 -5
  29. data/lib/mongoid/contextual/mongo.rb +92 -82
  30. data/lib/mongoid/contextual/none.rb +13 -0
  31. data/lib/mongoid/copyable.rb +6 -1
  32. data/lib/mongoid/criteria.rb +36 -3
  33. data/lib/mongoid/document.rb +3 -4
  34. data/lib/mongoid/errors.rb +6 -6
  35. data/lib/mongoid/errors/{mixed_session_configuration.rb → mixed_client_configuration.rb} +5 -5
  36. data/lib/mongoid/errors/no_client_config.rb +22 -0
  37. data/lib/mongoid/errors/{no_session_database.rb → no_client_database.rb} +4 -4
  38. data/lib/mongoid/errors/{no_session_hosts.rb → no_client_hosts.rb} +4 -4
  39. data/lib/mongoid/errors/{no_sessions_config.rb → no_clients_config.rb} +4 -4
  40. data/lib/mongoid/errors/no_default_client.rb +23 -0
  41. data/lib/mongoid/extensions/hash.rb +5 -1
  42. data/lib/mongoid/extensions/object.rb +3 -2
  43. data/lib/mongoid/extensions/set.rb +5 -5
  44. data/lib/mongoid/factory.rb +4 -2
  45. data/lib/mongoid/fields.rb +7 -2
  46. data/lib/mongoid/findable.rb +4 -1
  47. data/lib/mongoid/indexable.rb +15 -9
  48. data/lib/mongoid/persistable.rb +1 -2
  49. data/lib/mongoid/persistable/creatable.rb +2 -2
  50. data/lib/mongoid/persistable/deletable.rb +3 -3
  51. data/lib/mongoid/persistable/incrementable.rb +1 -1
  52. data/lib/mongoid/persistable/logical.rb +1 -1
  53. data/lib/mongoid/persistable/poppable.rb +1 -1
  54. data/lib/mongoid/persistable/pullable.rb +2 -2
  55. data/lib/mongoid/persistable/pushable.rb +2 -2
  56. data/lib/mongoid/persistable/renamable.rb +1 -1
  57. data/lib/mongoid/persistable/settable.rb +1 -1
  58. data/lib/mongoid/persistable/unsettable.rb +1 -1
  59. data/lib/mongoid/persistable/updatable.rb +2 -2
  60. data/lib/mongoid/persistable/upsertable.rb +1 -1
  61. data/lib/mongoid/query_cache.rb +98 -104
  62. data/lib/mongoid/railtie.rb +1 -21
  63. data/lib/mongoid/railties/database.rake +1 -1
  64. data/lib/mongoid/relations/builders.rb +3 -1
  65. data/lib/mongoid/relations/counter_cache.rb +1 -1
  66. data/lib/mongoid/relations/embedded/batchable.rb +3 -10
  67. data/lib/mongoid/relations/embedded/many.rb +4 -2
  68. data/lib/mongoid/relations/many.rb +1 -0
  69. data/lib/mongoid/relations/proxy.rb +6 -6
  70. data/lib/mongoid/relations/referenced/many.rb +2 -1
  71. data/lib/mongoid/relations/targets/enumerable.rb +11 -11
  72. data/lib/mongoid/relations/touchable.rb +1 -1
  73. data/lib/mongoid/reloadable.rb +2 -2
  74. data/lib/mongoid/scopable.rb +6 -17
  75. data/lib/mongoid/selectable.rb +1 -36
  76. data/lib/mongoid/serializable.rb +2 -2
  77. data/lib/mongoid/stateful.rb +0 -1
  78. data/lib/mongoid/tasks/database.rake +2 -2
  79. data/lib/mongoid/tasks/database.rb +23 -16
  80. data/lib/mongoid/threaded.rb +54 -33
  81. data/lib/mongoid/threaded/lifecycle.rb +21 -16
  82. data/lib/mongoid/traversable.rb +16 -1
  83. data/lib/mongoid/validatable.rb +1 -1
  84. data/lib/mongoid/validatable/queryable.rb +1 -1
  85. data/lib/mongoid/validatable/uniqueness.rb +3 -20
  86. data/lib/mongoid/version.rb +1 -1
  87. data/lib/rails/generators/mongoid/config/templates/mongoid.yml +91 -57
  88. data/lib/rails/mongoid.rb +2 -2
  89. data/spec/app/models/audio.rb +1 -1
  90. data/spec/app/models/band.rb +1 -0
  91. data/spec/app/models/company.rb +5 -0
  92. data/spec/app/models/label.rb +7 -0
  93. data/spec/app/models/pub.rb +6 -0
  94. data/spec/app/models/staff.rb +7 -0
  95. data/spec/app/models/store_as_dup_test1.rb +5 -0
  96. data/spec/app/models/store_as_dup_test2.rb +5 -0
  97. data/spec/config/mongoid.yml +7 -25
  98. data/spec/mongoid/atomic/paths_spec.rb +3 -11
  99. data/spec/mongoid/attributes/nested_spec.rb +16 -16
  100. data/spec/mongoid/attributes/readonly_spec.rb +80 -18
  101. data/spec/mongoid/attributes_spec.rb +3 -3
  102. data/spec/mongoid/changeable_spec.rb +70 -0
  103. data/spec/mongoid/clients/factory_spec.rb +284 -0
  104. data/spec/mongoid/{sessions → clients}/options_spec.rb +4 -6
  105. data/spec/mongoid/clients_spec.rb +739 -0
  106. data/spec/mongoid/config/environment_spec.rb +14 -11
  107. data/spec/mongoid/config_spec.rb +33 -48
  108. data/spec/mongoid/contextual/atomic_spec.rb +1 -17
  109. data/spec/mongoid/contextual/geo_near_spec.rb +35 -0
  110. data/spec/mongoid/contextual/mongo_spec.rb +26 -83
  111. data/spec/mongoid/contextual/none_spec.rb +15 -0
  112. data/spec/mongoid/copyable_spec.rb +35 -1
  113. data/spec/mongoid/criteria/findable_spec.rb +197 -0
  114. data/spec/mongoid/criteria/modifiable_spec.rb +7 -29
  115. data/spec/mongoid/criteria_spec.rb +74 -91
  116. data/spec/mongoid/document_spec.rb +1 -1
  117. data/spec/mongoid/errors/{mixed_session_configuration_spec.rb → mixed_client_configuration_spec.rb} +1 -1
  118. data/spec/mongoid/errors/{no_session_config_spec.rb → no_client_config_spec.rb} +4 -4
  119. data/spec/mongoid/errors/{no_session_database_spec.rb → no_client_database_spec.rb} +4 -4
  120. data/spec/mongoid/errors/{no_session_hosts_spec.rb → no_client_hosts_spec.rb} +3 -3
  121. data/spec/mongoid/errors/{no_sessions_config_spec.rb → no_clients_config_spec.rb} +2 -2
  122. data/spec/mongoid/fields/localized_spec.rb +1 -0
  123. data/spec/mongoid/fields_spec.rb +1 -0
  124. data/spec/mongoid/findable_spec.rb +2 -23
  125. data/spec/mongoid/indexable_spec.rb +12 -8
  126. data/spec/mongoid/interceptable_spec.rb +15 -0
  127. data/spec/mongoid/persistable/settable_spec.rb +16 -0
  128. data/spec/mongoid/persistable/updatable_spec.rb +3 -2
  129. data/spec/mongoid/persistable_spec.rb +4 -4
  130. data/spec/mongoid/query_cache_spec.rb +13 -8
  131. data/spec/mongoid/relations/auto_save_spec.rb +1 -1
  132. data/spec/mongoid/relations/counter_cache_spec.rb +34 -0
  133. data/spec/mongoid/relations/eager/belongs_to_spec.rb +9 -0
  134. data/spec/mongoid/relations/eager/has_and_belongs_to_many_spec.rb +3 -3
  135. data/spec/mongoid/relations/embedded/many_spec.rb +123 -1
  136. data/spec/mongoid/relations/embedded/one_spec.rb +3 -3
  137. data/spec/mongoid/relations/proxy_spec.rb +28 -0
  138. data/spec/mongoid/relations/referenced/in_spec.rb +1 -1
  139. data/spec/mongoid/relations/referenced/many_spec.rb +47 -23
  140. data/spec/mongoid/relations/referenced/many_to_many_spec.rb +1 -1
  141. data/spec/mongoid/relations/referenced/one_spec.rb +1 -1
  142. data/spec/mongoid/relations/targets/enumerable_spec.rb +9 -2
  143. data/spec/mongoid/reloadable_spec.rb +6 -6
  144. data/spec/mongoid/scopable_spec.rb +41 -28
  145. data/spec/mongoid/selectable_spec.rb +6 -16
  146. data/spec/mongoid/tasks/database_rake_spec.rb +13 -13
  147. data/spec/mongoid/tasks/database_spec.rb +2 -2
  148. data/spec/mongoid/threaded_spec.rb +0 -7
  149. data/spec/mongoid/traversable_spec.rb +2 -2
  150. data/spec/mongoid/validatable/uniqueness_spec.rb +30 -1
  151. data/spec/mongoid_spec.rb +13 -15
  152. data/spec/rails/mongoid_spec.rb +13 -4
  153. data/spec/spec_helper.rb +44 -27
  154. data/spec/support/authorization.rb +12 -0
  155. data/spec/support/expectations.rb +14 -0
  156. metadata +52 -59
  157. data/lib/mongoid/contextual/find_and_modify.rb +0 -69
  158. data/lib/mongoid/contextual/text_search.rb +0 -178
  159. data/lib/mongoid/criteria/#findable.rb# +0 -141
  160. data/lib/mongoid/errors/no_default_session.rb +0 -23
  161. data/lib/mongoid/errors/no_session_config.rb +0 -22
  162. data/lib/mongoid/log_subscriber.rb +0 -55
  163. data/lib/mongoid/positional.rb +0 -71
  164. data/lib/mongoid/sessions.rb +0 -125
  165. data/lib/mongoid/sessions/factory.rb +0 -131
  166. data/lib/mongoid/sessions/mongo_uri.rb +0 -93
  167. data/lib/mongoid/sessions/validators.rb +0 -2
  168. data/lib/mongoid/support/query_counter.rb +0 -23
  169. data/spec/helpers.rb +0 -18
  170. data/spec/mongoid/#atomic_spec.rb# +0 -365
  171. data/spec/mongoid/contextual/find_and_modify_spec.rb +0 -220
  172. data/spec/mongoid/contextual/text_search_spec.rb +0 -209
  173. data/spec/mongoid/log_subscriber_spec.rb +0 -75
  174. data/spec/mongoid/positional_spec.rb +0 -222
  175. data/spec/mongoid/sessions/factory_spec.rb +0 -333
  176. data/spec/mongoid/sessions/mongo_uri_spec.rb +0 -103
  177. data/spec/mongoid/sessions_spec.rb +0 -1252
@@ -172,7 +172,7 @@ describe Mongoid::Attributes do
172
172
  before do
173
173
  person.collection
174
174
  .find({ _id: person.id })
175
- .update({ "$unset" => { age: 1 }})
175
+ .update_one({ "$unset" => { age: 1 }})
176
176
  end
177
177
 
178
178
  context "when found" do
@@ -742,7 +742,7 @@ describe Mongoid::Attributes do
742
742
  before do
743
743
  person.collection
744
744
  .find({ _id: person.id })
745
- .update({ "$unset" => { age: 1 }})
745
+ .update_one({ "$unset" => { age: 1 }})
746
746
  Mongoid.raise_not_found_error = false
747
747
  person.reload
748
748
  Mongoid.raise_not_found_error = true
@@ -829,7 +829,7 @@ describe Mongoid::Attributes do
829
829
  before do
830
830
  person.collection
831
831
  .find({ _id: person.id })
832
- .update({ "$unset" => { age: 1 }})
832
+ .update_one({ "$unset" => { age: 1 }})
833
833
  Mongoid.raise_not_found_error = false
834
834
  person.reload
835
835
  Mongoid.raise_not_found_error = true
@@ -661,6 +661,24 @@ describe Mongoid::Changeable do
661
661
  it "returns an array of changed field names" do
662
662
  expect(person.changed).to include("title")
663
663
  end
664
+
665
+ end
666
+
667
+ context "When the document has changed but changed back to the original" do
668
+
669
+ let(:person) do
670
+ Person.instantiate(title: "Grand Poobah")
671
+ end
672
+
673
+ before do
674
+ person.title = "Captain Obvious"
675
+ person.title = nil
676
+ end
677
+
678
+ it "returns an array of changed field names" do
679
+ expect(person.changed).not_to include("title")
680
+ end
681
+
664
682
  end
665
683
 
666
684
  context "when the document has not changed" do
@@ -793,6 +811,58 @@ describe Mongoid::Changeable do
793
811
  end
794
812
  end
795
813
 
814
+ context "when changed? has been called before child elements size change" do
815
+
816
+ let(:person) do
817
+ Person.create
818
+ end
819
+
820
+ let(:address) do
821
+ person.addresses.create(street: "hobrecht")
822
+ end
823
+
824
+ let!(:location) do
825
+ address.locations.create(name: "home")
826
+ end
827
+
828
+ before do
829
+ person.changed?
830
+ end
831
+
832
+ context "when adding via new" do
833
+
834
+ before do
835
+ address.locations.new
836
+ end
837
+
838
+ it "returns true" do
839
+ expect(person).to be_changed
840
+ end
841
+ end
842
+
843
+ context "when adding via build" do
844
+
845
+ before do
846
+ address.locations.build
847
+ end
848
+
849
+ it "returns true" do
850
+ expect(person).to be_changed
851
+ end
852
+ end
853
+
854
+ context "when adding via create" do
855
+
856
+ before do
857
+ address.locations.create
858
+ end
859
+
860
+ it "returns false" do
861
+ expect(person).to_not be_changed
862
+ end
863
+ end
864
+ end
865
+
796
866
  context "when a deeply embedded child has changed" do
797
867
 
798
868
  let(:person) do
@@ -0,0 +1,284 @@
1
+ require "spec_helper"
2
+
3
+ describe Mongoid::Clients::Factory do
4
+
5
+ describe ".create" do
6
+
7
+ context "when provided a name" do
8
+
9
+ context "when the configuration exists" do
10
+
11
+ context "when the configuration is standard" do
12
+
13
+ let(:config) do
14
+ {
15
+ default: { hosts: [ "127.0.0.1:27017" ], database: database_id },
16
+ secondary: { hosts: [ "127.0.0.1:27017" ], database: database_id }
17
+ }
18
+ end
19
+
20
+ before do
21
+ Mongoid::Config.send(:clients=, config)
22
+ end
23
+
24
+ let(:client) do
25
+ described_class.create(:secondary)
26
+ end
27
+
28
+ let(:cluster) do
29
+ client.cluster
30
+ end
31
+
32
+ it "returns a client" do
33
+ expect(client).to be_a(Mongo::Client)
34
+ end
35
+
36
+ it "sets the cluster's seeds" do
37
+ expect(cluster.addresses.first.to_s).to eq("127.0.0.1:27017")
38
+ end
39
+ end
40
+
41
+ context "when the configuration has no ports" do
42
+
43
+ let(:config) do
44
+ {
45
+ default: { hosts: [ "127.0.0.1" ], database: database_id },
46
+ secondary: { hosts: [ "127.0.0.1" ], database: database_id }
47
+ }
48
+ end
49
+
50
+ before do
51
+ Mongoid::Config.send(:clients=, config)
52
+ end
53
+
54
+ let(:client) do
55
+ described_class.create(:secondary)
56
+ end
57
+
58
+ let(:default) do
59
+ described_class.create(:default)
60
+ end
61
+
62
+ let(:cluster) do
63
+ client.cluster
64
+ end
65
+
66
+ it "returns a client" do
67
+ expect(client).to be_a(Mongo::Client)
68
+ end
69
+
70
+ it "sets the cluster's seed ports to 27017" do
71
+ expect(cluster.addresses.first.to_s).to eq("127.0.0.1:27017")
72
+ end
73
+
74
+ it "sets ips with no ports to 27017" do
75
+ expect(default.cluster.addresses.first.to_s).to eq("127.0.0.1:27017")
76
+ end
77
+ end
78
+
79
+ context "when configured via a uri" do
80
+
81
+ context "when the uri has a single host:port" do
82
+
83
+ let(:config) do
84
+ {
85
+ default: { hosts: [ "127.0.0.1:27017" ], database: database_id },
86
+ secondary: { uri: "mongodb://127.0.0.1:27017/mongoid_test" }
87
+ }
88
+ end
89
+
90
+ before do
91
+ Mongoid::Config.send(:clients=, config)
92
+ end
93
+
94
+ let(:client) do
95
+ described_class.create(:secondary)
96
+ end
97
+
98
+ let(:cluster) do
99
+ client.cluster
100
+ end
101
+
102
+ it "returns a client" do
103
+ expect(client).to be_a(Mongo::Client)
104
+ end
105
+
106
+ it "sets the cluster's seeds" do
107
+ expect(cluster.addresses.first.to_s).to eq("127.0.0.1:27017")
108
+ end
109
+
110
+ it "sets the database" do
111
+ expect(client.options[:database]).to eq("mongoid_test")
112
+ end
113
+ end
114
+
115
+ context "when the uri has multiple host:port pairs" do
116
+
117
+ let(:config) do
118
+ {
119
+ default: { hosts: [ "127.0.0.1:27017" ], database: database_id },
120
+ secondary: { uri: "mongodb://127.0.0.1:27017,127.0.0.1:27018/mongoid_test" }
121
+ }
122
+ end
123
+
124
+ before do
125
+ Mongoid::Config.send(:clients=, config)
126
+ end
127
+
128
+ let(:client) do
129
+ described_class.create(:secondary)
130
+ end
131
+
132
+ let(:cluster) do
133
+ client.cluster
134
+ end
135
+
136
+ let(:seeds) do
137
+ cluster.addresses.map{ |address| address.to_s }
138
+ end
139
+
140
+ it "returns a client" do
141
+ expect(client).to be_a(Mongo::Client)
142
+ end
143
+
144
+ it "sets the cluster's seeds" do
145
+ expect(seeds).to eq([ "127.0.0.1:27017", "127.0.0.1:27018" ])
146
+ end
147
+ end
148
+ end
149
+ end
150
+
151
+ context "when the configuration does not exist" do
152
+
153
+ it "raises an error" do
154
+ expect {
155
+ described_class.create(:unknown)
156
+ }.to raise_error(Mongoid::Errors::NoClientConfig)
157
+ end
158
+ end
159
+ end
160
+
161
+ context "when no name is provided" do
162
+
163
+ let(:config) do
164
+ { default: { hosts: ["127.0.0.1:27017"], database: database_id }}
165
+ end
166
+
167
+ before do
168
+ Mongoid::Config.send(:clients=, config)
169
+ end
170
+
171
+ let(:client) do
172
+ described_class.create
173
+ end
174
+
175
+ let(:cluster) do
176
+ client.cluster
177
+ end
178
+
179
+ let(:seeds) do
180
+ cluster.addresses.map{ |address| address.to_s }
181
+ end
182
+
183
+ it "returns the default client" do
184
+ expect(client).to be_a(Mongo::Client)
185
+ end
186
+
187
+ it "sets the cluster's seeds" do
188
+ expect(seeds).to eq([ "127.0.0.1:27017" ])
189
+ end
190
+ end
191
+
192
+ context "when nil is provided and no default config" do
193
+
194
+ let(:config) { nil }
195
+
196
+ before do
197
+ Mongoid.clients[:default] = nil
198
+ end
199
+
200
+ it "raises NoClientsConfig error" do
201
+ expect{ Mongoid::Clients::Factory.create(config) }.to raise_error(Mongoid::Errors::NoClientsConfig)
202
+ end
203
+ end
204
+ end
205
+
206
+ describe ".default" do
207
+
208
+ let(:config) do
209
+ { default: { hosts: ["127.0.0.1:27017"], database: database_id }}
210
+ end
211
+
212
+ before do
213
+ Mongoid::Config.send(:clients=, config)
214
+ end
215
+
216
+ let(:client) do
217
+ described_class.default
218
+ end
219
+
220
+ let(:cluster) do
221
+ client.cluster
222
+ end
223
+
224
+ let(:seeds) do
225
+ cluster.addresses.map{ |address| address.to_s }
226
+ end
227
+
228
+ it "returns the default client" do
229
+ expect(client).to be_a(Mongo::Client)
230
+ end
231
+
232
+ it "sets the cluster's seeds" do
233
+ expect(seeds).to eq([ "127.0.0.1:27017" ])
234
+ end
235
+ end
236
+
237
+ context "when options are provided with string keys" do
238
+
239
+ let(:config) do
240
+ {
241
+ default: {
242
+ hosts: [ "127.0.0.1:27017" ],
243
+ database: database_id,
244
+ options: {
245
+ "server_selection_timeout" => 10,
246
+ "write" => { "w" => 1 }
247
+ }
248
+ }
249
+ }
250
+ end
251
+
252
+ before do
253
+ Mongoid::Config.send(:clients=, config)
254
+ end
255
+
256
+ let(:client) do
257
+ described_class.default
258
+ end
259
+
260
+ let(:cluster) do
261
+ client.cluster
262
+ end
263
+
264
+ let(:seeds) do
265
+ cluster.addresses.map{ |address| address.to_s }
266
+ end
267
+
268
+ it "returns the default client" do
269
+ expect(client).to be_a(Mongo::Client)
270
+ end
271
+
272
+ it "sets the cluster's seeds" do
273
+ expect(seeds).to eq([ "127.0.0.1:27017" ])
274
+ end
275
+
276
+ it "sets the server selection timeout" do
277
+ expect(cluster.options[:server_selection_timeout]).to eq(10)
278
+ end
279
+
280
+ it "sets the write concern" do
281
+ expect(client.write_concern).to be_a(Mongo::WriteConcern::Acknowledged)
282
+ end
283
+ end
284
+ end
@@ -1,8 +1,8 @@
1
1
  require "spec_helper"
2
2
 
3
- describe Mongoid::Sessions::Options do
3
+ describe Mongoid::Clients::Options do
4
4
 
5
- describe "#with" do
5
+ describe "#with", if: non_legacy_server? do
6
6
 
7
7
  context "when passing some options" do
8
8
 
@@ -52,7 +52,7 @@ describe Mongoid::Sessions::Options do
52
52
  end
53
53
  end
54
54
 
55
- describe ".with" do
55
+ describe ".with", if: non_legacy_server? do
56
56
 
57
57
  let(:options) { { database: 'test' } }
58
58
 
@@ -65,9 +65,7 @@ describe Mongoid::Sessions::Options do
65
65
  end
66
66
 
67
67
  it "passes down the options to collection" do
68
- session = Band.mongo_session
69
- expect_any_instance_of(Moped::Session).to receive(:with).with(options).and_return(session)
70
- instance.collection
68
+ expect(instance.collection.database.name).to eq('test')
71
69
  end
72
70
  end
73
71
 
@@ -0,0 +1,739 @@
1
+ require "spec_helper"
2
+
3
+ describe Mongoid::Clients do
4
+
5
+ describe "#collection" do
6
+
7
+ shared_examples_for "an overridden collection at the class level" do
8
+
9
+ let(:band) do
10
+ klass.new
11
+ end
12
+
13
+ it "returns the collection for the model" do
14
+ expect(band.collection).to be_a(Mongo::Collection)
15
+ end
16
+
17
+ it "sets the correct collection name" do
18
+ expect(band.collection.name).to eq("artists")
19
+ end
20
+
21
+ context "when accessing from the class level" do
22
+
23
+ it "returns the collection for the model" do
24
+ expect(klass.collection).to be_a(Mongo::Collection)
25
+ end
26
+
27
+ it "sets the correct collection name" do
28
+ expect(klass.collection.name).to eq("artists")
29
+ end
30
+ end
31
+ end
32
+
33
+ context "when overriding the persistence options" do
34
+
35
+ let(:klass) do
36
+ Band.with(collection: "artists")
37
+ end
38
+
39
+ it_behaves_like "an overridden collection at the class level"
40
+ end
41
+
42
+ context "when overriding store_in and persistence options" do
43
+
44
+ let(:klass) do
45
+ Band.with(collection: "artists")
46
+ end
47
+
48
+ before do
49
+ Band.store_in collection: "foo"
50
+ end
51
+
52
+ after do
53
+ Band.reset_storage_options!
54
+ end
55
+
56
+ it_behaves_like "an overridden collection at the class level"
57
+ end
58
+
59
+ context "when overriding the default with store_in" do
60
+
61
+ after do
62
+ Band.reset_storage_options!
63
+ end
64
+
65
+ context "when called multiple times with different options" do
66
+
67
+ before do
68
+ Band.store_in collection: "artists"
69
+ Band.store_in client: "another"
70
+ end
71
+
72
+ it "should merge the options together" do
73
+ expect(Band.storage_options[:collection]).to eq("artists")
74
+ expect(Band.storage_options[:client]).to eq("another")
75
+ end
76
+ end
77
+
78
+ context "when overriding with a proc" do
79
+
80
+ let(:klass) { Band }
81
+
82
+ before do
83
+ Band.store_in(collection: ->{ "artists" })
84
+ end
85
+
86
+ it_behaves_like "an overridden collection at the class level"
87
+ end
88
+
89
+ context "when overriding with a string" do
90
+
91
+ let(:klass) { Band }
92
+
93
+ before do
94
+ Band.store_in(collection: "artists")
95
+ end
96
+
97
+ after do
98
+ Band.reset_storage_options!
99
+ end
100
+
101
+ it_behaves_like "an overridden collection at the class level"
102
+ end
103
+
104
+ context "when overriding with a symbol" do
105
+
106
+ let(:klass) { Band }
107
+
108
+ before do
109
+ klass.store_in(collection: :artists)
110
+ end
111
+
112
+ after do
113
+ klass.reset_storage_options!
114
+ end
115
+
116
+ it_behaves_like "an overridden collection at the class level"
117
+ end
118
+ end
119
+
120
+ context "when not overriding the default" do
121
+
122
+ let(:band) do
123
+ Band.new
124
+ end
125
+
126
+ it "returns the collection for the model" do
127
+ expect(band.collection).to be_a(Mongo::Collection)
128
+ end
129
+
130
+ it "sets the correct collection name" do
131
+ expect(band.collection.name.to_s).to eq("bands")
132
+ end
133
+
134
+ context "when accessing from the class level" do
135
+
136
+ it "returns the collection for the model" do
137
+ expect(Band.collection).to be_a(Mongo::Collection)
138
+ end
139
+
140
+ it "sets the correct collection name" do
141
+ expect(Band.collection.name.to_s).to eq("bands")
142
+ end
143
+ end
144
+ end
145
+ end
146
+
147
+ describe "#collection_name" do
148
+
149
+ shared_examples_for "an overridden collection name at the class level" do
150
+
151
+ let(:band) do
152
+ klass.new
153
+ end
154
+
155
+ context "when accessing from the instance" do
156
+
157
+ it "returns the overridden value" do
158
+ expect(band.collection_name).to eq(:artists)
159
+ end
160
+ end
161
+
162
+ context "when accessing from the class level" do
163
+
164
+ it "returns the overridden value" do
165
+ expect(klass.collection_name).to eq(:artists)
166
+ end
167
+ end
168
+ end
169
+
170
+ context "when overriding the persistence options" do
171
+
172
+ let(:klass) do
173
+ Band.with(collection: "artists")
174
+ end
175
+
176
+ it_behaves_like "an overridden collection name at the class level"
177
+ end
178
+
179
+ context "when overriding store_in and persistence options" do
180
+
181
+ let(:klass) do
182
+ Band.with(collection: "artists")
183
+ end
184
+
185
+ before do
186
+ Band.store_in collection: "foo"
187
+ end
188
+
189
+ after do
190
+ Band.reset_storage_options!
191
+ end
192
+
193
+ it_behaves_like "an overridden collection name at the class level"
194
+ end
195
+
196
+ context "when overriding the default with store_in" do
197
+
198
+ let(:klass) { Band }
199
+
200
+ after do
201
+ Band.reset_storage_options!
202
+ end
203
+
204
+ context "when overriding with a proc" do
205
+
206
+ before do
207
+ Band.store_in(collection: ->{ "artists" })
208
+ end
209
+
210
+ it_behaves_like "an overridden collection name at the class level"
211
+ end
212
+
213
+ context "when overriding with a string" do
214
+
215
+ before do
216
+ Band.store_in(collection: "artists")
217
+ end
218
+
219
+ it_behaves_like "an overridden collection name at the class level"
220
+ end
221
+
222
+ context "when overriding with a symbol" do
223
+
224
+ before do
225
+ Band.store_in(collection: :artists)
226
+ end
227
+
228
+ it_behaves_like "an overridden collection name at the class level"
229
+ end
230
+ end
231
+
232
+ context "when not overriding the default" do
233
+
234
+ let(:band) do
235
+ Band.new
236
+ end
237
+
238
+ it "returns the pluralized model name" do
239
+ expect(band.collection_name).to eq(:bands)
240
+ end
241
+
242
+ context "when accessing from the class level" do
243
+
244
+ it "returns the pluralized model name" do
245
+ expect(Band.collection_name).to eq(:bands)
246
+ end
247
+ end
248
+ end
249
+
250
+ context "when the model is a subclass" do
251
+
252
+ let(:firefox) do
253
+ Firefox.new
254
+ end
255
+
256
+ it "returns the root class pluralized model name" do
257
+ expect(firefox.collection_name).to eq(:canvases)
258
+ end
259
+
260
+ context "when accessing from the class level" do
261
+
262
+ it "returns the root class pluralized model name" do
263
+ expect(Firefox.collection_name).to eq(:canvases)
264
+ end
265
+ end
266
+ end
267
+ end
268
+
269
+ describe "#database_name", if: non_legacy_server? do
270
+
271
+ shared_examples_for "an overridden database name" do
272
+
273
+ let(:band) do
274
+ klass.new
275
+ end
276
+
277
+ context "when accessing from the instance" do
278
+
279
+ it "returns the overridden value" do
280
+ # @todo
281
+ # expect(band.mongo_client.options[:database].to_s).to eq(database_id_alt)
282
+ end
283
+ end
284
+
285
+ context "when accessing from the class level" do
286
+
287
+ it "returns the overridden value" do
288
+ expect(klass.database_name.to_s).to eq(database_id_alt)
289
+ end
290
+
291
+ it "client returns the overridden value" do
292
+ expect(klass.mongo_client.options[:database].to_s).to eq(database_id_alt)
293
+ end
294
+ end
295
+ end
296
+
297
+ context "when overriding the persistence options" do
298
+
299
+ let(:klass) do
300
+ Band.with(database: database_id_alt)
301
+ end
302
+
303
+ it_behaves_like "an overridden database name"
304
+ end
305
+
306
+ context "when overriding with store_in" do
307
+
308
+ let(:klass) { Band }
309
+
310
+ before do
311
+ Band.store_in database: database_id_alt
312
+ end
313
+
314
+ after do
315
+ Band.reset_storage_options!
316
+ end
317
+
318
+ it_behaves_like "an overridden database name"
319
+ end
320
+
321
+ context "when overriding store_in and persistence options" do
322
+
323
+ let(:klass) do
324
+ Band.with(database: database_id_alt)
325
+ end
326
+
327
+ before do
328
+ Band.store_in database: "foo"
329
+ end
330
+
331
+ after do
332
+ Band.reset_storage_options!
333
+ end
334
+
335
+ it_behaves_like "an overridden database name"
336
+ end
337
+
338
+ context "when overriding using the client" do
339
+
340
+ let(:client_name) { :alternative }
341
+
342
+ before do
343
+ Mongoid.clients[client_name] = { database: database_id_alt, hosts: [ "#{HOST}:#{PORT}" ] }
344
+ end
345
+
346
+ after do
347
+ Mongoid.clients.delete(client_name)
348
+ end
349
+
350
+ context "when overriding the persistence options" do
351
+
352
+ let(:klass) do
353
+ Band.with(client: client_name)
354
+ end
355
+
356
+ it_behaves_like "an overridden database name"
357
+ end
358
+
359
+ context "when overriding with store_in" do
360
+
361
+ let(:klass) { Band }
362
+
363
+ before do
364
+ Band.store_in(client: client_name)
365
+ end
366
+
367
+ after do
368
+ Band.reset_storage_options!
369
+ end
370
+
371
+ it_behaves_like "an overridden database name"
372
+ end
373
+ end
374
+ end
375
+
376
+ describe "#mongo_client", if: non_legacy_server? do
377
+
378
+ let(:file) do
379
+ File.join(File.dirname(__FILE__), "..", "config", "mongoid.yml")
380
+ end
381
+
382
+ before do
383
+ described_class.clear
384
+ Mongoid.load!(file, :test)
385
+ Mongoid.clients[:default][:database] = database_id
386
+ end
387
+
388
+ context "when getting the default" do
389
+
390
+ let(:file) do
391
+ File.join(File.dirname(__FILE__), "..", "config", "mongoid.yml")
392
+ end
393
+
394
+ before do
395
+ described_class.clear
396
+ Mongoid.load!(file, :test)
397
+ Mongoid.clients[:default][:database] = database_id
398
+ end
399
+
400
+ let!(:band) do
401
+ Band.new
402
+ end
403
+
404
+ let!(:mongo_client) do
405
+ band.mongo_client
406
+ end
407
+
408
+ it "returns the default client" do
409
+ expect(mongo_client.options[:database].to_s).to eq(database_id)
410
+ end
411
+ end
412
+
413
+ context "when no client exists with the key" do
414
+
415
+ before(:all) do
416
+ Band.store_in(client: :nonexistant)
417
+ end
418
+
419
+ let(:band) do
420
+ Band.new
421
+ end
422
+
423
+ it "raises an error" do
424
+ expect {
425
+ band.mongo_client
426
+ }.to raise_error(Mongoid::Errors::NoClientConfig)
427
+ end
428
+ end
429
+ end
430
+
431
+ describe ".mongo_client", if: non_legacy_server? do
432
+
433
+ let(:file) do
434
+ File.join(File.dirname(__FILE__), "..", "config", "mongoid.yml")
435
+ end
436
+
437
+ before do
438
+ described_class.clear
439
+ Mongoid.load!(file, :test)
440
+ Mongoid.clients[:default][:database] = database_id
441
+ end
442
+
443
+ after do
444
+ Band.reset_storage_options!
445
+ end
446
+
447
+ context "when getting the default" do
448
+
449
+ let(:file) do
450
+ File.join(File.dirname(__FILE__), "..", "config", "mongoid.yml")
451
+ end
452
+
453
+ before do
454
+ Band.reset_storage_options!
455
+ described_class.clear
456
+ Mongoid.load!(file, :test)
457
+ Mongoid.clients[:default][:database] = database_id
458
+ end
459
+
460
+ let!(:mongo_client) do
461
+ Band.mongo_client
462
+ end
463
+
464
+ it "returns the default client" do
465
+ expect(mongo_client.options[:database].to_s).to eq(database_id)
466
+ end
467
+ end
468
+
469
+ context "when no client exists with the key" do
470
+
471
+ before(:all) do
472
+ Band.store_in(client: :nonexistant)
473
+ end
474
+
475
+ it "raises an error" do
476
+ expect {
477
+ Band.mongo_client
478
+ }.to raise_error(Mongoid::Errors::NoClientConfig)
479
+ end
480
+ end
481
+ end
482
+
483
+ describe ".store_in", if: non_legacy_server? do
484
+
485
+ context "when provided a non hash" do
486
+
487
+ it "raises an error" do
488
+ expect {
489
+ Band.store_in :artists
490
+ }.to raise_error(Mongoid::Errors::InvalidStorageOptions)
491
+ end
492
+ end
493
+
494
+ context "when provided a class that extend another document" do
495
+
496
+ let(:klass) do
497
+ Class.new(Band)
498
+ end
499
+
500
+ it "raises an error" do
501
+ expect {
502
+ klass.store_in(database: :artists)
503
+ }.to raise_error(Mongoid::Errors::InvalidStorageParent)
504
+ end
505
+ end
506
+
507
+ context "when provided a hash" do
508
+
509
+ context "when the hash is not valid" do
510
+
511
+ it "raises an error" do
512
+ expect {
513
+ Band.store_in coll: "artists"
514
+ }.to raise_error(Mongoid::Errors::InvalidStorageOptions)
515
+ end
516
+ end
517
+ end
518
+ end
519
+
520
+ describe ".with", if: non_legacy_server? do
521
+
522
+ context "when sending operations to a different database" do
523
+
524
+ after do
525
+ Band.with(database: database_id_alt).delete_all
526
+ end
527
+
528
+ describe ".create" do
529
+
530
+ let!(:band) do
531
+ Band.with(database: database_id_alt).create
532
+ end
533
+
534
+ it "does not persist to the default database" do
535
+ expect {
536
+ Band.find(band.id)
537
+ }.to raise_error(Mongoid::Errors::DocumentNotFound)
538
+ end
539
+
540
+ let(:from_db) do
541
+ Band.with(database: database_id_alt).find(band.id)
542
+ end
543
+
544
+ it "persists to the specified database" do
545
+ expect(from_db).to eq(band)
546
+ end
547
+
548
+ it "persists the correct number of documents" do
549
+ expect(Band.with(database: database_id_alt).count).to eq(1)
550
+ end
551
+ end
552
+ end
553
+
554
+ context "when sending operations to a different collection" do
555
+
556
+ describe ".create" do
557
+
558
+ let!(:band) do
559
+ Band.with(collection: "artists").create
560
+ end
561
+
562
+ it "does not persist to the default database" do
563
+ expect {
564
+ Band.find(band.id)
565
+ }.to raise_error(Mongoid::Errors::DocumentNotFound)
566
+ end
567
+
568
+ let(:from_db) do
569
+ Band.with(collection: "artists").find(band.id)
570
+ end
571
+
572
+ it "persists to the specified database" do
573
+ expect(from_db).to eq(band)
574
+ end
575
+
576
+ it "persists the correct number of documents" do
577
+ expect(Band.with(collection: "artists").count).to eq(1)
578
+ end
579
+ end
580
+ end
581
+
582
+ context "when sending operations with safe mode" do
583
+
584
+ describe ".create" do
585
+
586
+ before do
587
+ Person.create_indexes
588
+ Person.create(ssn: "432-97-1111")
589
+ end
590
+
591
+ context "when no error occurs" do
592
+
593
+ it "inserts the document" do
594
+ expect(Person.count).to eq(1)
595
+ end
596
+ end
597
+
598
+ context "when a mongodb error occurs" do
599
+
600
+ it "bubbles up to the caller" do
601
+ expect {
602
+ Person.create(ssn: "432-97-1111")
603
+ }.to raise_error(Mongo::Error::OperationFailure)
604
+ end
605
+ end
606
+ end
607
+
608
+ describe ".create!" do
609
+
610
+ before do
611
+ Person.create!(ssn: "432-97-1112")
612
+ end
613
+
614
+ context "when no error occurs" do
615
+
616
+ it "inserts the document" do
617
+ expect(Person.count).to eq(1)
618
+ end
619
+ end
620
+
621
+ context "when a mongodb error occurs" do
622
+
623
+ before do
624
+ Person.create_indexes
625
+ end
626
+
627
+ it "bubbles up to the caller" do
628
+ expect {
629
+ Person.create!(ssn: "432-97-1112")
630
+ }.to raise_error(Mongo::Error::OperationFailure)
631
+ end
632
+ end
633
+
634
+ context "when a validation error occurs" do
635
+
636
+ it "raises the validation error" do
637
+ expect {
638
+ Account.create!(name: "this name is way too long")
639
+ }.to raise_error(Mongoid::Errors::Validations)
640
+ end
641
+ end
642
+ end
643
+
644
+ describe ".save" do
645
+
646
+ before do
647
+ Person.create(ssn: "432-97-1113")
648
+ end
649
+
650
+ context "when a mongodb error occurs" do
651
+
652
+ let(:person) do
653
+ Person.new(ssn: "432-97-1113")
654
+ end
655
+
656
+ before do
657
+ Person.create_indexes
658
+ end
659
+
660
+ it "bubbles up to the caller" do
661
+ expect {
662
+ person.save
663
+ }.to raise_error(Mongo::Error::OperationFailure)
664
+ end
665
+ end
666
+ end
667
+
668
+ describe ".save!" do
669
+
670
+ before do
671
+ Person.create!(ssn: "432-97-1114")
672
+ end
673
+
674
+ context "when a mongodb error occurs" do
675
+
676
+ let(:person) do
677
+ Person.new(ssn: "432-97-1114")
678
+ end
679
+
680
+ before do
681
+ Person.create_indexes
682
+ end
683
+
684
+ it "bubbles up to the caller" do
685
+ expect {
686
+ person.save!
687
+ }.to raise_error(Mongo::Error::OperationFailure)
688
+ end
689
+ end
690
+
691
+ context "when a validation error occurs" do
692
+
693
+ let(:account) do
694
+ Account.new(name: "this name is way too long")
695
+ end
696
+
697
+ it "raises the validation error" do
698
+ expect {
699
+ account.save!
700
+ }.to raise_error(Mongoid::Errors::Validations)
701
+ end
702
+ end
703
+ end
704
+ end
705
+ end
706
+
707
+ context "when overriding the default database", if: non_legacy_server? do
708
+
709
+ let(:file) do
710
+ File.join(File.dirname(__FILE__), "..", "config", "mongoid.yml")
711
+ end
712
+
713
+ before do
714
+ Mongoid::Config.load!(file, :test)
715
+ end
716
+
717
+ context "when the override is global" do
718
+
719
+ before do
720
+ Mongoid.override_database(:mongoid_optional)
721
+ end
722
+
723
+ after do
724
+ Band.delete_all
725
+ Mongoid.override_database(nil)
726
+ end
727
+
728
+ let!(:band) do
729
+ Band.create(name: "Tool")
730
+ end
731
+
732
+ it "persists to the overridden database" do
733
+ Band.mongo_client.with(database: :mongoid_optional) do |sess|
734
+ expect(sess[:bands].find(name: "Tool")).to_not be_nil
735
+ end
736
+ end
737
+ end
738
+ end
739
+ end