mongoid 8.0.3 → 8.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (188) 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/lib/config/locales/en.yml +46 -14
  6. data/lib/mongoid/association/accessors.rb +2 -2
  7. data/lib/mongoid/association/builders.rb +1 -1
  8. data/lib/mongoid/association/embedded/batchable.rb +2 -2
  9. data/lib/mongoid/association/embedded/embedded_in/buildable.rb +2 -2
  10. data/lib/mongoid/association/embedded/embedded_in/proxy.rb +2 -1
  11. data/lib/mongoid/association/embedded/embeds_many/buildable.rb +3 -2
  12. data/lib/mongoid/association/embedded/embeds_many/proxy.rb +23 -21
  13. data/lib/mongoid/association/embedded/embeds_one/buildable.rb +1 -1
  14. data/lib/mongoid/association/embedded/embeds_one/proxy.rb +1 -1
  15. data/lib/mongoid/association/nested/one.rb +40 -2
  16. data/lib/mongoid/association/proxy.rb +1 -1
  17. data/lib/mongoid/association/referenced/counter_cache.rb +2 -2
  18. data/lib/mongoid/association/referenced/has_and_belongs_to_many/proxy.rb +5 -1
  19. data/lib/mongoid/association/referenced/has_many/enumerable.rb +2 -2
  20. data/lib/mongoid/association/referenced/has_many/proxy.rb +7 -3
  21. data/lib/mongoid/association/reflections.rb +2 -2
  22. data/lib/mongoid/attributes/dynamic.rb +1 -1
  23. data/lib/mongoid/attributes/nested.rb +2 -2
  24. data/lib/mongoid/attributes/projector.rb +1 -1
  25. data/lib/mongoid/attributes/readonly.rb +1 -1
  26. data/lib/mongoid/attributes.rb +8 -2
  27. data/lib/mongoid/changeable.rb +104 -4
  28. data/lib/mongoid/clients/storage_options.rb +2 -5
  29. data/lib/mongoid/clients/validators/storage.rb +1 -13
  30. data/lib/mongoid/collection_configurable.rb +58 -0
  31. data/lib/mongoid/composable.rb +2 -0
  32. data/lib/mongoid/config/defaults.rb +60 -0
  33. data/lib/mongoid/config/validators/async_query_executor.rb +24 -0
  34. data/lib/mongoid/config/validators.rb +1 -0
  35. data/lib/mongoid/config.rb +101 -0
  36. data/lib/mongoid/contextual/atomic.rb +1 -1
  37. data/lib/mongoid/contextual/memory.rb +233 -33
  38. data/lib/mongoid/contextual/mongo/documents_loader.rb +177 -0
  39. data/lib/mongoid/contextual/mongo.rb +373 -113
  40. data/lib/mongoid/contextual/none.rb +162 -7
  41. data/lib/mongoid/contextual.rb +12 -0
  42. data/lib/mongoid/criteria/findable.rb +2 -2
  43. data/lib/mongoid/criteria/includable.rb +4 -3
  44. data/lib/mongoid/criteria/queryable/extensions/array.rb +1 -1
  45. data/lib/mongoid/criteria/queryable/extensions/hash.rb +1 -1
  46. data/lib/mongoid/criteria/queryable/extensions/numeric.rb +0 -8
  47. data/lib/mongoid/criteria/queryable/extensions/string.rb +1 -11
  48. data/lib/mongoid/criteria/queryable/extensions/symbol.rb +0 -10
  49. data/lib/mongoid/criteria/queryable/key.rb +1 -1
  50. data/lib/mongoid/criteria/queryable/mergeable.rb +1 -1
  51. data/lib/mongoid/criteria/queryable/optional.rb +8 -8
  52. data/lib/mongoid/criteria/queryable/selectable.rb +43 -12
  53. data/lib/mongoid/criteria/translator.rb +45 -0
  54. data/lib/mongoid/criteria.rb +7 -5
  55. data/lib/mongoid/deprecable.rb +1 -1
  56. data/lib/mongoid/document.rb +50 -13
  57. data/lib/mongoid/errors/create_collection_failure.rb +33 -0
  58. data/lib/mongoid/errors/drop_collection_failure.rb +27 -0
  59. data/lib/mongoid/errors/immutable_attribute.rb +26 -0
  60. data/lib/mongoid/errors/invalid_async_query_executor.rb +25 -0
  61. data/lib/mongoid/errors/invalid_global_executor_concurrency.rb +22 -0
  62. data/lib/mongoid/errors/invalid_storage_parent.rb +2 -0
  63. data/lib/mongoid/errors.rb +4 -1
  64. data/lib/mongoid/extensions/object.rb +2 -2
  65. data/lib/mongoid/extensions/time.rb +2 -0
  66. data/lib/mongoid/factory.rb +21 -8
  67. data/lib/mongoid/fields/localized.rb +10 -0
  68. data/lib/mongoid/fields/standard.rb +10 -0
  69. data/lib/mongoid/fields.rb +69 -13
  70. data/lib/mongoid/findable.rb +27 -3
  71. data/lib/mongoid/interceptable.rb +7 -6
  72. data/lib/mongoid/matcher/eq_impl.rb +1 -1
  73. data/lib/mongoid/matcher/type.rb +1 -1
  74. data/lib/mongoid/matcher.rb +21 -6
  75. data/lib/mongoid/persistable/creatable.rb +1 -0
  76. data/lib/mongoid/persistable/deletable.rb +1 -1
  77. data/lib/mongoid/persistable/savable.rb +13 -1
  78. data/lib/mongoid/persistable/unsettable.rb +2 -2
  79. data/lib/mongoid/persistable/updatable.rb +51 -1
  80. data/lib/mongoid/persistable/upsertable.rb +20 -1
  81. data/lib/mongoid/persistable.rb +3 -0
  82. data/lib/mongoid/query_cache.rb +5 -1
  83. data/lib/mongoid/railties/database.rake +7 -2
  84. data/lib/mongoid/shardable.rb +35 -11
  85. data/lib/mongoid/stateful.rb +22 -1
  86. data/lib/mongoid/tasks/database.rake +12 -0
  87. data/lib/mongoid/tasks/database.rb +20 -0
  88. data/lib/mongoid/threaded.rb +30 -0
  89. data/lib/mongoid/traversable.rb +1 -1
  90. data/lib/mongoid/utils.rb +22 -0
  91. data/lib/mongoid/validatable/macros.rb +5 -5
  92. data/lib/mongoid/validatable.rb +4 -1
  93. data/lib/mongoid/version.rb +1 -1
  94. data/lib/mongoid/warnings.rb +17 -1
  95. data/lib/mongoid.rb +16 -3
  96. data/spec/integration/app_spec.rb +2 -2
  97. data/spec/integration/callbacks_models.rb +37 -0
  98. data/spec/integration/callbacks_spec.rb +134 -0
  99. data/spec/integration/discriminator_key_spec.rb +4 -5
  100. data/spec/integration/i18n_fallbacks_spec.rb +3 -2
  101. data/spec/mongoid/association/embedded/embedded_in/proxy_spec.rb +27 -0
  102. data/spec/mongoid/association/embedded/embeds_many/proxy_spec.rb +57 -57
  103. data/spec/mongoid/association/embedded/embeds_many_models.rb +1 -0
  104. data/spec/mongoid/association/embedded/embeds_one/proxy_spec.rb +15 -2
  105. data/spec/mongoid/association/referenced/belongs_to_spec.rb +2 -18
  106. data/spec/mongoid/association/referenced/has_and_belongs_to_many/proxy_spec.rb +148 -224
  107. data/spec/mongoid/association/referenced/has_many/proxy_spec.rb +111 -164
  108. data/spec/mongoid/association/syncable_spec.rb +1 -1
  109. data/spec/mongoid/attributes_spec.rb +5 -8
  110. data/spec/mongoid/changeable_spec.rb +299 -24
  111. data/spec/mongoid/clients_spec.rb +122 -13
  112. data/spec/mongoid/collection_configurable_spec.rb +158 -0
  113. data/spec/mongoid/config/defaults_spec.rb +160 -0
  114. data/spec/mongoid/config_spec.rb +154 -18
  115. data/spec/mongoid/contextual/memory_spec.rb +332 -76
  116. data/spec/mongoid/contextual/mongo/documents_loader_spec.rb +187 -0
  117. data/spec/mongoid/contextual/mongo_spec.rb +995 -36
  118. data/spec/mongoid/contextual/none_spec.rb +49 -2
  119. data/spec/mongoid/copyable_spec.rb +3 -11
  120. data/spec/mongoid/criteria/queryable/extensions/string_spec.rb +4 -69
  121. data/spec/mongoid/criteria/queryable/extensions/symbol_spec.rb +0 -59
  122. data/spec/mongoid/criteria/queryable/optional_spec.rb +15 -0
  123. data/spec/mongoid/criteria/queryable/options_spec.rb +1 -1
  124. data/spec/mongoid/criteria/queryable/selectable_logical_spec.rb +419 -0
  125. data/spec/mongoid/criteria/queryable/selectable_spec.rb +1 -1
  126. data/spec/mongoid/criteria/queryable/selector_spec.rb +1 -1
  127. data/spec/mongoid/criteria/translator_spec.rb +132 -0
  128. data/spec/mongoid/criteria_projection_spec.rb +1 -4
  129. data/spec/mongoid/criteria_spec.rb +5 -9
  130. data/spec/mongoid/errors/readonly_document_spec.rb +2 -2
  131. data/spec/mongoid/extensions/time_spec.rb +8 -43
  132. data/spec/mongoid/extensions/time_with_zone_spec.rb +7 -52
  133. data/spec/mongoid/fields/localized_spec.rb +46 -28
  134. data/spec/mongoid/fields_spec.rb +136 -34
  135. data/spec/mongoid/findable_spec.rb +391 -34
  136. data/spec/mongoid/indexable_spec.rb +16 -10
  137. data/spec/mongoid/interceptable_spec.rb +15 -3
  138. data/spec/mongoid/persistable/deletable_spec.rb +26 -6
  139. data/spec/mongoid/persistable/destroyable_spec.rb +26 -6
  140. data/spec/mongoid/persistable/incrementable_spec.rb +37 -0
  141. data/spec/mongoid/persistable/logical_spec.rb +37 -0
  142. data/spec/mongoid/persistable/poppable_spec.rb +36 -0
  143. data/spec/mongoid/persistable/pullable_spec.rb +72 -0
  144. data/spec/mongoid/persistable/pushable_spec.rb +72 -0
  145. data/spec/mongoid/persistable/renamable_spec.rb +36 -0
  146. data/spec/mongoid/persistable/savable_spec.rb +96 -0
  147. data/spec/mongoid/persistable/settable_spec.rb +37 -0
  148. data/spec/mongoid/persistable/unsettable_spec.rb +36 -0
  149. data/spec/mongoid/persistable/updatable_spec.rb +20 -28
  150. data/spec/mongoid/persistable/upsertable_spec.rb +80 -6
  151. data/spec/mongoid/persistence_context_spec.rb +7 -57
  152. data/spec/mongoid/query_cache_spec.rb +56 -61
  153. data/spec/mongoid/reloadable_spec.rb +24 -4
  154. data/spec/mongoid/scopable_spec.rb +70 -0
  155. data/spec/mongoid/serializable_spec.rb +9 -30
  156. data/spec/mongoid/shardable_models.rb +14 -0
  157. data/spec/mongoid/shardable_spec.rb +153 -61
  158. data/spec/mongoid/stateful_spec.rb +122 -8
  159. data/spec/mongoid/tasks/database_rake_spec.rb +74 -0
  160. data/spec/mongoid/tasks/database_spec.rb +127 -0
  161. data/spec/mongoid/timestamps_spec.rb +9 -11
  162. data/spec/mongoid/touchable_spec.rb +277 -5
  163. data/spec/mongoid/touchable_spec_models.rb +3 -1
  164. data/spec/mongoid/traversable_spec.rb +9 -24
  165. data/spec/mongoid/validatable/uniqueness_spec.rb +2 -3
  166. data/spec/mongoid_spec.rb +35 -9
  167. data/spec/shared/lib/mrss/docker_runner.rb +7 -0
  168. data/spec/shared/lib/mrss/event_subscriber.rb +15 -5
  169. data/spec/shared/lib/mrss/lite_constraints.rb +10 -2
  170. data/spec/shared/lib/mrss/server_version_registry.rb +16 -23
  171. data/spec/shared/lib/mrss/utils.rb +28 -6
  172. data/spec/shared/share/Dockerfile.erb +36 -40
  173. data/spec/shared/shlib/server.sh +32 -8
  174. data/spec/shared/shlib/set_env.sh +4 -4
  175. data/spec/spec_helper.rb +5 -0
  176. data/spec/support/immutable_ids.rb +118 -0
  177. data/spec/support/macros.rb +47 -15
  178. data/spec/support/models/artist.rb +0 -1
  179. data/spec/support/models/band.rb +1 -0
  180. data/spec/support/models/book.rb +1 -0
  181. data/spec/support/models/building.rb +2 -0
  182. data/spec/support/models/cover.rb +10 -0
  183. data/spec/support/models/product.rb +1 -0
  184. data.tar.gz.sig +0 -0
  185. metadata +700 -656
  186. metadata.gz.sig +0 -0
  187. data/spec/mongoid/criteria/queryable/extensions/bignum_spec.rb +0 -60
  188. data/spec/mongoid/criteria/queryable/extensions/fixnum_spec.rb +0 -60
