mongoid 8.0.5 → 8.1.0

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 (174) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/CHANGELOG.md +3 -3
  4. data/README.md +3 -3
  5. data/Rakefile +0 -25
  6. data/lib/config/locales/en.yml +46 -14
  7. data/lib/mongoid/association/accessors.rb +2 -2
  8. data/lib/mongoid/association/builders.rb +1 -1
  9. data/lib/mongoid/association/embedded/batchable.rb +2 -2
  10. data/lib/mongoid/association/embedded/embedded_in/buildable.rb +2 -2
  11. data/lib/mongoid/association/embedded/embedded_in/proxy.rb +2 -1
  12. data/lib/mongoid/association/embedded/embeds_many/buildable.rb +3 -2
  13. data/lib/mongoid/association/embedded/embeds_many/proxy.rb +6 -6
  14. data/lib/mongoid/association/embedded/embeds_one/buildable.rb +1 -1
  15. data/lib/mongoid/association/embedded/embeds_one/proxy.rb +1 -1
  16. data/lib/mongoid/association/nested/one.rb +40 -2
  17. data/lib/mongoid/association/proxy.rb +1 -1
  18. data/lib/mongoid/association/referenced/counter_cache.rb +2 -2
  19. data/lib/mongoid/association/referenced/has_and_belongs_to_many/proxy.rb +1 -1
  20. data/lib/mongoid/association/referenced/has_many/enumerable.rb +2 -2
  21. data/lib/mongoid/association/referenced/has_many/proxy.rb +3 -3
  22. data/lib/mongoid/association/reflections.rb +2 -2
  23. data/lib/mongoid/atomic.rb +0 -7
  24. data/lib/mongoid/attributes/dynamic.rb +1 -1
  25. data/lib/mongoid/attributes/nested.rb +2 -2
  26. data/lib/mongoid/attributes/projector.rb +1 -1
  27. data/lib/mongoid/attributes/readonly.rb +1 -1
  28. data/lib/mongoid/attributes.rb +8 -2
  29. data/lib/mongoid/changeable.rb +107 -5
  30. data/lib/mongoid/clients/storage_options.rb +2 -5
  31. data/lib/mongoid/clients/validators/storage.rb +1 -13
  32. data/lib/mongoid/collection_configurable.rb +58 -0
  33. data/lib/mongoid/composable.rb +2 -0
  34. data/lib/mongoid/config/defaults.rb +60 -0
  35. data/lib/mongoid/config/validators/async_query_executor.rb +24 -0
  36. data/lib/mongoid/config/validators.rb +1 -0
  37. data/lib/mongoid/config.rb +101 -0
  38. data/lib/mongoid/contextual/atomic.rb +1 -1
  39. data/lib/mongoid/contextual/memory.rb +233 -33
  40. data/lib/mongoid/contextual/mongo/documents_loader.rb +177 -0
  41. data/lib/mongoid/contextual/mongo.rb +373 -113
  42. data/lib/mongoid/contextual/none.rb +162 -7
  43. data/lib/mongoid/contextual.rb +12 -0
  44. data/lib/mongoid/criteria/findable.rb +2 -2
  45. data/lib/mongoid/criteria/includable.rb +4 -3
  46. data/lib/mongoid/criteria/queryable/key.rb +1 -1
  47. data/lib/mongoid/criteria/queryable/mergeable.rb +1 -1
  48. data/lib/mongoid/criteria/queryable/optional.rb +8 -8
  49. data/lib/mongoid/criteria/queryable/selectable.rb +43 -12
  50. data/lib/mongoid/criteria.rb +6 -5
  51. data/lib/mongoid/deprecable.rb +1 -1
  52. data/lib/mongoid/errors/create_collection_failure.rb +33 -0
  53. data/lib/mongoid/errors/drop_collection_failure.rb +27 -0
  54. data/lib/mongoid/errors/immutable_attribute.rb +26 -0
  55. data/lib/mongoid/errors/invalid_async_query_executor.rb +25 -0
  56. data/lib/mongoid/errors/invalid_global_executor_concurrency.rb +22 -0
  57. data/lib/mongoid/errors/invalid_storage_parent.rb +2 -0
  58. data/lib/mongoid/errors.rb +4 -1
  59. data/lib/mongoid/extensions/object.rb +2 -2
  60. data/lib/mongoid/extensions/time.rb +2 -0
  61. data/lib/mongoid/fields/localized.rb +10 -0
  62. data/lib/mongoid/fields/standard.rb +10 -0
  63. data/lib/mongoid/fields.rb +69 -13
  64. data/lib/mongoid/findable.rb +27 -3
  65. data/lib/mongoid/interceptable.rb +7 -6
  66. data/lib/mongoid/matcher/eq_impl.rb +1 -1
  67. data/lib/mongoid/matcher/type.rb +1 -1
  68. data/lib/mongoid/persistable/creatable.rb +1 -0
  69. data/lib/mongoid/persistable/deletable.rb +1 -1
  70. data/lib/mongoid/persistable/savable.rb +13 -1
  71. data/lib/mongoid/persistable/unsettable.rb +2 -2
  72. data/lib/mongoid/persistable/updatable.rb +51 -1
  73. data/lib/mongoid/persistable/upsertable.rb +20 -1
  74. data/lib/mongoid/persistable.rb +3 -0
  75. data/lib/mongoid/query_cache.rb +5 -1
  76. data/lib/mongoid/railties/database.rake +7 -2
  77. data/lib/mongoid/reloadable.rb +5 -3
  78. data/lib/mongoid/stateful.rb +22 -1
  79. data/lib/mongoid/tasks/database.rake +12 -0
  80. data/lib/mongoid/tasks/database.rb +20 -0
  81. data/lib/mongoid/utils.rb +22 -0
  82. data/lib/mongoid/validatable/macros.rb +5 -5
  83. data/lib/mongoid/validatable.rb +4 -1
  84. data/lib/mongoid/version.rb +1 -1
  85. data/lib/mongoid/warnings.rb +17 -1
  86. data/lib/mongoid.rb +16 -3
  87. data/spec/integration/app_spec.rb +2 -2
  88. data/spec/integration/callbacks_models.rb +37 -0
  89. data/spec/integration/callbacks_spec.rb +134 -0
  90. data/spec/integration/discriminator_key_spec.rb +4 -5
  91. data/spec/integration/i18n_fallbacks_spec.rb +3 -2
  92. data/spec/mongoid/association/embedded/embedded_in/proxy_spec.rb +27 -0
  93. data/spec/mongoid/association/embedded/embeds_many/proxy_spec.rb +20 -25
  94. data/spec/mongoid/association/embedded/embeds_many_models.rb +1 -0
  95. data/spec/mongoid/association/embedded/embeds_one/proxy_spec.rb +15 -2
  96. data/spec/mongoid/association/referenced/belongs_to_spec.rb +2 -18
  97. data/spec/mongoid/association/referenced/has_and_belongs_to_many/proxy_spec.rb +5 -27
  98. data/spec/mongoid/association/referenced/has_many/proxy_spec.rb +9 -50
  99. data/spec/mongoid/association/syncable_spec.rb +1 -1
  100. data/spec/mongoid/attributes_spec.rb +3 -6
  101. data/spec/mongoid/changeable_spec.rb +299 -24
  102. data/spec/mongoid/clients_spec.rb +122 -13
  103. data/spec/mongoid/collection_configurable_spec.rb +158 -0
  104. data/spec/mongoid/config/defaults_spec.rb +160 -0
  105. data/spec/mongoid/config_spec.rb +154 -18
  106. data/spec/mongoid/contextual/memory_spec.rb +332 -76
  107. data/spec/mongoid/contextual/mongo/documents_loader_spec.rb +187 -0
  108. data/spec/mongoid/contextual/mongo_spec.rb +995 -36
  109. data/spec/mongoid/contextual/none_spec.rb +49 -2
  110. data/spec/mongoid/copyable_spec.rb +3 -11
  111. data/spec/mongoid/criteria/queryable/extensions/string_spec.rb +4 -10
  112. data/spec/mongoid/criteria/queryable/options_spec.rb +1 -1
  113. data/spec/mongoid/criteria/queryable/selectable_logical_spec.rb +419 -0
  114. data/spec/mongoid/criteria/queryable/selectable_spec.rb +1 -1
  115. data/spec/mongoid/criteria/queryable/selector_spec.rb +1 -1
  116. data/spec/mongoid/criteria_projection_spec.rb +1 -4
  117. data/spec/mongoid/criteria_spec.rb +5 -9
  118. data/spec/mongoid/errors/readonly_document_spec.rb +2 -2
  119. data/spec/mongoid/extensions/time_spec.rb +8 -43
  120. data/spec/mongoid/extensions/time_with_zone_spec.rb +7 -52
  121. data/spec/mongoid/fields/localized_spec.rb +46 -28
  122. data/spec/mongoid/fields_spec.rb +136 -34
  123. data/spec/mongoid/findable_spec.rb +391 -34
  124. data/spec/mongoid/indexable_spec.rb +16 -10
  125. data/spec/mongoid/interceptable_spec.rb +15 -3
  126. data/spec/mongoid/persistable/deletable_spec.rb +26 -6
  127. data/spec/mongoid/persistable/destroyable_spec.rb +26 -6
  128. data/spec/mongoid/persistable/incrementable_spec.rb +37 -0
  129. data/spec/mongoid/persistable/logical_spec.rb +37 -0
  130. data/spec/mongoid/persistable/poppable_spec.rb +36 -0
  131. data/spec/mongoid/persistable/pullable_spec.rb +72 -0
  132. data/spec/mongoid/persistable/pushable_spec.rb +72 -0
  133. data/spec/mongoid/persistable/renamable_spec.rb +36 -0
  134. data/spec/mongoid/persistable/savable_spec.rb +96 -0
  135. data/spec/mongoid/persistable/settable_spec.rb +37 -0
  136. data/spec/mongoid/persistable/unsettable_spec.rb +36 -0
  137. data/spec/mongoid/persistable/updatable_spec.rb +20 -28
  138. data/spec/mongoid/persistable/upsertable_spec.rb +80 -6
  139. data/spec/mongoid/persistence_context_spec.rb +7 -57
  140. data/spec/mongoid/query_cache_spec.rb +56 -61
  141. data/spec/mongoid/reloadable_spec.rb +24 -28
  142. data/spec/mongoid/scopable_spec.rb +70 -0
  143. data/spec/mongoid/serializable_spec.rb +9 -30
  144. data/spec/mongoid/stateful_spec.rb +122 -8
  145. data/spec/mongoid/tasks/database_rake_spec.rb +74 -0
  146. data/spec/mongoid/tasks/database_spec.rb +127 -0
  147. data/spec/mongoid/timestamps_spec.rb +9 -11
  148. data/spec/mongoid/touchable_spec.rb +277 -5
  149. data/spec/mongoid/touchable_spec_models.rb +3 -1
  150. data/spec/mongoid/traversable_spec.rb +9 -24
  151. data/spec/mongoid/validatable/uniqueness_spec.rb +2 -3
  152. data/spec/mongoid_spec.rb +36 -10
  153. data/spec/shared/lib/mrss/docker_runner.rb +7 -0
  154. data/spec/shared/lib/mrss/event_subscriber.rb +15 -5
  155. data/spec/shared/lib/mrss/lite_constraints.rb +10 -2
  156. data/spec/shared/lib/mrss/server_version_registry.rb +16 -23
  157. data/spec/shared/lib/mrss/utils.rb +28 -6
  158. data/spec/shared/share/Dockerfile.erb +36 -40
  159. data/spec/shared/shlib/server.sh +32 -8
  160. data/spec/shared/shlib/set_env.sh +4 -4
  161. data/spec/spec_helper.rb +5 -0
  162. data/spec/support/immutable_ids.rb +118 -0
  163. data/spec/support/macros.rb +47 -15
  164. data/spec/support/models/artist.rb +0 -1
  165. data/spec/support/models/band.rb +1 -0
  166. data/spec/support/models/book.rb +1 -0
  167. data/spec/support/models/building.rb +2 -0
  168. data/spec/support/models/cover.rb +10 -0
  169. data/spec/support/models/product.rb +1 -0
  170. data.tar.gz.sig +0 -0
  171. metadata +686 -650
  172. metadata.gz.sig +0 -0
  173. data/spec/mongoid/criteria/queryable/extensions/bignum_spec.rb +0 -60
  174. data/spec/mongoid/criteria/queryable/extensions/fixnum_spec.rb +0 -60
