mongoid 8.0.3 → 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.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/CHANGELOG.md +3 -3
- data/README.md +3 -3
- data/lib/config/locales/en.yml +46 -14
- data/lib/mongoid/association/accessors.rb +2 -2
- data/lib/mongoid/association/builders.rb +1 -1
- data/lib/mongoid/association/embedded/batchable.rb +2 -2
- data/lib/mongoid/association/embedded/embedded_in/buildable.rb +2 -2
- data/lib/mongoid/association/embedded/embedded_in/proxy.rb +2 -1
- data/lib/mongoid/association/embedded/embeds_many/buildable.rb +3 -2
- data/lib/mongoid/association/embedded/embeds_many/proxy.rb +23 -21
- data/lib/mongoid/association/embedded/embeds_one/buildable.rb +1 -1
- data/lib/mongoid/association/embedded/embeds_one/proxy.rb +1 -1
- data/lib/mongoid/association/nested/one.rb +40 -2
- data/lib/mongoid/association/proxy.rb +1 -1
- data/lib/mongoid/association/referenced/counter_cache.rb +2 -2
- data/lib/mongoid/association/referenced/has_and_belongs_to_many/proxy.rb +5 -1
- data/lib/mongoid/association/referenced/has_many/enumerable.rb +2 -2
- data/lib/mongoid/association/referenced/has_many/proxy.rb +7 -3
- data/lib/mongoid/association/reflections.rb +2 -2
- data/lib/mongoid/attributes/dynamic.rb +1 -1
- data/lib/mongoid/attributes/nested.rb +2 -2
- data/lib/mongoid/attributes/projector.rb +1 -1
- data/lib/mongoid/attributes/readonly.rb +1 -1
- data/lib/mongoid/attributes.rb +8 -2
- data/lib/mongoid/changeable.rb +104 -4
- data/lib/mongoid/clients/storage_options.rb +2 -5
- data/lib/mongoid/clients/validators/storage.rb +1 -13
- data/lib/mongoid/collection_configurable.rb +58 -0
- data/lib/mongoid/composable.rb +2 -0
- data/lib/mongoid/config/defaults.rb +60 -0
- data/lib/mongoid/config/validators/async_query_executor.rb +24 -0
- data/lib/mongoid/config/validators.rb +1 -0
- data/lib/mongoid/config.rb +101 -0
- data/lib/mongoid/contextual/atomic.rb +1 -1
- data/lib/mongoid/contextual/memory.rb +233 -33
- data/lib/mongoid/contextual/mongo/documents_loader.rb +177 -0
- data/lib/mongoid/contextual/mongo.rb +373 -113
- data/lib/mongoid/contextual/none.rb +162 -7
- data/lib/mongoid/contextual.rb +12 -0
- data/lib/mongoid/criteria/findable.rb +2 -2
- data/lib/mongoid/criteria/includable.rb +4 -3
- data/lib/mongoid/criteria/queryable/extensions/array.rb +1 -1
- data/lib/mongoid/criteria/queryable/extensions/hash.rb +1 -1
- data/lib/mongoid/criteria/queryable/extensions/numeric.rb +0 -8
- data/lib/mongoid/criteria/queryable/extensions/string.rb +1 -11
- data/lib/mongoid/criteria/queryable/extensions/symbol.rb +0 -10
- data/lib/mongoid/criteria/queryable/key.rb +1 -1
- data/lib/mongoid/criteria/queryable/mergeable.rb +1 -1
- data/lib/mongoid/criteria/queryable/optional.rb +8 -8
- data/lib/mongoid/criteria/queryable/selectable.rb +43 -12
- data/lib/mongoid/criteria/translator.rb +45 -0
- data/lib/mongoid/criteria.rb +7 -5
- data/lib/mongoid/deprecable.rb +1 -1
- data/lib/mongoid/document.rb +50 -13
- data/lib/mongoid/errors/create_collection_failure.rb +33 -0
- data/lib/mongoid/errors/drop_collection_failure.rb +27 -0
- data/lib/mongoid/errors/immutable_attribute.rb +26 -0
- data/lib/mongoid/errors/invalid_async_query_executor.rb +25 -0
- data/lib/mongoid/errors/invalid_global_executor_concurrency.rb +22 -0
- data/lib/mongoid/errors/invalid_storage_parent.rb +2 -0
- data/lib/mongoid/errors.rb +4 -1
- data/lib/mongoid/extensions/object.rb +2 -2
- data/lib/mongoid/extensions/time.rb +2 -0
- data/lib/mongoid/factory.rb +21 -8
- data/lib/mongoid/fields/localized.rb +10 -0
- data/lib/mongoid/fields/standard.rb +10 -0
- data/lib/mongoid/fields.rb +69 -13
- data/lib/mongoid/findable.rb +27 -3
- data/lib/mongoid/interceptable.rb +7 -6
- data/lib/mongoid/matcher/eq_impl.rb +1 -1
- data/lib/mongoid/matcher/type.rb +1 -1
- data/lib/mongoid/matcher.rb +21 -6
- data/lib/mongoid/persistable/creatable.rb +1 -0
- data/lib/mongoid/persistable/deletable.rb +1 -1
- data/lib/mongoid/persistable/savable.rb +13 -1
- data/lib/mongoid/persistable/unsettable.rb +2 -2
- data/lib/mongoid/persistable/updatable.rb +51 -1
- data/lib/mongoid/persistable/upsertable.rb +20 -1
- data/lib/mongoid/persistable.rb +3 -0
- data/lib/mongoid/query_cache.rb +5 -1
- data/lib/mongoid/railties/database.rake +7 -2
- data/lib/mongoid/shardable.rb +35 -11
- data/lib/mongoid/stateful.rb +22 -1
- data/lib/mongoid/tasks/database.rake +12 -0
- data/lib/mongoid/tasks/database.rb +20 -0
- data/lib/mongoid/threaded.rb +30 -0
- data/lib/mongoid/traversable.rb +1 -1
- data/lib/mongoid/utils.rb +22 -0
- data/lib/mongoid/validatable/macros.rb +5 -5
- data/lib/mongoid/validatable.rb +4 -1
- data/lib/mongoid/version.rb +1 -1
- data/lib/mongoid/warnings.rb +17 -1
- data/lib/mongoid.rb +16 -3
- data/spec/integration/app_spec.rb +2 -2
- data/spec/integration/callbacks_models.rb +37 -0
- data/spec/integration/callbacks_spec.rb +134 -0
- data/spec/integration/discriminator_key_spec.rb +4 -5
- data/spec/integration/i18n_fallbacks_spec.rb +3 -2
- data/spec/mongoid/association/embedded/embedded_in/proxy_spec.rb +27 -0
- data/spec/mongoid/association/embedded/embeds_many/proxy_spec.rb +57 -57
- data/spec/mongoid/association/embedded/embeds_many_models.rb +1 -0
- data/spec/mongoid/association/embedded/embeds_one/proxy_spec.rb +15 -2
- data/spec/mongoid/association/referenced/belongs_to_spec.rb +2 -18
- data/spec/mongoid/association/referenced/has_and_belongs_to_many/proxy_spec.rb +148 -224
- data/spec/mongoid/association/referenced/has_many/proxy_spec.rb +111 -164
- data/spec/mongoid/association/syncable_spec.rb +1 -1
- data/spec/mongoid/attributes_spec.rb +5 -8
- data/spec/mongoid/changeable_spec.rb +299 -24
- data/spec/mongoid/clients_spec.rb +122 -13
- data/spec/mongoid/collection_configurable_spec.rb +158 -0
- data/spec/mongoid/config/defaults_spec.rb +160 -0
- data/spec/mongoid/config_spec.rb +154 -18
- data/spec/mongoid/contextual/memory_spec.rb +332 -76
- data/spec/mongoid/contextual/mongo/documents_loader_spec.rb +187 -0
- data/spec/mongoid/contextual/mongo_spec.rb +995 -36
- data/spec/mongoid/contextual/none_spec.rb +49 -2
- data/spec/mongoid/copyable_spec.rb +3 -11
- data/spec/mongoid/criteria/queryable/extensions/string_spec.rb +4 -69
- data/spec/mongoid/criteria/queryable/extensions/symbol_spec.rb +0 -59
- data/spec/mongoid/criteria/queryable/optional_spec.rb +15 -0
- data/spec/mongoid/criteria/queryable/options_spec.rb +1 -1
- data/spec/mongoid/criteria/queryable/selectable_logical_spec.rb +419 -0
- data/spec/mongoid/criteria/queryable/selectable_spec.rb +1 -1
- data/spec/mongoid/criteria/queryable/selector_spec.rb +1 -1
- data/spec/mongoid/criteria/translator_spec.rb +132 -0
- data/spec/mongoid/criteria_projection_spec.rb +1 -4
- data/spec/mongoid/criteria_spec.rb +5 -9
- data/spec/mongoid/errors/readonly_document_spec.rb +2 -2
- data/spec/mongoid/extensions/time_spec.rb +8 -43
- data/spec/mongoid/extensions/time_with_zone_spec.rb +7 -52
- data/spec/mongoid/fields/localized_spec.rb +46 -28
- data/spec/mongoid/fields_spec.rb +136 -34
- data/spec/mongoid/findable_spec.rb +391 -34
- data/spec/mongoid/indexable_spec.rb +16 -10
- data/spec/mongoid/interceptable_spec.rb +15 -3
- data/spec/mongoid/persistable/deletable_spec.rb +26 -6
- data/spec/mongoid/persistable/destroyable_spec.rb +26 -6
- data/spec/mongoid/persistable/incrementable_spec.rb +37 -0
- data/spec/mongoid/persistable/logical_spec.rb +37 -0
- data/spec/mongoid/persistable/poppable_spec.rb +36 -0
- data/spec/mongoid/persistable/pullable_spec.rb +72 -0
- data/spec/mongoid/persistable/pushable_spec.rb +72 -0
- data/spec/mongoid/persistable/renamable_spec.rb +36 -0
- data/spec/mongoid/persistable/savable_spec.rb +96 -0
- data/spec/mongoid/persistable/settable_spec.rb +37 -0
- data/spec/mongoid/persistable/unsettable_spec.rb +36 -0
- data/spec/mongoid/persistable/updatable_spec.rb +20 -28
- data/spec/mongoid/persistable/upsertable_spec.rb +80 -6
- data/spec/mongoid/persistence_context_spec.rb +7 -57
- data/spec/mongoid/query_cache_spec.rb +56 -61
- data/spec/mongoid/reloadable_spec.rb +24 -4
- data/spec/mongoid/scopable_spec.rb +70 -0
- data/spec/mongoid/serializable_spec.rb +9 -30
- data/spec/mongoid/shardable_models.rb +14 -0
- data/spec/mongoid/shardable_spec.rb +153 -61
- data/spec/mongoid/stateful_spec.rb +122 -8
- data/spec/mongoid/tasks/database_rake_spec.rb +74 -0
- data/spec/mongoid/tasks/database_spec.rb +127 -0
- data/spec/mongoid/timestamps_spec.rb +9 -11
- data/spec/mongoid/touchable_spec.rb +277 -5
- data/spec/mongoid/touchable_spec_models.rb +3 -1
- data/spec/mongoid/traversable_spec.rb +9 -24
- data/spec/mongoid/validatable/uniqueness_spec.rb +2 -3
- data/spec/mongoid_spec.rb +35 -9
- data/spec/shared/lib/mrss/docker_runner.rb +7 -0
- data/spec/shared/lib/mrss/event_subscriber.rb +15 -5
- data/spec/shared/lib/mrss/lite_constraints.rb +10 -2
- data/spec/shared/lib/mrss/server_version_registry.rb +16 -23
- data/spec/shared/lib/mrss/utils.rb +28 -6
- data/spec/shared/share/Dockerfile.erb +36 -40
- data/spec/shared/shlib/server.sh +32 -8
- data/spec/shared/shlib/set_env.sh +4 -4
- data/spec/spec_helper.rb +5 -0
- data/spec/support/immutable_ids.rb +118 -0
- data/spec/support/macros.rb +47 -15
- data/spec/support/models/artist.rb +0 -1
- data/spec/support/models/band.rb +1 -0
- data/spec/support/models/book.rb +1 -0
- data/spec/support/models/building.rb +2 -0
- data/spec/support/models/cover.rb +10 -0
- data/spec/support/models/product.rb +1 -0
- data.tar.gz.sig +0 -0
- metadata +700 -656
- metadata.gz.sig +0 -0
- data/spec/mongoid/criteria/queryable/extensions/bignum_spec.rb +0 -60
- 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://
|
|
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
|
-
|
|
2059
|
+
require_fallbacks
|
|
2063
2060
|
|
|
2064
|
-
|
|
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
|
|
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
|
|
21
|
+
"Documents that are marked readonly cannot be persisted"
|
|
22
22
|
)
|
|
23
23
|
end
|
|
24
24
|
|