@@ -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
@@ -0,0 +1,132 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ describe Mongoid::Criteria::Translator do
6
+ describe "#to_direction" do
7
+ context "when the value is a string" do
8
+ context "when ascending" do
9
+ it "returns 1" do
10
+ expect(described_class.to_direction("ascending")).to eq(1)
11
+ end
12
+ end
13
+
14
+ context "when asc" do
15
+ it "returns 1" do
16
+ expect(described_class.to_direction("asc")).to eq(1)
17
+ end
18
+ end
19
+
20
+ context "when ASCENDING" do
21
+ it "returns 1" do
22
+ expect(described_class.to_direction("ASCENDING")).to eq(1)
23
+ end
24
+ end
25
+
26
+ context "when ASC" do
27
+ it "returns 1" do
28
+ expect(described_class.to_direction("ASC")).to eq(1)
29
+ end
30
+ end
31
+
32
+ context "when descending" do
33
+ it "returns -1" do
34
+ expect(described_class.to_direction("descending")).to eq(-1)
35
+ end
36
+ end
37
+
38
+ context "when desc" do
39
+ it "returns -1" do
40
+ expect(described_class.to_direction("desc")).to eq(-1)
41
+ end
42
+ end
43
+
44
+ context "when DESCENDING" do
45
+ it "returns -1" do
46
+ expect(described_class.to_direction("DESCENDING")).to eq(-1)
47
+ end
48
+ end
49
+
50
+ context "when DESC" do
51
+ it "returns -1" do
52
+ expect(described_class.to_direction("DESC")).to eq(-1)
53
+ end
54
+ end
55
+ end
56
+
57
+ context "when the value is a symbol" do
58
+ context "when ascending" do
59
+ it "returns 1" do
60
+ expect(described_class.to_direction(:ascending)).to eq(1)
61
+ end
62
+ end
63
+
64
+ context "when asc" do
65
+ it "returns 1" do
66
+ expect(described_class.to_direction(:asc)).to eq(1)
67
+ end
68
+ end
69
+
70
+ context "when ASCENDING" do
71
+ it "returns 1" do
72
+ expect(described_class.to_direction(:ASCENDING)).to eq(1)
73
+ end
74
+ end
75
+
76
+ context "when ASC" do
77
+ it "returns 1" do
78
+ expect(described_class.to_direction(:ASC)).to eq(1)
79
+ end
80
+ end
81
+
82
+ context "when descending" do
83
+ it "returns -1" do
84
+ expect(described_class.to_direction(:descending)).to eq(-1)
85
+ end
86
+ end
87
+
88
+ context "when desc" do
89
+ it "returns -1" do
90
+ expect(described_class.to_direction(:desc)).to eq(-1)
91
+ end
92
+ end
93
+
94
+ context "when DESCENDING" do
95
+ it "returns -1" do
96
+ expect(described_class.to_direction(:DESCENDING)).to eq(-1)
97
+ end
98
+ end
99
+
100
+ context "when DESC" do
101
+ it "returns -1" do
102
+ expect(described_class.to_direction(:DESC)).to eq(-1)
103
+ end
104
+ end
105
+ end
106
+
107
+ context "when the value is numeric" do
108
+ it "should pass the value through unchanged" do
109
+ expect(described_class.to_direction(1)).to eq(1)
110
+ expect(described_class.to_direction(-1)).to eq(-1)
111
+ expect(described_class.to_direction(Math::PI)).to eq(Math::PI)
112
+ end
113
+ end
114
+
115
+ context "when the value is a hash" do
116
+ it "should pass the value through unchanged" do
117
+ expect(described_class.to_direction({})).to eq({})
118
+ expect(described_class.to_direction(scope: { "$meta" => "textScore" }))
119
+ .to eq(scope: { "$meta" => "textScore" })
120
+ expect(described_class.to_direction(a: 1, b: 2)).to eq(a: 1, b: 2)
121
+ end
122
+ end
123
+
124
+ context "when the value is an unrecognized type" do
125
+ it "should raise ArgumentError" do
126
+ expect { described_class.to_direction([]) }.to raise_error(ArgumentError)
127
+ expect { described_class.to_direction(/a/) }.to raise_error(ArgumentError)
128
+ expect { described_class.to_direction(Object.new) }.to raise_error(ArgumentError)
129
+ end
130
+ end
131
+ end
132
+ end
@@ -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
@@ -12,13 +12,13 @@ describe Mongoid::Errors::ReadonlyDocument do
12
12
 
13
13
  it "contains the problem in the message" do
14
14
  expect(error.message).to include(
15
- "Attempted to persist the readonly document 'Band'."
15
+ "Attempted to persist a readonly document of class 'Band'."
16
16
  )
17
17
  end
18
18
 
19
19
  it "contains the summary in the message" do
20
20
  expect(error.message).to include(
21
- "Documents loaded from the database using #only"
21
+ "Documents that are marked readonly cannot be persisted"
22
22
  )
23
23
  end
24
24