@@ -54,8 +54,17 @@ describe Mongoid::Contextual::None do
54
54
  end
55
55
 
56
56
  describe "#pluck" do
57
- it "returns an empty array" do
58
- expect(context.pluck(:id)).to eq([])
57
+
58
+ context "when plucking one field" do
59
+ it "returns an empty array" do
60
+ expect(context.pluck(:id)).to eq([])
61
+ end
62
+ end
63
+
64
+ context "when plucking multiple fields" do
65
+ it "returns an empty array" do
66
+ expect(context.pluck(:id, :foo)).to eq([])
67
+ end
59
68
  end
60
69
  end
61
70
 
@@ -81,6 +90,14 @@ describe Mongoid::Contextual::None do
81
90
  end
82
91
  end
83
92
 
93
+ describe "#first!" do
94
+ it "raises an error" do
95
+ expect do
96
+ context.first!
97
+ end.to raise_error(Mongoid::Errors::DocumentNotFound, /Could not find a document of class Band./)
98
+ end
99
+ end
100
+
84
101
  describe "#last" do
85
102
  it "returns nil" do
86
103
  expect(context.last).to be_nil
@@ -91,6 +108,14 @@ describe Mongoid::Contextual::None do
91
108
  end
92
109
  end
93
110
 
111
+ describe "#last!" do
112
+ it "raises an error" do
113
+ expect do
114
+ context.last!
115
+ end.to raise_error(Mongoid::Errors::DocumentNotFound, /Could not find a document of class Band./)
116
+ end
117
+ end
118
+
94
119
  describe "#take" do
