mongoid 7.1.0 → 7.1.6
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.tar.gz.sig +0 -0
- data/CHANGELOG.md +6 -6
- data/README.md +1 -1
- data/Rakefile +14 -5
- data/lib/config/locales/en.yml +5 -5
- data/lib/mongoid/association/accessors.rb +37 -2
- data/lib/mongoid/association/embedded/embeds_many.rb +2 -1
- data/lib/mongoid/association/embedded/embeds_one.rb +2 -1
- data/lib/mongoid/association/proxy.rb +1 -1
- data/lib/mongoid/association/referenced/belongs_to/binding.rb +1 -1
- data/lib/mongoid/association/referenced/belongs_to/eager.rb +38 -2
- data/lib/mongoid/association/referenced/eager.rb +29 -9
- data/lib/mongoid/association/referenced/has_one/proxy.rb +6 -1
- data/lib/mongoid/atomic.rb +13 -3
- data/lib/mongoid/clients/factory.rb +2 -2
- data/lib/mongoid/clients/options.rb +8 -8
- data/lib/mongoid/clients/sessions.rb +20 -4
- data/lib/mongoid/clients/storage_options.rb +5 -5
- data/lib/mongoid/config.rb +39 -9
- data/lib/mongoid/criteria.rb +23 -4
- data/lib/mongoid/criteria/modifiable.rb +2 -1
- data/lib/mongoid/criteria/queryable/extensions/numeric.rb +1 -1
- data/lib/mongoid/criteria/queryable/extensions/regexp.rb +6 -6
- data/lib/mongoid/criteria/queryable/extensions/time_with_zone.rb +12 -0
- data/lib/mongoid/criteria/queryable/mergeable.rb +75 -8
- data/lib/mongoid/criteria/queryable/pipeline.rb +3 -2
- data/lib/mongoid/criteria/queryable/selectable.rb +120 -13
- data/lib/mongoid/criteria/queryable/storable.rb +104 -99
- data/lib/mongoid/errors/eager_load.rb +2 -0
- data/lib/mongoid/errors/no_client_config.rb +2 -2
- data/lib/mongoid/errors/no_default_client.rb +1 -1
- data/lib/mongoid/extensions/hash.rb +4 -2
- data/lib/mongoid/extensions/regexp.rb +1 -1
- data/lib/mongoid/fields.rb +2 -1
- data/lib/mongoid/fields/validators/macro.rb +4 -1
- data/lib/mongoid/matchable/regexp.rb +2 -2
- data/lib/mongoid/persistable/pushable.rb +11 -2
- data/lib/mongoid/persistence_context.rb +6 -6
- data/lib/mongoid/query_cache.rb +61 -18
- data/lib/mongoid/serializable.rb +9 -3
- data/lib/mongoid/tasks/database.rb +38 -3
- data/lib/mongoid/validatable/uniqueness.rb +1 -1
- data/lib/mongoid/version.rb +1 -1
- data/lib/rails/generators/mongoid/config/templates/mongoid.yml +32 -23
- data/lib/rails/generators/mongoid/model/templates/model.rb.tt +1 -1
- data/spec/app/models/coding.rb +4 -0
- data/spec/app/models/coding/pull_request.rb +12 -0
- data/spec/app/models/delegating_patient.rb +16 -0
- data/spec/app/models/passport.rb +1 -0
- data/spec/app/models/person.rb +2 -0
- data/spec/app/models/phone.rb +1 -0
- data/spec/app/models/publication.rb +5 -0
- data/spec/app/models/publication/encyclopedia.rb +12 -0
- data/spec/app/models/publication/review.rb +14 -0
- data/spec/app/models/series.rb +1 -0
- data/spec/app/models/wiki_page.rb +1 -0
- data/spec/integration/app_spec.rb +254 -0
- data/spec/integration/associations/embedded_spec.rb +54 -0
- data/spec/integration/associations/embeds_many_spec.rb +24 -0
- data/spec/integration/associations/embeds_one_spec.rb +24 -0
- data/spec/integration/associations/has_many_spec.rb +76 -0
- data/spec/integration/associations/has_one_spec.rb +76 -0
- data/spec/integration/bson_regexp_raw_spec.rb +20 -0
- data/spec/integration/criteria/date_field_spec.rb +41 -0
- data/spec/integration/criteria/logical_spec.rb +13 -0
- data/spec/integration/document_spec.rb +22 -0
- data/spec/integration/shardable_spec.rb +20 -4
- data/spec/lite_spec_helper.rb +12 -4
- data/spec/mongoid/association/accessors_spec.rb +238 -63
- data/spec/mongoid/association/embedded/embeds_many_models.rb +19 -0
- data/spec/mongoid/association/embedded/embeds_many_spec.rb +10 -0
- data/spec/mongoid/association/embedded/embeds_one_spec.rb +0 -2
- data/spec/mongoid/association/referenced/belongs_to/eager_spec.rb +193 -10
- data/spec/mongoid/association/referenced/has_and_belongs_to_many/proxy_spec.rb +140 -1
- data/spec/mongoid/association/referenced/has_many/enumerable_spec.rb +105 -0
- data/spec/mongoid/association/referenced/has_many/proxy_spec.rb +2 -1
- data/spec/mongoid/clients/factory_spec.rb +8 -8
- data/spec/mongoid/clients/options_spec.rb +11 -11
- data/spec/mongoid/clients/sessions_spec.rb +8 -4
- data/spec/mongoid/clients/transactions_spec.rb +20 -8
- data/spec/mongoid/clients_spec.rb +2 -2
- data/spec/mongoid/contextual/atomic_spec.rb +22 -11
- data/spec/mongoid/contextual/geo_near_spec.rb +11 -2
- data/spec/mongoid/contextual/map_reduce_spec.rb +20 -5
- data/spec/mongoid/contextual/mongo_spec.rb +76 -53
- data/spec/mongoid/criteria/queryable/extensions/regexp_raw_spec.rb +1 -1
- data/spec/mongoid/criteria/queryable/extensions/regexp_spec.rb +7 -7
- data/spec/mongoid/criteria/queryable/extensions/string_spec.rb +1 -1
- data/spec/mongoid/criteria/queryable/extensions/time_spec.rb +19 -7
- data/spec/mongoid/criteria/queryable/extensions/time_with_zone_spec.rb +28 -1
- data/spec/mongoid/criteria/queryable/mergeable_spec.rb +45 -12
- data/spec/mongoid/criteria/queryable/selectable_logical_spec.rb +1051 -392
- data/spec/mongoid/criteria/queryable/selectable_spec.rb +52 -0
- data/spec/mongoid/criteria/queryable/storable_spec.rb +80 -2
- data/spec/mongoid/criteria_spec.rb +36 -2
- data/spec/mongoid/document_persistence_context_spec.rb +33 -0
- data/spec/mongoid/errors/no_client_config_spec.rb +2 -2
- data/spec/mongoid/errors/no_client_database_spec.rb +3 -3
- data/spec/mongoid/errors/no_client_hosts_spec.rb +3 -3
- data/spec/mongoid/fields_spec.rb +24 -1
- data/spec/mongoid/indexable_spec.rb +6 -4
- data/spec/mongoid/matchable/default_spec.rb +1 -1
- data/spec/mongoid/matchable/regexp_spec.rb +2 -2
- data/spec/mongoid/matchable_spec.rb +2 -2
- data/spec/mongoid/persistable/pushable_spec.rb +55 -1
- data/spec/mongoid/query_cache_spec.rb +77 -9
- data/spec/mongoid/relations/proxy_spec.rb +1 -1
- data/spec/mongoid/scopable_spec.rb +2 -1
- data/spec/mongoid/serializable_spec.rb +129 -18
- data/spec/mongoid/shardable_models.rb +1 -1
- data/spec/mongoid/shardable_spec.rb +2 -2
- data/spec/mongoid/tasks/database_rake_spec.rb +13 -13
- data/spec/mongoid/tasks/database_spec.rb +1 -1
- data/spec/shared/LICENSE +20 -0
- data/spec/shared/lib/mrss/child_process_helper.rb +80 -0
- data/spec/shared/lib/mrss/cluster_config.rb +211 -0
- data/spec/shared/lib/mrss/constraints.rb +312 -0
- data/spec/shared/lib/mrss/lite_constraints.rb +175 -0
- data/spec/shared/lib/mrss/spec_organizer.rb +149 -0
- data/spec/spec_helper.rb +2 -31
- data/spec/support/child_process_helper.rb +76 -0
- data/spec/support/cluster_config.rb +3 -3
- data/spec/support/constraints.rb +26 -10
- data/spec/support/expectations.rb +3 -1
- data/spec/support/helpers.rb +11 -0
- data/spec/support/session_registry.rb +50 -0
- data/spec/support/spec_config.rb +12 -4
- metadata +520 -473
- metadata.gz.sig +0 -0
|
@@ -32,20 +32,20 @@ module Mongoid
|
|
|
32
32
|
# @example Store this model by default in a different client.
|
|
33
33
|
# class Band
|
|
34
34
|
# include Mongoid::Document
|
|
35
|
-
# store_in client: "
|
|
35
|
+
# store_in client: "analytics"
|
|
36
36
|
# end
|
|
37
37
|
#
|
|
38
38
|
# @example Store this model with a combination of options.
|
|
39
39
|
# class Band
|
|
40
40
|
# include Mongoid::Document
|
|
41
|
-
# store_in collection: "artists", database: "
|
|
41
|
+
# store_in collection: "artists", database: "music"
|
|
42
42
|
# end
|
|
43
43
|
#
|
|
44
44
|
# @param [ Hash ] options The storage options.
|
|
45
45
|
#
|
|
46
|
-
# @option options [ String
|
|
47
|
-
# @option options [ String
|
|
48
|
-
# @option options [ String
|
|
46
|
+
# @option options [ String | Symbol ] :collection The collection name.
|
|
47
|
+
# @option options [ String | Symbol ] :database The database name.
|
|
48
|
+
# @option options [ String | Symbol ] :client The client name.
|
|
49
49
|
#
|
|
50
50
|
# @return [ Class ] The model class.
|
|
51
51
|
#
|
data/lib/mongoid/config.rb
CHANGED
|
@@ -18,14 +18,31 @@ module Mongoid
|
|
|
18
18
|
|
|
19
19
|
LOCK = Mutex.new
|
|
20
20
|
|
|
21
|
+
# Application name that is printed to the mongodb logs upon establishing
|
|
22
|
+
# a connection in server versions >= 3.4. Note that the name cannot
|
|
23
|
+
# exceed 128 bytes. It is also used as the database name if the
|
|
24
|
+
# database name is not explicitly defined.
|
|
25
|
+
option :app_name, default: nil
|
|
26
|
+
|
|
27
|
+
# Create indexes in background by default.
|
|
28
|
+
option :background_indexing, default: false
|
|
29
|
+
|
|
30
|
+
# Mark belongs_to associations as required by default, so that saving a
|
|
31
|
+
# model with a missing belongs_to association will trigger a validation
|
|
32
|
+
# error.
|
|
33
|
+
option :belongs_to_required_by_default, default: true
|
|
34
|
+
|
|
35
|
+
# Raise an exception when a field is redefined.
|
|
36
|
+
option :duplicate_fields_exception, default: false
|
|
37
|
+
|
|
38
|
+
# Include the root model name in json serialization.
|
|
21
39
|
option :include_root_in_json, default: false
|
|
40
|
+
|
|
41
|
+
# # Include the _type field in serialization.
|
|
22
42
|
option :include_type_for_serialization, default: false
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
option :duplicate_fields_exception, default: false
|
|
27
|
-
option :use_activesupport_time_zone, default: true
|
|
28
|
-
option :use_utc, default: false
|
|
43
|
+
|
|
44
|
+
# Whether to join nested persistence contexts for atomic operations
|
|
45
|
+
# to parent contexts by default.
|
|
29
46
|
option :join_contexts, default: false
|
|
30
47
|
|
|
31
48
|
# The log level.
|
|
@@ -38,9 +55,22 @@ module Mongoid
|
|
|
38
55
|
# configuration file is the log level given by this option honored.
|
|
39
56
|
option :log_level, default: :info
|
|
40
57
|
|
|
41
|
-
|
|
42
|
-
option :
|
|
43
|
-
|
|
58
|
+
# Preload all models in development, needed when models use inheritance.
|
|
59
|
+
option :preload_models, default: false
|
|
60
|
+
|
|
61
|
+
# Raise an error when performing a #find and the document is not found.
|
|
62
|
+
option :raise_not_found_error, default: true
|
|
63
|
+
|
|
64
|
+
# Raise an error when defining a scope with the same name as an
|
|
65
|
+
# existing method.
|
|
66
|
+
option :scope_overwrite_exception, default: false
|
|
67
|
+
|
|
68
|
+
# Use ActiveSupport's time zone in time operations instead of the
|
|
69
|
+
# Ruby default time zone.
|
|
70
|
+
option :use_activesupport_time_zone, default: true
|
|
71
|
+
|
|
72
|
+
# Return stored times as UTC.
|
|
73
|
+
option :use_utc, default: false
|
|
44
74
|
|
|
45
75
|
# Has Mongoid been configured? This is checking that at least a valid
|
|
46
76
|
# client config exists.
|
data/lib/mongoid/criteria.rb
CHANGED
|
@@ -400,9 +400,22 @@ module Mongoid
|
|
|
400
400
|
# @return [ Criteria ] The cloned selectable.
|
|
401
401
|
#
|
|
402
402
|
# @since 1.0.0
|
|
403
|
-
def where(
|
|
404
|
-
|
|
405
|
-
|
|
403
|
+
def where(*args)
|
|
404
|
+
# Historically this method required exactly one argument.
|
|
405
|
+
# As of https://jira.mongodb.org/browse/MONGOID-4804 it also accepts
|
|
406
|
+
# zero arguments.
|
|
407
|
+
# The underlying where implemetation that super invokes supports
|
|
408
|
+
# any number of arguments, but we don't presently allow mutiple
|
|
409
|
+
# arguments through this method. This API can be reconsidered in the
|
|
410
|
+
# future.
|
|
411
|
+
if args.length > 1
|
|
412
|
+
raise ArgumentError, "Criteria#where requires zero or one arguments (given #{args.length})"
|
|
413
|
+
end
|
|
414
|
+
if args.length == 1
|
|
415
|
+
expression = args.first
|
|
416
|
+
if expression.is_a?(::String) && embedded?
|
|
417
|
+
raise Errors::UnsupportedJavascript.new(klass, expression)
|
|
418
|
+
end
|
|
406
419
|
end
|
|
407
420
|
super
|
|
408
421
|
end
|
|
@@ -437,7 +450,13 @@ module Mongoid
|
|
|
437
450
|
#
|
|
438
451
|
# @since 3.1.0
|
|
439
452
|
def for_js(javascript, scope = {})
|
|
440
|
-
|
|
453
|
+
code = if scope.empty?
|
|
454
|
+
# CodeWithScope is not supported for $where as of MongoDB 4.4
|
|
455
|
+
BSON::Code.new(javascript)
|
|
456
|
+
else
|
|
457
|
+
BSON::CodeWithScope.new(javascript, scope)
|
|
458
|
+
end
|
|
459
|
+
js_query(code)
|
|
441
460
|
end
|
|
442
461
|
|
|
443
462
|
private
|
|
@@ -60,7 +60,7 @@ module Mongoid
|
|
|
60
60
|
#
|
|
61
61
|
# @since 1.0.0
|
|
62
62
|
def __numeric__(object)
|
|
63
|
-
object.to_s =~ /(
|
|
63
|
+
object.to_s =~ /(\A[-+]?[0-9]+\z)|(\.0+\z)|(\.\z)/ ? object.to_i : Float(object)
|
|
64
64
|
end
|
|
65
65
|
|
|
66
66
|
# Evolve the object to an integer.
|
|
@@ -12,7 +12,7 @@ module Mongoid
|
|
|
12
12
|
# Is the object a regexp?
|
|
13
13
|
#
|
|
14
14
|
# @example Is the object a regex?
|
|
15
|
-
#
|
|
15
|
+
# /\A[123]/.regexp?
|
|
16
16
|
#
|
|
17
17
|
# @return [ true ] Always true.
|
|
18
18
|
#
|
|
@@ -24,7 +24,7 @@ module Mongoid
|
|
|
24
24
|
# Evolve the object into a regex.
|
|
25
25
|
#
|
|
26
26
|
# @example Evolve the object to a regex.
|
|
27
|
-
# Regexp.evolve("
|
|
27
|
+
# Regexp.evolve("\A[123]")
|
|
28
28
|
#
|
|
29
29
|
# @param [ Regexp, String ] object The object to evolve.
|
|
30
30
|
#
|
|
@@ -38,7 +38,7 @@ module Mongoid
|
|
|
38
38
|
end
|
|
39
39
|
end
|
|
40
40
|
|
|
41
|
-
module
|
|
41
|
+
module Raw_
|
|
42
42
|
|
|
43
43
|
# Is the object a regexp?
|
|
44
44
|
#
|
|
@@ -55,7 +55,7 @@ module Mongoid
|
|
|
55
55
|
# Evolve the object into a raw bson regex.
|
|
56
56
|
#
|
|
57
57
|
# @example Evolve the object to a regex.
|
|
58
|
-
# BSON::Regexp::Raw.evolve("
|
|
58
|
+
# BSON::Regexp::Raw.evolve("\\A[123]")
|
|
59
59
|
#
|
|
60
60
|
# @param [ BSON::Regexp::Raw, String ] object The object to evolve.
|
|
61
61
|
#
|
|
@@ -77,5 +77,5 @@ end
|
|
|
77
77
|
|
|
78
78
|
::Regexp.__send__(:include,Mongoid::Criteria::Queryable::Extensions::Regexp)
|
|
79
79
|
::Regexp.__send__(:extend, Mongoid::Criteria::Queryable::Extensions::Regexp::ClassMethods)
|
|
80
|
-
BSON::Regexp::Raw.__send__(:include,Mongoid::Criteria::Queryable::Extensions::Regexp::
|
|
81
|
-
BSON::Regexp::Raw.__send__(:extend, Mongoid::Criteria::Queryable::Extensions::Regexp::
|
|
80
|
+
BSON::Regexp::Raw.__send__(:include,Mongoid::Criteria::Queryable::Extensions::Regexp::Raw_)
|
|
81
|
+
BSON::Regexp::Raw.__send__(:extend, Mongoid::Criteria::Queryable::Extensions::Regexp::Raw_::ClassMethods)
|
|
@@ -9,6 +9,18 @@ module Mongoid
|
|
|
9
9
|
# This module contains additional time with zone behavior.
|
|
10
10
|
module TimeWithZone
|
|
11
11
|
|
|
12
|
+
# Evolve the time as a date, UTC midnight.
|
|
13
|
+
#
|
|
14
|
+
# @example Evolve the time to a date query format.
|
|
15
|
+
# time.__evolve_date__
|
|
16
|
+
#
|
|
17
|
+
# @return [ Time ] The date at midnight UTC.
|
|
18
|
+
#
|
|
19
|
+
# @since 1.0.0
|
|
20
|
+
def __evolve_date__
|
|
21
|
+
::Time.utc(year, month, day, 0, 0, 0, 0)
|
|
22
|
+
end
|
|
23
|
+
|
|
12
24
|
# Evolve the time into a utc time.
|
|
13
25
|
#
|
|
14
26
|
# @example Evolve the time.
|
|
@@ -163,7 +163,7 @@ module Mongoid
|
|
|
163
163
|
if expr.is_a?(Selectable)
|
|
164
164
|
expr = expr.selector
|
|
165
165
|
end
|
|
166
|
-
normalized =
|
|
166
|
+
normalized = _mongoid_expand_keys(expr)
|
|
167
167
|
sel.store(operator, result_criteria.push(normalized))
|
|
168
168
|
end
|
|
169
169
|
end
|
|
@@ -190,9 +190,9 @@ module Mongoid
|
|
|
190
190
|
sel = query.selector
|
|
191
191
|
_mongoid_flatten_arrays(criteria).each do |criterion|
|
|
192
192
|
if criterion.is_a?(Selectable)
|
|
193
|
-
expr =
|
|
193
|
+
expr = _mongoid_expand_keys(criterion.selector)
|
|
194
194
|
else
|
|
195
|
-
expr = criterion
|
|
195
|
+
expr = _mongoid_expand_keys(criterion)
|
|
196
196
|
end
|
|
197
197
|
if sel.empty?
|
|
198
198
|
sel.store(operator, [expr])
|
|
@@ -212,7 +212,7 @@ module Mongoid
|
|
|
212
212
|
# explicitly only expands Array objects and Array subclasses.
|
|
213
213
|
private def _mongoid_flatten_arrays(array)
|
|
214
214
|
out = []
|
|
215
|
-
pending = array
|
|
215
|
+
pending = array.dup
|
|
216
216
|
until pending.empty?
|
|
217
217
|
item = pending.shift
|
|
218
218
|
if item.nil?
|
|
@@ -226,11 +226,78 @@ module Mongoid
|
|
|
226
226
|
out
|
|
227
227
|
end
|
|
228
228
|
|
|
229
|
-
#
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
229
|
+
# Takes a criteria hash and expands Key objects into hashes containing
|
|
230
|
+
# MQL corresponding to said key objects.
|
|
231
|
+
#
|
|
232
|
+
# Ruby does not permit multiple symbol operators. For example,
|
|
233
|
+
# {:foo.gt => 1, :foo.gt => 2} is collapsed to {:foo.gt => 2} by the
|
|
234
|
+
# language. Therefore this method never has to deal with multiple
|
|
235
|
+
# identical operators.
|
|
236
|
+
#
|
|
237
|
+
# Similarly, this method should never need to expand a literal value
|
|
238
|
+
# and an operator at the same time.
|
|
239
|
+
#
|
|
240
|
+
# @param [ Hash ] Criteria including Key instances.
|
|
241
|
+
#
|
|
242
|
+
# @return [ Hash ] Expanded criteria.
|
|
243
|
+
private def _mongoid_expand_keys(expr)
|
|
244
|
+
unless expr.is_a?(Hash)
|
|
245
|
+
raise ArgumentError, 'Argument must be a Hash'
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
result = {}
|
|
249
|
+
expr.each do |field, value|
|
|
250
|
+
field.__expr_part__(value.__expand_complex__).each do |k, v|
|
|
251
|
+
if result[k]
|
|
252
|
+
if result[k].is_a?(Hash)
|
|
253
|
+
# Existing value is an operator.
|
|
254
|
+
# If new value is also an operator, ensure there are no
|
|
255
|
+
# conflicts and add
|
|
256
|
+
if v.is_a?(Hash)
|
|
257
|
+
# The new value is also an operator.
|
|
258
|
+
# If there are no conflicts, combine the hashes, otherwise
|
|
259
|
+
# add new conditions to top level with $and.
|
|
260
|
+
if (v.keys & result[k].keys).empty?
|
|
261
|
+
result[k].update(v)
|
|
262
|
+
else
|
|
263
|
+
raise NotImplementedError, 'Ruby does not allow same symbol operator with different values'
|
|
264
|
+
result['$and'] ||= []
|
|
265
|
+
result['$and'] << {k => v}
|
|
266
|
+
end
|
|
267
|
+
else
|
|
268
|
+
# The new value is a simple value.
|
|
269
|
+
# If there isn't an $eq operator already in the query,
|
|
270
|
+
# transform the new value into an $eq operator and add it
|
|
271
|
+
# to the existing hash. Otherwise add the new condition
|
|
272
|
+
# with $and to the top level.
|
|
273
|
+
if result[k].key?('$eq')
|
|
274
|
+
raise NotImplementedError, 'Ruby does not allow same symbol operator with different values'
|
|
275
|
+
result['$and'] ||= []
|
|
276
|
+
result['$and'] << {k => v}
|
|
277
|
+
else
|
|
278
|
+
result[k].update('$eq' => v)
|
|
279
|
+
end
|
|
280
|
+
end
|
|
281
|
+
else
|
|
282
|
+
# Existing value is a simple value.
|
|
283
|
+
# If we are adding an operator, and the operator is not $eq,
|
|
284
|
+
# convert existing value into $eq and add the new operator
|
|
285
|
+
# to the same hash. Otherwise add the new condition with $and
|
|
286
|
+
# to the top level.
|
|
287
|
+
if v.is_a?(Hash) && !v.key?('$eq')
|
|
288
|
+
result[k] = {'$eq' => result[k]}.update(v)
|
|
289
|
+
else
|
|
290
|
+
raise NotImplementedError, 'Ruby does not allow same symbol operator with different values'
|
|
291
|
+
result['$and'] ||= []
|
|
292
|
+
result['$and'] << {k => v}
|
|
293
|
+
end
|
|
294
|
+
end
|
|
295
|
+
else
|
|
296
|
+
result[k] = v
|
|
297
|
+
end
|
|
298
|
+
end
|
|
233
299
|
end
|
|
300
|
+
result
|
|
234
301
|
end
|
|
235
302
|
|
|
236
303
|
# Adds the criterion to the existing selection.
|
|
@@ -33,7 +33,7 @@ module Mongoid
|
|
|
33
33
|
# Add a group operation to the aggregation pipeline.
|
|
34
34
|
#
|
|
35
35
|
# @example Add a group operation.
|
|
36
|
-
# pipeline.group(:count.sum => 1, :max.max => "likes")
|
|
36
|
+
# pipeline.group(:_id => "foo", :count.sum => 1, :max.max => "likes")
|
|
37
37
|
#
|
|
38
38
|
# @param [ Hash ] entry The group entry.
|
|
39
39
|
#
|
|
@@ -76,7 +76,8 @@ module Mongoid
|
|
|
76
76
|
# pipeline.unwind(:field)
|
|
77
77
|
# pipeline.unwind(document)
|
|
78
78
|
#
|
|
79
|
-
# @param [ String, Symbol, Hash ] field_or_doc
|
|
79
|
+
# @param [ String, Symbol, Hash ] field_or_doc A field name or a
|
|
80
|
+
# document.
|
|
80
81
|
#
|
|
81
82
|
# @return [ Pipeline ] The pipeline.
|
|
82
83
|
#
|
|
@@ -89,11 +89,27 @@ module Mongoid
|
|
|
89
89
|
if new_s.is_a?(Selectable)
|
|
90
90
|
new_s = new_s.selector
|
|
91
91
|
end
|
|
92
|
-
normalized =
|
|
92
|
+
normalized = _mongoid_expand_keys(new_s)
|
|
93
93
|
normalized.each do |k, v|
|
|
94
94
|
k = k.to_s
|
|
95
|
-
if c.selector[k]
|
|
96
|
-
|
|
95
|
+
if c.selector[k]
|
|
96
|
+
# There is already a condition on k.
|
|
97
|
+
# If v is an operator, and all existing conditions are
|
|
98
|
+
# also operators, and v isn't present in existing conditions,
|
|
99
|
+
# we can add to existing conditions.
|
|
100
|
+
# Otherwise use $and.
|
|
101
|
+
if v.is_a?(Hash) &&
|
|
102
|
+
v.length == 1 &&
|
|
103
|
+
(new_k = v.keys.first).start_with?('$') &&
|
|
104
|
+
(existing_kv = c.selector[k]).is_a?(Hash) &&
|
|
105
|
+
!existing_kv.key?(new_k) &&
|
|
106
|
+
existing_kv.keys.all? { |sub_k| sub_k.start_with?('$') }
|
|
107
|
+
then
|
|
108
|
+
merged_v = c.selector[k].merge(v)
|
|
109
|
+
c.selector.store(k, merged_v)
|
|
110
|
+
else
|
|
111
|
+
c = c.send(:__multi__, [k => v], '$and')
|
|
112
|
+
end
|
|
97
113
|
else
|
|
98
114
|
c.selector.store(k, v)
|
|
99
115
|
end
|
|
@@ -567,17 +583,21 @@ module Mongoid
|
|
|
567
583
|
if new_s.is_a?(Selectable)
|
|
568
584
|
new_s = new_s.selector
|
|
569
585
|
end
|
|
570
|
-
new_s.each do |k, v|
|
|
586
|
+
_mongoid_expand_keys(new_s).each do |k, v|
|
|
571
587
|
k = k.to_s
|
|
572
588
|
if c.selector[k] || k[0] == ?$
|
|
573
589
|
c = c.send(:__multi__, [{'$nor' => [{k => v}]}], '$and')
|
|
574
590
|
else
|
|
575
|
-
if v.is_a?(
|
|
576
|
-
|
|
591
|
+
if v.is_a?(Hash)
|
|
592
|
+
c = c.send(:__multi__, [{'$nor' => [{k => v}]}], '$and')
|
|
577
593
|
else
|
|
578
|
-
|
|
594
|
+
if v.is_a?(Regexp)
|
|
595
|
+
negated_operator = '$not'
|
|
596
|
+
else
|
|
597
|
+
negated_operator = '$ne'
|
|
598
|
+
end
|
|
599
|
+
c = c.send(:__override__, {k => v}, negated_operator)
|
|
579
600
|
end
|
|
580
|
-
c = c.send(:__override__, {k => v}, negated_operator)
|
|
581
601
|
end
|
|
582
602
|
end
|
|
583
603
|
c
|
|
@@ -586,13 +606,34 @@ module Mongoid
|
|
|
586
606
|
end
|
|
587
607
|
key :not, :override, "$not"
|
|
588
608
|
|
|
589
|
-
#
|
|
609
|
+
# Creates a disjunction using $or from the existing criteria in the
|
|
610
|
+
# receiver and the provided arguments.
|
|
611
|
+
#
|
|
612
|
+
# This behavior (receiver becoming one of the disjunction operands)
|
|
613
|
+
# matches ActiveRecord's +or+ behavior.
|
|
614
|
+
#
|
|
615
|
+
# Use +any_of+ to add a disjunction of the arguments as an additional
|
|
616
|
+
# constraint to the criteria already existing in the receiver.
|
|
617
|
+
#
|
|
618
|
+
# Each argument can be a Hash, a Criteria object, an array of
|
|
619
|
+
# Hash or Criteria objects, or a nested array. Nested arrays will be
|
|
620
|
+
# flattened and can be of any depth. Passing arrays is deprecated.
|
|
590
621
|
#
|
|
591
|
-
# @example Add the $or selection.
|
|
622
|
+
# @example Add the $or selection where both fields must have the specified values.
|
|
592
623
|
# selectable.or(field: 1, field: 2)
|
|
593
624
|
#
|
|
594
|
-
# @
|
|
595
|
-
#
|
|
625
|
+
# @example Add the $or selection where either value match is sufficient.
|
|
626
|
+
# selectable.or({field: 1}, {field: 2})
|
|
627
|
+
#
|
|
628
|
+
# @example Same as previous example but using the deprecated array wrap.
|
|
629
|
+
# selectable.or([{field: 1}, {field: 2}])
|
|
630
|
+
#
|
|
631
|
+
# @example Same as previous example, also deprecated.
|
|
632
|
+
# selectable.or([{field: 1}], [{field: 2}])
|
|
633
|
+
#
|
|
634
|
+
# @param [ Hash | Criteria | Array<Hash | Criteria>, ... ] criteria
|
|
635
|
+
# Multiple key/value pair matches or Criteria objects, or arrays
|
|
636
|
+
# thereof. Passing arrays is deprecated.
|
|
596
637
|
#
|
|
597
638
|
# @return [ Selectable ] The new selectable.
|
|
598
639
|
#
|
|
@@ -600,7 +641,73 @@ module Mongoid
|
|
|
600
641
|
def or(*criteria)
|
|
601
642
|
_mongoid_add_top_level_operation('$or', criteria)
|
|
602
643
|
end
|
|
603
|
-
|
|
644
|
+
|
|
645
|
+
# Adds a disjunction of the arguments as an additional constraint
|
|
646
|
+
# to the criteria already existing in the receiver.
|
|
647
|
+
#
|
|
648
|
+
# Use +or+ to make the receiver one of the disjunction operands.
|
|
649
|
+
#
|
|
650
|
+
# Each argument can be a Hash, a Criteria object, an array of
|
|
651
|
+
# Hash or Criteria objects, or a nested array. Nested arrays will be
|
|
652
|
+
# flattened and can be of any depth. Passing arrays is deprecated.
|
|
653
|
+
#
|
|
654
|
+
# @example Add the $or selection where both fields must have the specified values.
|
|
655
|
+
# selectable.any_of(field: 1, field: 2)
|
|
656
|
+
#
|
|
657
|
+
# @example Add the $or selection where either value match is sufficient.
|
|
658
|
+
# selectable.any_of({field: 1}, {field: 2})
|
|
659
|
+
#
|
|
660
|
+
# @example Same as previous example but using the deprecated array wrap.
|
|
661
|
+
# selectable.any_of([{field: 1}, {field: 2}])
|
|
662
|
+
#
|
|
663
|
+
# @example Same as previous example, also deprecated.
|
|
664
|
+
# selectable.any_of([{field: 1}], [{field: 2}])
|
|
665
|
+
#
|
|
666
|
+
# @param [ Hash | Criteria | Array<Hash | Criteria>, ... ] criteria
|
|
667
|
+
# Multiple key/value pair matches or Criteria objects, or arrays
|
|
668
|
+
# thereof. Passing arrays is deprecated.
|
|
669
|
+
#
|
|
670
|
+
# @return [ Selectable ] The new selectable.
|
|
671
|
+
#
|
|
672
|
+
# @since 1.0.0
|
|
673
|
+
def any_of(*criteria)
|
|
674
|
+
criteria = _mongoid_flatten_arrays(criteria)
|
|
675
|
+
case criteria.length
|
|
676
|
+
when 0
|
|
677
|
+
clone
|
|
678
|
+
when 1
|
|
679
|
+
# When we have a single criteria, any_of behaves like and.
|
|
680
|
+
# Note: criteria can be a Query object, which #where method does
|
|
681
|
+
# not support.
|
|
682
|
+
self.and(*criteria)
|
|
683
|
+
else
|
|
684
|
+
# When we have multiple criteria, combine them all with $or
|
|
685
|
+
# and add the result to self.
|
|
686
|
+
exprs = criteria.map do |criterion|
|
|
687
|
+
if criterion.is_a?(Selectable)
|
|
688
|
+
_mongoid_expand_keys(criterion.selector)
|
|
689
|
+
else
|
|
690
|
+
Hash[criterion.map do |k, v|
|
|
691
|
+
if k.is_a?(Symbol)
|
|
692
|
+
[k.to_s, v]
|
|
693
|
+
else
|
|
694
|
+
[k, v]
|
|
695
|
+
end
|
|
696
|
+
end]
|
|
697
|
+
end
|
|
698
|
+
end
|
|
699
|
+
# Should be able to do:
|
|
700
|
+
#where('$or' => exprs)
|
|
701
|
+
# But since that is broken do instead:
|
|
702
|
+
clone.tap do |query|
|
|
703
|
+
if query.selector['$or']
|
|
704
|
+
query.selector.store('$or', query.selector['$or'] + exprs)
|
|
705
|
+
else
|
|
706
|
+
query.selector.store('$or', exprs)
|
|
707
|
+
end
|
|
708
|
+
end
|
|
709
|
+
end
|
|
710
|
+
end
|
|
604
711
|
|
|
605
712
|
# Add a $size selection for array fields.
|
|
606
713
|
#
|