mongoid 5.4.1 → 6.1.1
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 +5 -5
- data/README.md +3 -3
- data/lib/config/locales/en.yml +19 -0
- data/lib/mongoid.rb +4 -4
- data/lib/mongoid/atomic.rb +2 -2
- data/lib/mongoid/atomic/modifiers.rb +8 -12
- data/lib/mongoid/attributes.rb +22 -21
- data/lib/mongoid/attributes/readonly.rb +22 -0
- data/lib/mongoid/cacheable.rb +36 -0
- data/lib/mongoid/changeable.rb +36 -0
- data/lib/mongoid/clients.rb +8 -63
- data/lib/mongoid/clients/options.rb +55 -250
- data/lib/mongoid/clients/storage_options.rb +1 -69
- data/lib/mongoid/composable.rb +29 -3
- data/lib/mongoid/config.rb +1 -0
- data/lib/mongoid/contextual/atomic.rb +5 -8
- data/lib/mongoid/contextual/map_reduce.rb +0 -4
- data/lib/mongoid/contextual/memory.rb +2 -2
- data/lib/mongoid/contextual/mongo.rb +40 -22
- data/lib/mongoid/contextual/none.rb +12 -0
- data/lib/mongoid/copyable.rb +13 -6
- data/lib/mongoid/criteria.rb +5 -2
- data/lib/mongoid/criteria/marshalable.rb +2 -2
- data/lib/mongoid/criteria/modifiable.rb +17 -1
- data/lib/mongoid/criteria/options.rb +25 -0
- data/lib/mongoid/criteria/queryable.rb +87 -0
- data/lib/mongoid/criteria/queryable/aggregable.rb +120 -0
- data/lib/mongoid/criteria/queryable/extensions.rb +28 -0
- data/lib/mongoid/criteria/queryable/extensions/array.rb +185 -0
- data/lib/mongoid/criteria/queryable/extensions/big_decimal.rb +37 -0
- data/lib/mongoid/criteria/queryable/extensions/boolean.rb +34 -0
- data/lib/mongoid/criteria/queryable/extensions/date.rb +63 -0
- data/lib/mongoid/criteria/queryable/extensions/date_time.rb +53 -0
- data/lib/mongoid/criteria/queryable/extensions/hash.rb +200 -0
- data/lib/mongoid/criteria/queryable/extensions/nil_class.rb +86 -0
- data/lib/mongoid/criteria/queryable/extensions/numeric.rb +90 -0
- data/lib/mongoid/criteria/queryable/extensions/object.rb +206 -0
- data/lib/mongoid/criteria/queryable/extensions/range.rb +70 -0
- data/lib/mongoid/criteria/queryable/extensions/regexp.rb +79 -0
- data/lib/mongoid/criteria/queryable/extensions/set.rb +34 -0
- data/lib/mongoid/criteria/queryable/extensions/string.rb +137 -0
- data/lib/mongoid/criteria/queryable/extensions/symbol.rb +79 -0
- data/lib/mongoid/criteria/queryable/extensions/time.rb +60 -0
- data/lib/mongoid/criteria/queryable/extensions/time_with_zone.rb +54 -0
- data/lib/mongoid/criteria/queryable/forwardable.rb +65 -0
- data/lib/mongoid/criteria/queryable/key.rb +103 -0
- data/lib/mongoid/criteria/queryable/macroable.rb +27 -0
- data/lib/mongoid/criteria/queryable/mergeable.rb +271 -0
- data/lib/mongoid/criteria/queryable/optional.rb +429 -0
- data/lib/mongoid/criteria/queryable/options.rb +153 -0
- data/lib/mongoid/criteria/queryable/pipeline.rb +111 -0
- data/lib/mongoid/criteria/queryable/selectable.rb +662 -0
- data/lib/mongoid/criteria/queryable/selector.rb +212 -0
- data/lib/mongoid/criteria/queryable/smash.rb +104 -0
- data/lib/mongoid/document.rb +30 -37
- data/lib/mongoid/errors.rb +2 -0
- data/lib/mongoid/errors/ambiguous_relationship.rb +1 -1
- data/lib/mongoid/errors/in_memory_collation_not_supported.rb +1 -1
- data/lib/mongoid/errors/invalid_field.rb +2 -2
- data/lib/mongoid/errors/invalid_persistence_option.rb +29 -0
- data/lib/mongoid/errors/invalid_relation.rb +66 -0
- data/lib/mongoid/evolvable.rb +1 -1
- data/lib/mongoid/extensions.rb +0 -4
- data/lib/mongoid/extensions/big_decimal.rb +17 -8
- data/lib/mongoid/extensions/date.rb +4 -1
- data/lib/mongoid/extensions/decimal128.rb +3 -3
- data/lib/mongoid/extensions/hash.rb +1 -0
- data/lib/mongoid/extensions/string.rb +4 -3
- data/lib/mongoid/extensions/time.rb +4 -1
- data/lib/mongoid/fields/validators/macro.rb +18 -0
- data/lib/mongoid/findable.rb +2 -2
- data/lib/mongoid/indexable.rb +15 -13
- data/lib/mongoid/interceptable.rb +5 -22
- data/lib/mongoid/matchable.rb +13 -7
- data/lib/mongoid/matchable/all.rb +2 -2
- data/lib/mongoid/matchable/and.rb +3 -3
- data/lib/mongoid/matchable/default.rb +2 -2
- data/lib/mongoid/matchable/elem_match.rb +28 -0
- data/lib/mongoid/matchable/exists.rb +2 -2
- data/lib/mongoid/matchable/gt.rb +4 -2
- data/lib/mongoid/matchable/gte.rb +4 -2
- data/lib/mongoid/matchable/in.rb +2 -2
- data/lib/mongoid/matchable/lt.rb +4 -2
- data/lib/mongoid/matchable/lte.rb +4 -2
- data/lib/mongoid/matchable/ne.rb +2 -2
- data/lib/mongoid/matchable/nin.rb +2 -2
- data/lib/mongoid/matchable/or.rb +3 -3
- data/lib/mongoid/matchable/regexp.rb +3 -3
- data/lib/mongoid/matchable/size.rb +2 -2
- data/lib/mongoid/persistable.rb +3 -5
- data/lib/mongoid/persistable/creatable.rb +2 -2
- data/lib/mongoid/persistable/deletable.rb +1 -1
- data/lib/mongoid/persistable/settable.rb +1 -1
- data/lib/mongoid/persistable/updatable.rb +5 -12
- data/lib/mongoid/persistable/upsertable.rb +1 -1
- data/lib/mongoid/persistence_context.rb +215 -0
- data/lib/mongoid/query_cache.rb +3 -6
- data/lib/mongoid/relations/accessors.rb +3 -0
- data/lib/mongoid/relations/auto_save.rb +12 -4
- data/lib/mongoid/relations/bindings/referenced/many_to_many.rb +4 -4
- data/lib/mongoid/relations/counter_cache.rb +15 -5
- data/lib/mongoid/relations/eager.rb +6 -11
- data/lib/mongoid/relations/eager/base.rb +3 -3
- data/lib/mongoid/relations/eager/has_and_belongs_to_many.rb +2 -2
- data/lib/mongoid/relations/eager/has_many.rb +1 -1
- data/lib/mongoid/relations/embedded/batchable.rb +12 -36
- data/lib/mongoid/relations/embedded/in.rb +13 -1
- data/lib/mongoid/relations/embedded/many.rb +28 -10
- data/lib/mongoid/relations/embedded/one.rb +14 -1
- data/lib/mongoid/relations/macros.rb +9 -1
- data/lib/mongoid/relations/metadata.rb +3 -3
- data/lib/mongoid/relations/options.rb +2 -2
- data/lib/mongoid/relations/proxy.rb +1 -31
- data/lib/mongoid/relations/referenced/in.rb +19 -10
- data/lib/mongoid/relations/referenced/many.rb +23 -17
- data/lib/mongoid/relations/referenced/many_to_many.rb +20 -13
- data/lib/mongoid/relations/referenced/one.rb +15 -1
- data/lib/mongoid/relations/synchronization.rb +11 -11
- data/lib/mongoid/relations/touchable.rb +6 -3
- data/lib/mongoid/reloadable.rb +1 -1
- data/lib/mongoid/serializable.rb +1 -1
- data/lib/mongoid/traversable.rb +1 -1
- data/lib/mongoid/validatable/uniqueness.rb +1 -2
- data/lib/mongoid/version.rb +1 -1
- data/lib/rails/generators/mongoid/config/templates/mongoid.yml +14 -3
- data/spec/app/models/album.rb +5 -1
- data/spec/app/models/artist.rb +21 -0
- data/spec/app/models/book.rb +2 -1
- data/spec/app/models/dokument.rb +1 -0
- data/spec/app/models/ordered_post.rb +5 -0
- data/spec/app/models/oscar.rb +1 -2
- data/spec/app/models/page.rb +1 -1
- data/spec/app/models/person.rb +3 -3
- data/spec/app/models/princess.rb +2 -0
- data/spec/app/models/record.rb +1 -0
- data/spec/app/models/subscription.rb +1 -0
- data/spec/app/models/thing.rb +1 -1
- data/spec/config/mongoid.yml +15 -0
- data/spec/mongoid/atomic/modifiers_spec.rb +17 -17
- data/spec/mongoid/atomic_spec.rb +17 -17
- data/spec/mongoid/attributes/nested_spec.rb +14 -14
- data/spec/mongoid/attributes/readonly_spec.rb +87 -44
- data/spec/mongoid/attributes_spec.rb +90 -5
- data/spec/mongoid/cacheable_spec.rb +112 -0
- data/spec/mongoid/changeable_spec.rb +58 -0
- data/spec/mongoid/clients/factory_spec.rb +31 -3
- data/spec/mongoid/clients/options_spec.rb +382 -96
- data/spec/mongoid/clients_spec.rb +243 -101
- data/spec/mongoid/composable_spec.rb +7 -0
- data/spec/mongoid/config_spec.rb +67 -11
- data/spec/mongoid/contextual/atomic_spec.rb +3 -3
- data/spec/mongoid/contextual/mongo_spec.rb +165 -20
- data/spec/mongoid/contextual/none_spec.rb +15 -0
- data/spec/mongoid/copyable_spec.rb +13 -4
- data/spec/mongoid/criteria/modifiable_spec.rb +239 -7
- data/spec/mongoid/criteria/options_spec.rb +29 -0
- data/spec/mongoid/criteria/queryable/aggregable_spec.rb +370 -0
- data/spec/mongoid/criteria/queryable/extensions/array_spec.rb +523 -0
- data/spec/mongoid/criteria/queryable/extensions/big_decimal_spec.rb +59 -0
- data/spec/mongoid/criteria/queryable/extensions/bignum_spec.rb +58 -0
- data/spec/mongoid/criteria/queryable/extensions/boolean_spec.rb +213 -0
- data/spec/mongoid/criteria/queryable/extensions/date_spec.rb +330 -0
- data/spec/mongoid/criteria/queryable/extensions/date_time_spec.rb +405 -0
- data/spec/mongoid/criteria/queryable/extensions/fixnum_spec.rb +58 -0
- data/spec/mongoid/criteria/queryable/extensions/float_spec.rb +65 -0
- data/spec/mongoid/criteria/queryable/extensions/hash_spec.rb +327 -0
- data/spec/mongoid/criteria/queryable/extensions/integer_spec.rb +65 -0
- data/spec/mongoid/criteria/queryable/extensions/nil_class_spec.rb +77 -0
- data/spec/mongoid/criteria/queryable/extensions/object_spec.rb +108 -0
- data/spec/mongoid/criteria/queryable/extensions/range_spec.rb +309 -0
- data/spec/mongoid/{extensions/origin → criteria/queryable/extensions}/regexp_raw_spec.rb +2 -2
- data/spec/mongoid/criteria/queryable/extensions/regexp_spec.rb +90 -0
- data/spec/mongoid/criteria/queryable/extensions/set_spec.rb +39 -0
- data/spec/mongoid/criteria/queryable/extensions/string_spec.rb +302 -0
- data/spec/mongoid/criteria/queryable/extensions/symbol_spec.rb +167 -0
- data/spec/mongoid/criteria/queryable/extensions/time_spec.rb +376 -0
- data/spec/mongoid/criteria/queryable/extensions/time_with_zone_spec.rb +347 -0
- data/spec/mongoid/criteria/queryable/forwardable_spec.rb +87 -0
- data/spec/mongoid/criteria/queryable/key_spec.rb +52 -0
- data/spec/mongoid/criteria/queryable/mergeable_spec.rb +49 -0
- data/spec/mongoid/criteria/queryable/optional_spec.rb +1799 -0
- data/spec/mongoid/criteria/queryable/options_spec.rb +360 -0
- data/spec/mongoid/criteria/queryable/pipeline_spec.rb +200 -0
- data/spec/mongoid/criteria/queryable/queryable_spec.rb +137 -0
- data/spec/mongoid/criteria/queryable/selectable_spec.rb +4174 -0
- data/spec/mongoid/criteria/queryable/selector_spec.rb +844 -0
- data/spec/mongoid/criteria/queryable/smash_spec.rb +30 -0
- data/spec/mongoid/criteria_spec.rb +152 -21
- data/spec/mongoid/document_spec.rb +37 -88
- data/spec/mongoid/errors/invalid_relation_spec.rb +37 -0
- data/spec/mongoid/errors/mongoid_error_spec.rb +6 -3
- data/spec/mongoid/extensions/big_decimal_spec.rb +320 -18
- data/spec/mongoid/extensions/boolean_spec.rb +14 -0
- data/spec/mongoid/extensions/date_spec.rb +2 -6
- data/spec/mongoid/extensions/date_time_spec.rb +2 -6
- data/spec/mongoid/extensions/decimal128_spec.rb +1 -1
- data/spec/mongoid/extensions/float_spec.rb +8 -1
- data/spec/mongoid/extensions/hash_spec.rb +15 -0
- data/spec/mongoid/extensions/integer_spec.rb +8 -1
- data/spec/mongoid/extensions/object_spec.rb +11 -0
- data/spec/mongoid/extensions/string_spec.rb +21 -0
- data/spec/mongoid/extensions/time_spec.rb +2 -6
- data/spec/mongoid/extensions/time_with_zone_spec.rb +2 -6
- data/spec/mongoid/findable_spec.rb +46 -1
- data/spec/mongoid/indexable_spec.rb +15 -3
- data/spec/mongoid/interceptable_spec.rb +68 -10
- data/spec/mongoid/matchable/all_spec.rb +4 -4
- data/spec/mongoid/matchable/and_spec.rb +10 -10
- data/spec/mongoid/matchable/default_spec.rb +12 -12
- data/spec/mongoid/matchable/elem_match_spec.rb +86 -0
- data/spec/mongoid/matchable/exists_spec.rb +5 -5
- data/spec/mongoid/matchable/gt_spec.rb +18 -7
- data/spec/mongoid/matchable/gte_spec.rb +17 -7
- data/spec/mongoid/matchable/in_spec.rb +5 -5
- data/spec/mongoid/matchable/lt_spec.rb +18 -7
- data/spec/mongoid/matchable/lte_spec.rb +18 -7
- data/spec/mongoid/matchable/ne_spec.rb +5 -5
- data/spec/mongoid/matchable/nin_spec.rb +5 -5
- data/spec/mongoid/matchable/or_spec.rb +7 -7
- data/spec/mongoid/matchable/regexp_spec.rb +5 -5
- data/spec/mongoid/matchable/size_spec.rb +3 -3
- data/spec/mongoid/matchable_spec.rb +173 -53
- data/spec/mongoid/persistable/creatable_spec.rb +7 -2
- data/spec/mongoid/persistable/deletable_spec.rb +16 -1
- data/spec/mongoid/persistable/destroyable_spec.rb +6 -2
- data/spec/mongoid/persistable/savable_spec.rb +35 -30
- data/spec/mongoid/persistable/settable_spec.rb +45 -29
- data/spec/mongoid/persistable/updatable_spec.rb +184 -5
- data/spec/mongoid/persistence_context_spec.rb +680 -0
- data/spec/mongoid/positional_spec.rb +10 -10
- data/spec/mongoid/query_cache_spec.rb +89 -0
- data/spec/mongoid/relations/accessors_spec.rb +1 -1
- data/spec/mongoid/relations/auto_save_spec.rb +39 -6
- data/spec/mongoid/relations/bindings/referenced/many_to_many_spec.rb +4 -4
- data/spec/mongoid/relations/builders_spec.rb +37 -10
- data/spec/mongoid/relations/counter_cache_spec.rb +64 -3
- data/spec/mongoid/relations/eager/has_and_belongs_to_many_spec.rb +16 -0
- data/spec/mongoid/relations/eager_spec.rb +40 -0
- data/spec/mongoid/relations/embedded/many_spec.rb +63 -47
- data/spec/mongoid/relations/embedded/one_spec.rb +2 -1
- data/spec/mongoid/relations/macros_spec.rb +395 -7
- data/spec/mongoid/relations/metadata_spec.rb +15 -1
- data/spec/mongoid/relations/proxy_spec.rb +27 -1
- data/spec/mongoid/relations/referenced/in_spec.rb +41 -1
- data/spec/mongoid/relations/referenced/many_spec.rb +13 -25
- data/spec/mongoid/relations/referenced/many_to_many_spec.rb +14 -26
- data/spec/mongoid/relations/synchronization_spec.rb +48 -2
- data/spec/mongoid/relations/touchable_spec.rb +40 -0
- data/spec/mongoid/reloadable_spec.rb +51 -0
- data/spec/mongoid/serializable_spec.rb +0 -50
- data/spec/mongoid/validatable/presence_spec.rb +1 -1
- data/spec/mongoid/validatable/uniqueness_spec.rb +18 -9
- data/spec/mongoid/validatable_spec.rb +16 -0
- data/spec/spec_helper.rb +20 -11
- metadata +524 -469
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/lib/mongoid/clients/thread_options.rb +0 -19
- data/lib/mongoid/extensions/origin/regexp_raw.rb +0 -43
- metadata.gz.sig +0 -0
data/lib/mongoid/config.rb
CHANGED
@@ -25,6 +25,7 @@ module Mongoid
|
|
25
25
|
option :use_activesupport_time_zone, default: true
|
26
26
|
option :use_utc, default: false
|
27
27
|
option :log_level, default: :info
|
28
|
+
option :belongs_to_required_by_default, default: true
|
28
29
|
option :app_name, default: nil
|
29
30
|
|
30
31
|
# Has Mongoid been configured? This is checking that at least a valid
|
@@ -106,21 +106,18 @@ module Mongoid
|
|
106
106
|
view.update_many("$push" => collect_operations(pushes))
|
107
107
|
end
|
108
108
|
|
109
|
-
# Perform an atomic $
|
109
|
+
# Perform an atomic $pushAll operation on the matching documents.
|
110
110
|
#
|
111
111
|
# @example Push the values to the matching docs.
|
112
|
-
# context.
|
112
|
+
# context.push(members: [ "Alan", "Fletch" ])
|
113
113
|
#
|
114
114
|
# @param [ Hash ] pushes The operations.
|
115
115
|
#
|
116
116
|
# @return [ nil ] Nil.
|
117
117
|
#
|
118
|
-
# @since
|
119
|
-
def
|
120
|
-
|
121
|
-
ops.merge!(field => { '$each' => elements })
|
122
|
-
end
|
123
|
-
view.update_many("$push" => push_each_updates)
|
118
|
+
# @since 3.0.0
|
119
|
+
def push_all(pushes)
|
120
|
+
view.update_many("$pushAll" => collect_operations(pushes))
|
124
121
|
end
|
125
122
|
|
126
123
|
# Perform an atomic $rename of fields on the matching documents.
|
@@ -111,7 +111,6 @@ module Mongoid
|
|
111
111
|
end
|
112
112
|
|
113
113
|
# Specifies where the map/reduce output is to be stored.
|
114
|
-
# Please see MongoDB documentation for supported map reduce options.
|
115
114
|
#
|
116
115
|
# @example Store output in memory.
|
117
116
|
# map_reduce.out(inline: 1)
|
@@ -125,9 +124,6 @@ module Mongoid
|
|
125
124
|
# @example Store output in a collection, reducing existing documents.
|
126
125
|
# map_reduce.out(reduce: "collection_name")
|
127
126
|
#
|
128
|
-
# @example Return results from map reduce.
|
129
|
-
# map_reduce.out(inline: 1)
|
130
|
-
#
|
131
127
|
# @param [ Hash ] location The place to store the results.
|
132
128
|
#
|
133
129
|
# @return [ MapReduce ] The map/reduce object.
|
@@ -44,7 +44,7 @@ module Mongoid
|
|
44
44
|
deleted = count
|
45
45
|
removed = map do |doc|
|
46
46
|
prepare_remove(doc)
|
47
|
-
doc.
|
47
|
+
doc.send(:as_attributes)
|
48
48
|
end
|
49
49
|
unless removed.empty?
|
50
50
|
collection.find(selector).update_one(
|
@@ -148,7 +148,7 @@ module Mongoid
|
|
148
148
|
@documents = criteria.documents.select do |doc|
|
149
149
|
@root ||= doc._root
|
150
150
|
@collection ||= root.collection
|
151
|
-
doc.
|
151
|
+
doc._matches?(criteria.selector)
|
152
152
|
end
|
153
153
|
apply_sorting
|
154
154
|
apply_options
|
@@ -24,6 +24,7 @@ module Mongoid
|
|
24
24
|
:sort,
|
25
25
|
:batch_size,
|
26
26
|
:max_scan,
|
27
|
+
:max_time_ms,
|
27
28
|
:snapshot,
|
28
29
|
:comment,
|
29
30
|
:read,
|
@@ -110,7 +111,9 @@ module Mongoid
|
|
110
111
|
#
|
111
112
|
# @since 3.0.0
|
112
113
|
def distinct(field)
|
113
|
-
view.distinct(klass.database_field_name(field))
|
114
|
+
view.distinct(klass.database_field_name(field)).map do |value|
|
115
|
+
value.class.demongoize(value)
|
116
|
+
end
|
114
117
|
end
|
115
118
|
|
116
119
|
# Iterate over the context. If provided a block, yield to a Mongoid
|
@@ -233,21 +236,33 @@ module Mongoid
|
|
233
236
|
# @example Get the first document.
|
234
237
|
# context.first
|
235
238
|
#
|
236
|
-
# @note
|
237
|
-
#
|
238
|
-
#
|
239
|
-
#
|
240
|
-
#
|
239
|
+
# @note Automatically adding a sort on _id when no other sort is
|
240
|
+
# defined on the criteria has the potential to cause bad performance issues.
|
241
|
+
# If you experience unexpected poor performance when using #first or #last
|
242
|
+
# and have no sort defined on the criteria, use the option { id_sort: :none }.
|
243
|
+
# Be aware that #first/#last won't guarantee order in this case.
|
244
|
+
#
|
245
|
+
# @param [ Hash ] opts The options for the query returning the first document.
|
246
|
+
#
|
247
|
+
# @option opts [ :none ] :id_sort Don't apply a sort on _id if no other sort
|
248
|
+
# is defined on the criteria.
|
241
249
|
#
|
242
250
|
# @return [ Document ] The first document.
|
243
251
|
#
|
244
252
|
# @since 3.0.0
|
245
|
-
def first
|
253
|
+
def first(opts = {})
|
246
254
|
return documents.first if cached? && cache_loaded?
|
247
255
|
try_cache(:first) do
|
248
|
-
if
|
249
|
-
|
250
|
-
|
256
|
+
if sort = view.sort || ({ _id: 1 } unless opts[:id_sort] == :none)
|
257
|
+
if raw_doc = view.sort(sort).limit(-1).first
|
258
|
+
doc = Factory.from_db(klass, raw_doc, criteria.options[:fields])
|
259
|
+
eager_load([doc]).first
|
260
|
+
end
|
261
|
+
else
|
262
|
+
if raw_doc = view.limit(-1).first
|
263
|
+
doc = Factory.from_db(klass, raw_doc, criteria.options[:fields])
|
264
|
+
eager_load([doc]).first
|
265
|
+
end
|
251
266
|
end
|
252
267
|
end
|
253
268
|
end
|
@@ -323,7 +338,7 @@ module Mongoid
|
|
323
338
|
# @since 3.0.0
|
324
339
|
def initialize(criteria)
|
325
340
|
@criteria, @klass, @cache = criteria, criteria.klass, criteria.options[:cache]
|
326
|
-
@collection = @klass.
|
341
|
+
@collection = @klass.collection
|
327
342
|
criteria.send(:merge_type_selection)
|
328
343
|
@view = collection.find(criteria.selector)
|
329
344
|
apply_options
|
@@ -336,18 +351,21 @@ module Mongoid
|
|
336
351
|
# @example Get the last document.
|
337
352
|
# context.last
|
338
353
|
#
|
339
|
-
# @note
|
340
|
-
#
|
341
|
-
#
|
342
|
-
#
|
343
|
-
#
|
354
|
+
# @note Automatically adding a sort on _id when no other sort is
|
355
|
+
# defined on the criteria has the potential to cause bad performance issues.
|
356
|
+
# If you experience unexpected poor performance when using #first or #last
|
357
|
+
# and have no sort defined on the criteria, use the option { id_sort: :none }.
|
358
|
+
# Be aware that #first/#last won't guarantee order in this case.
|
359
|
+
#
|
360
|
+
# @param [ Hash ] opts The options for the query returning the first document.
|
344
361
|
#
|
345
|
-
# @
|
362
|
+
# @option opts [ :none ] :id_sort Don't apply a sort on _id if no other sort
|
363
|
+
# is defined on the criteria.
|
346
364
|
#
|
347
365
|
# @since 3.0.0
|
348
|
-
def last
|
366
|
+
def last(opts = {})
|
349
367
|
try_cache(:last) do
|
350
|
-
with_inverse_sorting do
|
368
|
+
with_inverse_sorting(opts) do
|
351
369
|
if raw_doc = view.limit(-1).first
|
352
370
|
doc = Factory.from_db(klass, raw_doc, criteria.options[:fields])
|
353
371
|
eager_load([doc]).first
|
@@ -583,10 +601,10 @@ module Mongoid
|
|
583
601
|
# context.with_inverse_sorting
|
584
602
|
#
|
585
603
|
# @since 3.0.0
|
586
|
-
def with_inverse_sorting
|
604
|
+
def with_inverse_sorting(opts = {})
|
587
605
|
begin
|
588
|
-
if
|
589
|
-
@view = view.sort(Hash[
|
606
|
+
if sort = criteria.options[:sort] || ( { _id: 1 } unless opts[:id_sort] == :none )
|
607
|
+
@view = view.sort(Hash[sort.map{|k, v| [k, -1*v]}])
|
590
608
|
end
|
591
609
|
yield
|
592
610
|
ensure
|
@@ -21,6 +21,18 @@ module Mongoid
|
|
21
21
|
other.is_a?(None)
|
22
22
|
end
|
23
23
|
|
24
|
+
# Allow distinct for null context.
|
25
|
+
#
|
26
|
+
# @example Get the distinct values.
|
27
|
+
# context.distinct(:name)
|
28
|
+
#
|
29
|
+
# @param [ String, Symbol ] field the name of the field.
|
30
|
+
#
|
31
|
+
# @return [ Array ] Empty Array
|
32
|
+
def distinct(field)
|
33
|
+
[]
|
34
|
+
end
|
35
|
+
|
24
36
|
# Iterate over the null context. There are no documents to iterate over
|
25
37
|
# in this case.
|
26
38
|
#
|
data/lib/mongoid/copyable.rb
CHANGED
@@ -20,11 +20,18 @@ module Mongoid
|
|
20
20
|
# _id and id field in the document would cause problems with Mongoid
|
21
21
|
# elsewhere.
|
22
22
|
attrs = clone_document.except("_id", "id")
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
23
|
+
dynamic_attrs = {}
|
24
|
+
attrs.reject! do |attr_name, value|
|
25
|
+
dynamic_attrs.merge!(attr_name => value) unless self.attribute_names.include?(attr_name)
|
26
|
+
end
|
27
|
+
self.class.new(attrs).tap do |object|
|
28
|
+
dynamic_attrs.each do |attr_name, value|
|
29
|
+
if object.respond_to?("#{attr_name}=")
|
30
|
+
object.send("#{attr_name}=", value)
|
31
|
+
else
|
32
|
+
object.attributes[attr_name] = value
|
33
|
+
end
|
34
|
+
end
|
28
35
|
end
|
29
36
|
end
|
30
37
|
alias :dup :clone
|
@@ -40,7 +47,7 @@ module Mongoid
|
|
40
47
|
#
|
41
48
|
# @since 3.0.22
|
42
49
|
def clone_document
|
43
|
-
attrs =
|
50
|
+
attrs = as_attributes.__deep_copy__
|
44
51
|
process_localized_attributes(self, attrs)
|
45
52
|
attrs
|
46
53
|
end
|
data/lib/mongoid/criteria.rb
CHANGED
@@ -4,7 +4,9 @@ require "mongoid/criteria/includable"
|
|
4
4
|
require "mongoid/criteria/inspectable"
|
5
5
|
require "mongoid/criteria/marshalable"
|
6
6
|
require "mongoid/criteria/modifiable"
|
7
|
+
require "mongoid/criteria/queryable"
|
7
8
|
require "mongoid/criteria/scopable"
|
9
|
+
require "mongoid/criteria/options"
|
8
10
|
|
9
11
|
module Mongoid
|
10
12
|
|
@@ -17,7 +19,7 @@ module Mongoid
|
|
17
19
|
class Criteria
|
18
20
|
include Enumerable
|
19
21
|
include Contextual
|
20
|
-
include
|
22
|
+
include Queryable
|
21
23
|
include Findable
|
22
24
|
include Inspectable
|
23
25
|
include Includable
|
@@ -25,6 +27,7 @@ module Mongoid
|
|
25
27
|
include Modifiable
|
26
28
|
include Scopable
|
27
29
|
include Clients::Options
|
30
|
+
include Options
|
28
31
|
|
29
32
|
# Static array used to check with method missing - we only need to ever
|
30
33
|
# instantiate once.
|
@@ -208,7 +211,7 @@ module Mongoid
|
|
208
211
|
#
|
209
212
|
# @example Merge the criteria with a hash. The hash must contain a klass
|
210
213
|
# key and the key/value pairs correspond to method names/args.
|
211
|
-
|
214
|
+
#
|
212
215
|
# criteria.merge({
|
213
216
|
# klass: Band,
|
214
217
|
# where: { name: "Depeche Mode" },
|
@@ -27,8 +27,8 @@ module Mongoid
|
|
27
27
|
def marshal_load(data)
|
28
28
|
@scoping_options, raw_selector, raw_options = data.pop(3)
|
29
29
|
@klass, @driver, @inclusions, @documents, @strategy, @negating = data
|
30
|
-
@selector = load_hash(
|
31
|
-
@options = load_hash(
|
30
|
+
@selector = load_hash(Queryable::Selector, raw_selector)
|
31
|
+
@options = load_hash(Queryable::Options, raw_options)
|
32
32
|
end
|
33
33
|
|
34
34
|
private
|
@@ -173,7 +173,7 @@ module Mongoid
|
|
173
173
|
# @since 3.0.0
|
174
174
|
def create_document(method, attrs = nil, &block)
|
175
175
|
attributes = selector.reduce(attrs ? attrs.dup : {}) do |hash, (key, value)|
|
176
|
-
unless key
|
176
|
+
unless invalid_key?(hash, key) || invalid_embedded_doc?(value)
|
177
177
|
hash[key] = value
|
178
178
|
end
|
179
179
|
hash
|
@@ -216,6 +216,22 @@ module Mongoid
|
|
216
216
|
def first_or(method, attrs = {}, &block)
|
217
217
|
first || create_document(method, attrs, &block)
|
218
218
|
end
|
219
|
+
|
220
|
+
private
|
221
|
+
|
222
|
+
def invalid_key?(hash, key)
|
223
|
+
# @todo Change this to BSON::String::ILLEGAL_KEY when ruby driver 2.3.0 is
|
224
|
+
# released and mongoid is updated to depend on driver >= 2.3.0
|
225
|
+
key.to_s =~ Mongoid::Document::ILLEGAL_KEY || hash.key?(key.to_sym) || hash.key?(key)
|
226
|
+
end
|
227
|
+
|
228
|
+
def invalid_embedded_doc?(value)
|
229
|
+
# @todo Change this to BSON::String::ILLEGAL_KEY when ruby driver 2.3.0 is
|
230
|
+
# released and mongoid is updated to depend on driver >= 2.3.0
|
231
|
+
value.is_a?(Hash) && value.any? do |key, v|
|
232
|
+
key.to_s =~ Mongoid::Document::ILLEGAL_KEY || invalid_embedded_doc?(v)
|
233
|
+
end
|
234
|
+
end
|
219
235
|
end
|
220
236
|
end
|
221
237
|
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Mongoid
|
3
|
+
class Criteria
|
4
|
+
|
5
|
+
# Module containing functionality for getting options on a Criteria object.
|
6
|
+
#
|
7
|
+
# @since 6.0.0
|
8
|
+
module Options
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def persistence_context
|
13
|
+
klass.persistence_context
|
14
|
+
end
|
15
|
+
|
16
|
+
def set_persistence_context(options)
|
17
|
+
PersistenceContext.set(klass, options)
|
18
|
+
end
|
19
|
+
|
20
|
+
def clear_persistence_context(original_cluster)
|
21
|
+
PersistenceContext.clear(klass, original_cluster)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require "mongoid/criteria/queryable/extensions"
|
3
|
+
require "mongoid/criteria/queryable/forwardable"
|
4
|
+
require "mongoid/criteria/queryable/key"
|
5
|
+
require "mongoid/criteria/queryable/macroable"
|
6
|
+
require "mongoid/criteria/queryable/mergeable"
|
7
|
+
require "mongoid/criteria/queryable/smash"
|
8
|
+
require "mongoid/criteria/queryable/aggregable"
|
9
|
+
require "mongoid/criteria/queryable/pipeline"
|
10
|
+
require "mongoid/criteria/queryable/optional"
|
11
|
+
require "mongoid/criteria/queryable/options"
|
12
|
+
require "mongoid/criteria/queryable/selectable"
|
13
|
+
require "mongoid/criteria/queryable/selector"
|
14
|
+
|
15
|
+
module Mongoid
|
16
|
+
class Criteria
|
17
|
+
|
18
|
+
# A queryable is any object that needs queryable's dsl injected into it to build
|
19
|
+
# MongoDB queries. For example, a Mongoid::Criteria is an Queryable.
|
20
|
+
#
|
21
|
+
# @example Include queryable functionality.
|
22
|
+
# class Criteria
|
23
|
+
# include Queryable
|
24
|
+
# end
|
25
|
+
module Queryable
|
26
|
+
include Mergeable
|
27
|
+
include Aggregable
|
28
|
+
include Selectable
|
29
|
+
include Optional
|
30
|
+
|
31
|
+
# @attribute [r] aliases The aliases.
|
32
|
+
# @attribute [r] driver The Mongo driver being used.
|
33
|
+
# @attribute [r] serializers The serializers.
|
34
|
+
attr_reader :aliases, :driver, :serializers
|
35
|
+
|
36
|
+
# Is this queryable equal to another object? Is true if the selector and
|
37
|
+
# options are equal.
|
38
|
+
#
|
39
|
+
# @example Are the objects equal?
|
40
|
+
# queryable == criteria
|
41
|
+
#
|
42
|
+
# @param [ Object ] other The object to compare against.
|
43
|
+
#
|
44
|
+
# @return [ true, false ] If the objects are equal.
|
45
|
+
#
|
46
|
+
# @since 1.0.0
|
47
|
+
def ==(other)
|
48
|
+
return false unless other.is_a?(Queryable)
|
49
|
+
selector == other.selector && options == other.options
|
50
|
+
end
|
51
|
+
|
52
|
+
# Initialize the new queryable. Will yield itself to the block if a block
|
53
|
+
# is provided for objects that need additional behaviour.
|
54
|
+
#
|
55
|
+
# @example Initialize the queryable.
|
56
|
+
# Queryable.new
|
57
|
+
#
|
58
|
+
# @param [ Hash ] aliases The optional field aliases.
|
59
|
+
# @param [ Hash ] serializers The optional field serializers.
|
60
|
+
# @param [ Symbol ] driver The driver being used.
|
61
|
+
#
|
62
|
+
# @since 1.0.0
|
63
|
+
def initialize(aliases = {}, serializers = {}, driver = :mongo)
|
64
|
+
@aliases, @driver, @serializers = aliases, driver.to_sym, serializers
|
65
|
+
@options = Options.new(aliases, serializers)
|
66
|
+
@selector = Selector.new(aliases, serializers)
|
67
|
+
@pipeline = Pipeline.new(aliases)
|
68
|
+
@aggregating = nil
|
69
|
+
yield(self) if block_given?
|
70
|
+
end
|
71
|
+
|
72
|
+
# Handle the creation of a copy via #clone or #dup.
|
73
|
+
#
|
74
|
+
# @example Handle copy initialization.
|
75
|
+
# queryable.initialize_copy(criteria)
|
76
|
+
#
|
77
|
+
# @param [ Queryable ] other The original copy.
|
78
|
+
#
|
79
|
+
# @since 1.0.0
|
80
|
+
def initialize_copy(other)
|
81
|
+
@options = other.options.__deep_copy__
|
82
|
+
@selector = other.selector.__deep_copy__
|
83
|
+
@pipeline = other.pipeline.__deep_copy__
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,120 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Mongoid
|
3
|
+
class Criteria
|
4
|
+
module Queryable
|
5
|
+
|
6
|
+
# Provides a DSL around crafting aggregation framework commands.
|
7
|
+
#
|
8
|
+
# @since 2.0.0
|
9
|
+
module Aggregable
|
10
|
+
extend Macroable
|
11
|
+
|
12
|
+
# @attribute [r] pipeline The aggregation pipeline.
|
13
|
+
attr_reader :pipeline
|
14
|
+
|
15
|
+
# @attribute [rw] aggregating Flag for whether or not we are aggregating.
|
16
|
+
attr_writer :aggregating
|
17
|
+
|
18
|
+
# Has the aggregable enter an aggregation state. Ie, are only aggregation
|
19
|
+
# operations allowed at this point on.
|
20
|
+
#
|
21
|
+
# @example Is the aggregable aggregating?
|
22
|
+
# aggregable.aggregating?
|
23
|
+
#
|
24
|
+
# @return [ true, false ] If the aggregable is aggregating.
|
25
|
+
#
|
26
|
+
# @since 2.0.0
|
27
|
+
def aggregating?
|
28
|
+
!!@aggregating
|
29
|
+
end
|
30
|
+
|
31
|
+
# Add a group ($group) operation to the aggregation pipeline.
|
32
|
+
#
|
33
|
+
# @example Add a group operation being verbose.
|
34
|
+
# aggregable.group(count: { "$sum" => 1 }, max: { "$max" => "likes" })
|
35
|
+
#
|
36
|
+
# @example Add a group operation using symbol shortcuts.
|
37
|
+
# aggregable.group(:count.sum => 1, :max.max => "likes")
|
38
|
+
#
|
39
|
+
# @param [ Hash ] operation The group operation.
|
40
|
+
#
|
41
|
+
# @return [ Aggregable ] The aggregable.
|
42
|
+
#
|
43
|
+
# @since 2.0.0
|
44
|
+
def group(operation)
|
45
|
+
aggregation(operation) do |pipeline|
|
46
|
+
pipeline.group(operation)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
key :avg, :override, "$avg"
|
50
|
+
key :max, :override, "$max"
|
51
|
+
key :min, :override, "$min"
|
52
|
+
key :sum, :override, "$sum"
|
53
|
+
key :last, :override, "$last"
|
54
|
+
key :push, :override, "$push"
|
55
|
+
key :first, :override, "$first"
|
56
|
+
key :add_to_set, :override, "$addToSet"
|
57
|
+
|
58
|
+
# Add a projection ($project) to the aggregation pipeline.
|
59
|
+
#
|
60
|
+
# @example Add a projection to the pipeline.
|
61
|
+
# aggregable.project(author: 1, name: 0)
|
62
|
+
#
|
63
|
+
# @param [ Hash ] operation The projection to make.
|
64
|
+
#
|
65
|
+
# @return [ Aggregable ] The aggregable.
|
66
|
+
#
|
67
|
+
# @since 2.0.0
|
68
|
+
def project(operation = nil)
|
69
|
+
aggregation(operation) do |pipeline|
|
70
|
+
pipeline.project(operation)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# Add an unwind ($unwind) to the aggregation pipeline.
|
75
|
+
#
|
76
|
+
# @example Add an unwind to the pipeline.
|
77
|
+
# aggregable.unwind(:field)
|
78
|
+
#
|
79
|
+
# @param [ String, Symbol ] field The name of the field to unwind.
|
80
|
+
#
|
81
|
+
# @return [ Aggregable ] The aggregable.
|
82
|
+
#
|
83
|
+
# @since 2.0.0
|
84
|
+
def unwind(field)
|
85
|
+
aggregation(field) do |pipeline|
|
86
|
+
pipeline.unwind(field)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
private
|
91
|
+
|
92
|
+
# Add the aggregation operation.
|
93
|
+
#
|
94
|
+
# @api private
|
95
|
+
#
|
96
|
+
# @example Aggregate on the operation.
|
97
|
+
# aggregation(operation) do |pipeline|
|
98
|
+
# pipeline.push("$project" => operation)
|
99
|
+
# end
|
100
|
+
#
|
101
|
+
# @param [ Hash ] operation The operation for the pipeline.
|
102
|
+
#
|
103
|
+
# @return [ Aggregable ] The cloned aggregable.
|
104
|
+
#
|
105
|
+
# @since 2.0.0
|
106
|
+
def aggregation(operation)
|
107
|
+
return self unless operation
|
108
|
+
clone.tap do |query|
|
109
|
+
unless aggregating?
|
110
|
+
query.pipeline.concat(query.selector.to_pipeline)
|
111
|
+
query.pipeline.concat(query.options.to_pipeline)
|
112
|
+
query.aggregating = true
|
113
|
+
end
|
114
|
+
yield(query.pipeline)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|