95
120
  it "returns nil" do
96
121
  expect(context.take).to be_nil
@@ -109,6 +134,28 @@ describe Mongoid::Contextual::None do
109
134
  end
110
135
  end
111
136
 
137
+ [ :second,
138
+ :third,
139
+ :fourth,
140
+ :fifth,
141
+ :second_to_last,
142
+ :third_to_last
143
+ ].each do |meth|
144
+ describe "##{meth}" do
145
+ it "returns nil" do
146
+ expect(context.send(meth)).to be_nil
147
+ end
148
+ end
149
+
150
+ describe "##{meth}!" do
151
+ it "raises an error" do
152
+ expect do
153
+ context.send("#{meth}!")
154
+ end.to raise_error(Mongoid::Errors::DocumentNotFound, /Could not find a document of class Band./)
155
+ end
156
+ end
157
+ end
158
+
112
159
  describe "#length" do
113
160
  it "returns zero" do
114
161
  expect(context.length).to eq(0)
@@ -90,7 +90,7 @@ describe Mongoid::Copyable do
90
90
  end
91
91
 
92
92
  it 'calls constructor with explicitly declared attributes only' do
93
- expect(Mongoid::Factory).to receive(:build).with(cls, 'name' => 'test').and_call_original
93
+ expect(Mongoid::Factory).to receive(:build).with(cls, { 'name' => 'test' }).and_call_original
94
94
  cloned
95
95
  end
96
96
  end
@@ -164,19 +164,15 @@ describe Mongoid::Copyable do
164
164
  end
165
165
 
166
166
  context "when cloning a document with multiple languages field" do
167
+ with_default_i18n_configs
167
168
 
168
169
  before do
169
- I18n.enforce_available_locales = false
170
170
  I18n.locale = 'pt_BR'
171
171
  person.desc = "descrição"
172
172
  person.addresses.first.name = "descrição"
173
173
  person.save!
174
174
  end
175
175
 
176
- after do
177
- I18n.locale = :en
178
- end
179
-
180
176
  let!(:from_db) do
181
177
  Person.find(person.id)
182
178
  end
@@ -212,22 +208,18 @@ describe Mongoid::Copyable do
212
208
  end
213
209
 
214
210
  context "when cloning a document with polymorphic embedded documents with multiple language field" do
211
+ with_default_i18n_configs
215
212
 
216
213
  let!(:shipment_address) do
217
214
  person.addresses.build({ shipping_name: "Title" }, ShipmentAddress)
218
215
  end
219
216
 
220
217
  before do
221
- I18n.enforce_available_locales = false
222
218
  I18n.locale = 'pt_BR'
223
219
  person.addresses.type(ShipmentAddress).each { |address| address.shipping_name = "Título" }
224
220
  person.save!
225
221
  end
226
222
 
227
- after do
228
- I18n.locale = :en
229
- end
230
-
231
223
  let!(:from_db) do
232
224
  Person.find(person.id)
233
225
  end
@@ -72,11 +72,8 @@ describe String do
72
72
  context "when the string without timezone" do
73
73
 
74
74
  context "when using active support's time zone" do
75
-
76
- before do
77
- Mongoid.use_activesupport_time_zone = true
78
- ::Time.zone = "Tokyo"
79
- end
75
+ config_override :use_activesupport_time_zone, true
76
+ time_zone_override "Tokyo"
80
77
 
81
78
  let(:date) do
82
79
  "2010-01-01 5:00:00"
@@ -92,11 +89,8 @@ describe String do
92
89
  end
93
90
 
94
91
  context "when not using active support's time zone" do
95
-
96
- before do
97
- Mongoid.use_activesupport_time_zone = false
98
- ::Time.zone = nil
99
- end
92
+ config_override :use_activesupport_time_zone, false
93
+ time_zone_override nil
100
94
 
101
95
  let(:date) do
102
96
  "2010-01-01 5:00:00"
@@ -221,6 +221,7 @@ describe Mongoid::Criteria::Queryable::Options do
221
221
  end
222
222
 
223
223
  context "when the serializer is localized" do
224
+ with_default_i18n_configs
224
225
 
225
226
  before(:all) do
226
227
  class Field
@@ -232,7 +233,6 @@ describe Mongoid::Criteria::Queryable::Options do
232
233
 
233
234
  after(:all) do
234
235
  Object.send(:remove_const, :Field)
235
- ::I18n.locale = :en
236
236
  end
237
237
 
238
238
  let(:options) do
@@ -2116,4 +2116,423 @@ describe Mongoid::Criteria::Queryable::Selectable do
2116
2116
  end
2117
2117
  end
2118
2118
  end
2119
+
2120
+ describe "#none_of" do
2121
+ context 'when argument is a mix of Criteria and hashes' do
2122
+ let(:query) { Mongoid::Query.new.where(hello: 'world') }
2123
+ let(:other1) { Mongoid::Query.new.where(foo: 'bar') }
2124
+ let(:other2) { { bar: 42 } }
2125
+ let(:other3) { Mongoid::Query.new.where(a: 2) }
2126
+
2127
+ let(:result) { query.none_of(other1, other2, other3) }
2128
+
2129
+ it 'combines' do
2130
+ expect(result.selector).to eq(
2131
+ 'hello' => 'world',
2132
+ '$nor' => [
2133
+ {'foo' => 'bar'},
2134
+ {'bar' => 42},
2135
+ {'a' => 2},
2136
+ ],
2137
+ )
2138
+ end
2139
+ end
2140
+
2141
+ context "when provided no arguments" do
2142
+ let(:selection) { query.none_of }
2143
+
2144
+ it_behaves_like 'returns a cloned query'
2145
+
2146
+ it "does not add any criteria" do
2147
+ expect(selection.selector).to eq({})
2148
+ end
2149
+
2150
+ it "returns the query" do
2151
+ expect(selection).to eq(query)
2152
+ end
2153
+ end
2154
+
2155
+ context "when provided nil" do
2156
+ let(:selection) { query.none_of(nil) }
2157
+
2158
+ it_behaves_like 'returns a cloned query'
2159
+
2160
+ it "does not add any criteria" do
2161
+ expect(selection.selector).to eq({})
2162
+ end
2163
+
2164
+ it "returns the query" do
2165
+ expect(selection).to eq(query)
2166
+ end
2167
+ end
2168
+
2169
+ context "when provided a single criterion" do
2170
+ let(:selection) { query.none_of(field: [ 1, 2 ]) }
2171
+
2172
+ it_behaves_like 'returns a cloned query'
2173
+
2174
+ it 'adds the $nor selector' do
2175
+ expect(selection.selector).to eq(
2176
+ '$nor' => [ { 'field' => [ 1, 2 ] } ],
2177
+ )
2178
+ end
2179
+
2180
+ context 'when the criterion is wrapped in array' do
2181
+ let(:selection) { query.none_of([{ field: [ 1, 2 ] }]) }
2182
+
2183
+ it_behaves_like 'returns a cloned query'
2184
+
2185
+ it 'adds the condition' do
2186
+ expect(selection.selector).to eq(
2187
+ '$nor' => [ { 'field' => [ 1, 2 ] } ],
2188
+ )
2189
+ end
2190
+
2191
+ context 'when the array has nil as one of the elements' do
2192
+ let(:selection) { query.none_of([{ field: [ 1, 2 ] }, nil]) }
2193
+
2194
+ it_behaves_like 'returns a cloned query'
2195
+
2196
+ it 'adds the $nor selector ignoring the nil element' do
2197
+ expect(selection.selector).to eq(
2198
+ '$nor' => [ { 'field' => [ 1, 2 ] } ],
2199
+ )
2200
+ end
2201
+ end
2202
+ end
2203
+
2204
+ context 'when query already has a condition on another field' do
2205
+ context 'when there is one argument' do
2206
+ let(:selection) { query.where(foo: 'bar').none_of(field: [ 1, 2 ]) }
2207
+
2208
+ it 'adds the new condition' do
2209
+ expect(selection.selector).to eq(
2210
+ 'foo' => 'bar',
2211
+ '$nor' => [ { 'field' => [1, 2] } ],
2212
+ )
2213
+ end
2214
+ end
2215
+
2216
+ context 'when there are multiple arguments' do
2217
+ let(:selection) do
2218
+ query.where(foo: 'bar').none_of({ field: [ 1, 2 ] }, { hello: 'world' })
2219
+ end
2220
+
2221
+ it 'adds the new condition' do
2222
+ expect(selection.selector).to eq(
2223
+ 'foo' => 'bar',
2224
+ '$nor' => [
2225
+ { 'field' => [1, 2] },
2226
+ { 'hello' => 'world' },
2227
+ ],
2228
+ )
2229
+ end
2230
+ end
2231
+ end
2232
+
2233
+ context 'when query already has a $nor condition and another condition' do
2234
+ let(:selection) do
2235
+ query.nor(field: [ 1, 2 ]).where(foo: 'bar').none_of(test: 1)
2236
+ end
2237
+
2238
+ it 'adds the new condition' do
2239
+ expect(selection.selector).to eq(
2240
+ '$nor' => [ { 'field' => [1, 2] } ],
2241
+ 'foo' => 'bar',
2242
+ '$and' => [ { '$nor' => [ { 'test' => 1 } ] } ]
2243
+ )
2244
+ end
2245
+ end
2246
+
2247
+ context 'when none_of has multiple arguments' do
2248
+ let(:selection) do
2249
+ query.nor(field: [ 1, 2 ]).where(foo: 'bar').none_of({a: 1}, {b: 2})
2250
+ end
2251
+
2252
+ it 'adds the new condition to top level' do
2253
+ expect(selection.selector).to eq(
2254
+ 'foo' => 'bar',
2255
+ '$nor' => [ { 'field' => [1, 2] } ],
2256
+ '$and' => [ { '$nor' => [ { 'a' => 1 }, { 'b' => 2 } ] } ]
2257
+ )
2258
+ end
2259
+
2260
+ context 'when query already has a top-level $and' do
2261
+ let(:selection) do
2262
+ query.nor(field: [ 1, 2 ]).where('$and' => [foo: 'bar']).none_of({a: 1}, {b: 2})
2263
+ end
2264
+
2265
+ it 'adds the new condition to top level $and' do
2266
+ expect(selection.selector).to eq(
2267
+ '$nor' => [ { 'field' => [1, 2] } ],
2268
+ '$and' => [
2269
+ { 'foo' => 'bar' },
2270
+ { '$nor' => [ { 'a' => 1 }, { 'b' => 2 } ] }
2271
+ ],
2272
+ )
2273
+ end
2274
+ end
2275
+ end
2276
+ end
2277
+
2278
+ context "when provided multiple criteria" do
2279
+ context "when the criteria are for different fields" do
2280
+ let(:selection) do
2281
+ query.none_of({ first: [ 1, 2 ] }, { second: [ 3, 4 ] })
2282
+ end
2283
+
2284
+ it_behaves_like 'returns a cloned query'
2285
+
2286
+ it "adds the $nor selector" do
2287
+ expect(selection.selector).to eq({
2288
+ "$nor" => [
2289
+ { "first" => [ 1, 2 ] },
2290
+ { "second" => [ 3, 4 ] }
2291
+ ]
2292
+ })
2293
+ end
2294
+ end
2295
+
2296
+ context "when the criteria uses a Key instance" do
2297
+ let(:selection) do
2298
+ query.none_of({ first: [ 1, 2 ] }, { :second.gt => 3 })
2299
+ end
2300
+
2301
+ it "adds the $nor selector" do
2302
+ expect(selection.selector).to eq({
2303
+ "$nor" => [
2304
+ { "first" => [ 1, 2 ] },
2305
+ { "second" => { "$gt" => 3 }}
2306
+ ]
2307
+ })
2308
+ end
2309
+
2310
+ it_behaves_like 'returns a cloned query'
2311
+ end
2312
+
2313
+ context 'when criteria are simple and handled via Key' do
2314
+ shared_examples_for 'adds conditions with $nor' do
2315
+ it "adds conditions with $nor" do
2316
+ expect(selection.selector).to eq({
2317
+ '$nor' => [
2318
+ {'field' => 3},
2319
+ {'field' => {'$lt' => 5}},
2320
+ ],
2321
+ })
2322
+ end
2323
+
2324
+ it_behaves_like 'returns a cloned query'
2325
+ end
2326
+
2327
+ shared_examples_for 'combines conditions with $eq' do
2328
+ it "combines conditions with $eq" do
2329
+ expect(selection.selector).to eq({
2330
+ '$nor' => [ { 'field' => { '$eq' => 3, '$lt' => 5 } } ]
2331
+ })
2332
+ end
2333
+
2334
+ it_behaves_like 'returns a cloned query'
2335
+ end
2336
+
2337
+ shared_examples_for 'combines conditions with $regex' do
2338
+ it 'combines conditions with $regex' do
2339
+ expect(selection.selector).to eq({
2340
+ '$nor' => [ { 'field' => { '$regex' => /t/, '$lt' => 5 } } ]
2341
+ })
2342
+ end
2343
+
2344
+ it_behaves_like 'returns a cloned query'
2345
+ end
2346
+
2347
+ context 'criteria are provided in the same hash' do
2348
+ context 'non-regexp argument' do
2349
+ let(:selection) { query.none_of(:field => 3, :field.lt => 5) }
2350
+ it_behaves_like 'combines conditions with $eq'
2351
+ end
2352
+
2353
+ context 'regexp argument' do
2354
+ let(:selection) { query.none_of(:field => /t/, :field.lt => 5) }
2355
+ it_behaves_like 'combines conditions with $regex'
2356
+ end
2357
+ end
2358
+
2359
+ context 'criteria are provided in separate hashes' do
2360
+ let(:selection) { query.none_of({:field => 3}, {:field.lt => 5}) }
2361
+ it_behaves_like 'adds conditions with $nor'
2362
+ end
2363
+
2364
+ context 'when the criterion is wrapped in an array' do
2365
+ let(:selection) { query.none_of([:field => 3], [:field.lt => 5]) }
2366
+ it_behaves_like 'adds conditions with $nor'
2367
+ end
2368
+ end
2369
+
2370
+ context 'when criteria are handled via Key and simple' do
2371
+ shared_examples_for 'adds conditions with $nor' do
2372
+ it 'adds conditions with $nor' do
2373
+ expect(selection.selector).to eq({
2374
+ '$nor' => [
2375
+ { 'field' => { '$gt' => 3 } },
2376
+ { 'field' => 5 },
2377
+ ],
2378
+ })
2379
+ end
2380
+
2381
+ it_behaves_like 'returns a cloned query'
2382
+ end
2383
+
2384
+ shared_examples_for 'combines conditions with $eq' do
2385
+ it 'combines conditions with $eq' do
2386
+ expect(selection.selector).to eq(
2387
+ '$nor' => [ { 'field' => {'$gt' => 3, '$eq' => 5} } ],
2388
+ )
2389
+ end
2390
+
2391
+ it_behaves_like 'returns a cloned query'
2392
+ end
2393
+
2394
+ shared_examples_for 'combines conditions with $regex' do
2395
+ it 'combines conditions with $regex' do
2396
+ expect(selection.selector).to eq(
2397
+ '$nor' => [ { 'field' => {'$gt' => 3, '$regex' => /t/} } ],
2398
+ )
2399
+ end
2400
+
2401
+ it_behaves_like 'returns a cloned query'
2402
+ end
2403
+
2404
+ context 'criteria are provided in the same hash' do
2405
+ context 'non-regexp argument' do
2406
+ let(:selection) { query.none_of(:field.gt => 3, :field => 5) }
2407
+ it_behaves_like 'combines conditions with $eq'
2408
+ end
2409
+
2410
+ context 'regexp argument' do
2411
+ let(:selection) { query.none_of(:field.gt => 3, :field => /t/) }
2412
+ it_behaves_like 'combines conditions with $regex'
2413
+ end
2414
+ end
2415
+
2416
+ context 'criteria are provided in separate hashes' do
2417
+ let(:selection) { query.none_of({:field.gt => 3}, {:field => 5}) }
2418
+ it_behaves_like 'adds conditions with $nor'
2419
+ end
2420
+
2421
+ context 'when the criterion is wrapped in an array' do
2422
+ let(:selection) { query.none_of([:field.gt => 3], [:field => 5]) }
2423
+ it_behaves_like 'adds conditions with $nor'
2424
+ end
2425
+ end
2426
+
2427
+ context 'when a criterion has an aliased field' do
2428
+ let(:selection) { query.none_of({ id: 1 }) }
2429
+
2430
+ it 'adds the $nor selector and aliases the field' do
2431
+ expect(selection.selector).to eq('$nor' => [{ '_id' => 1 }])
2432
+ end
2433
+
2434
+ it_behaves_like 'returns a cloned query'
2435
+ end
2436
+
2437
+ context 'when a criterion is wrapped in an array' do
2438
+ let(:selection) do
2439
+ query.none_of([{ first: [ 1, 2 ] }, { :second.gt => 3 }])
2440
+ end
2441
+
2442
+ it_behaves_like 'returns a cloned query'
2443
+
2444
+ it 'adds the $ nor selector' do
2445
+ expect(selection.selector).to eq({
2446
+ '$nor' => [
2447
+ { 'first' => [ 1, 2 ] },
2448
+ { 'second' => { '$gt' => 3 }}
2449
+ ]
2450
+ })
2451
+ end
2452
+ end
2453
+
2454
+ context "when the criteria are on the same field" do
2455
+ let(:selection) do
2456
+ query.none_of({ first: [ 1, 2 ] }, { first: [ 3, 4 ] })
2457
+ end
2458
+
2459
+ it_behaves_like 'returns a cloned query'
2460
+
2461
+ it 'appends both $nor expressions' do
2462
+ expect(selection.selector).to eq({
2463
+ "$nor" => [
2464
+ { "first" => [ 1, 2 ] },
2465
+ { "first" => [ 3, 4 ] }
2466
+ ]
2467
+ })
2468
+ end
2469
+ end
2470
+ end
2471
+
2472
+ context 'when chaining the criteria' do
2473
+ context 'when the criteria are for different fields' do
2474
+ let(:selection) do
2475
+ query.none_of(first: [ 1, 2 ]).none_of(second: [ 3, 4 ])
2476
+ end
2477
+
2478
+ it_behaves_like 'returns a cloned query'
2479
+
2480
+ it 'adds the conditions separately' do
2481
+ expect(selection.selector).to eq(
2482
+ '$nor' => [ { 'first' => [ 1, 2 ] } ],
2483
+ '$and' => [ { '$nor' => [ { 'second' => [ 3, 4 ] } ] } ],
2484
+ )
2485
+ end
2486
+ end
2487
+
2488
+ context "when the criteria are on the same field" do
2489
+ let(:selection) do
2490
+ query.none_of(first: [ 1, 2 ]).none_of(first: [ 3, 4 ])
2491
+ end
2492
+
2493
+ it_behaves_like 'returns a cloned query'
2494
+
2495
+ it 'adds the conditions separately' do
2496
+ expect(selection.selector).to eq(
2497
+ '$nor' => [ { 'first' => [ 1, 2 ] } ],
2498
+ '$and' => [ { '$nor' => [ { 'first' => [ 3, 4 ] } ] } ]
2499
+ )
2500
+ end
2501
+ end
2502
+ end
2503
+
2504
+ context 'when using multiple criteria and symbol operators' do
2505
+ context 'when using fields that meaningfully evolve values' do
2506
+ let(:query) do
2507
+ Dictionary.none_of({a: 1}, :published.gt => Date.new(2020, 2, 3))
2508
+ end
2509
+
2510
+ it 'generates the expected query' do
2511
+ query.selector.should == {'$nor' => [
2512
+ {'a' => 1},
2513
+ # Date instance is converted to a Time instance in local time,
2514
+ # because we are querying on a Time field and dates are interpreted
2515
+ # in local time when assigning to Time fields
2516
+ {'published' => {'$gt' => Time.local(2020, 2, 3) } },
2517
+ ] }
2518
+ end
2519
+ end
2520
+
2521
+ context 'when using fields that do not meaningfully evolve values' do
2522
+ let(:query) do
2523
+ Dictionary.none_of({a: 1}, :submitted_on.gt => Date.new(2020, 2, 3))
2524
+ end
2525
+
2526
+ it 'generates the expected query' do
2527
+ query.selector.should == {'$nor' => [
2528
+ {'a' => 1},
2529
+ # Date instance is converted to a Time instance in UTC,
2530
+ # because we are querying on a Date field and dates are interpreted
2531
+ # in UTC when persisted as dates by Mongoid
2532
+ {'submitted_on' => {'$gt' => Time.utc(2020, 2, 3)}},
2533
+ ]}
2534
+ end
2535
+ end
2536
+ end
2537
+ end
2119
2538
  end
@@ -2045,7 +2045,7 @@ describe Mongoid::Criteria::Queryable::Selectable do
2045
2045
  end
2046
2046
 
2047
2047
  # MongoDB server can only handle one text expression at a time,
2048
- # per https://docs.mongodb.com/manual/reference/operator/query/text/.
2048
+ # per https://www.mongodb.com/docs/manual/reference/operator/query/text/.
2049
2049
  # Nonetheless we test that the query is built correctly when
2050
2050
  # a user supplies more than one text condition.
2051
2051
  it 'merges conditions' do
@@ -608,6 +608,7 @@ describe Mongoid::Criteria::Queryable::Selector do
608
608
  end
609
609
 
610
610
  context "when the serializer is localized" do
611
+ with_default_i18n_configs
611
612
 
612
613
  before(:all) do
613
614
  class Field
@@ -623,7 +624,6 @@ describe Mongoid::Criteria::Queryable::Selector do
623
624
 
624
625
  after(:all) do
625
626
  Object.send(:remove_const, :Field)
626
- ::I18n.locale = :en
627
627
  end
628
628
 
629
629
  let(:selector) do
@@ -154,6 +154,7 @@ describe Mongoid::Criteria do
154
154
  end
155
155
 
156
156
  context 'when the field is localized' do
157
+ with_default_i18n_configs
157
158
 
158
159
  before do
159
160
  I18n.locale = :en
@@ -163,10 +164,6 @@ describe Mongoid::Criteria do
163
164
  d.save!
164
165
  end
165
166
 
166
- after do
167
- I18n.locale = :en
168
- end
169
-
170
167
  context 'when entire field is included' do
171
168
 
172
169
  let(:dictionary) do
@@ -1953,6 +1953,7 @@ describe Mongoid::Criteria do
1953
1953
  end
1954
1954
 
1955
1955
  context 'when plucking a localized field' do
1956
+ with_default_i18n_configs
1956
1957
 
1957
1958
  before do
1958
1959
  I18n.locale = :en
@@ -1962,10 +1963,6 @@ describe Mongoid::Criteria do
1962
1963
  d.save!
1963
1964
  end
1964
1965
 
1965
- after do
1966
- I18n.locale = :en
1967
- end
1968
-
1969
1966
  context 'when plucking the entire field' do
1970
1967
  let(:plucked) do
1971
1968
  Dictionary.all.pluck(:description)
@@ -2059,13 +2056,10 @@ describe Mongoid::Criteria do
2059
2056
  end
2060
2057
 
2061
2058
  context 'when fallbacks are enabled with a locale list' do
2062
- with_i18n_fallbacks
2059
+ require_fallbacks
2063
2060
 
2064
- around(:all) do |example|
2065
- prev_fallbacks = I18n.fallbacks.dup
2061
+ before do
2066
2062
  I18n.fallbacks[:he] = [ :en ]
2067
- example.run
2068
- I18n.fallbacks = prev_fallbacks
2069
2063
  end
2070
2064
 
2071
2065
  let(:plucked) do
@@ -2093,6 +2087,8 @@ describe Mongoid::Criteria do
2093
2087
  end
2094
2088
 
2095
2089
  context "when the localized field is embedded" do
2090
+ with_default_i18n_configs
2091
+
2096
2092
  before do
2097
2093
  p = Passport.new
2098
2094
  I18n.locale = :en