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
data/lib/mongoid/findable.rb
CHANGED
|
@@ -22,18 +22,24 @@ module Mongoid
|
|
|
22
22
|
:each,
|
|
23
23
|
:each_with_index,
|
|
24
24
|
:extras,
|
|
25
|
+
:fifth,
|
|
26
|
+
:fifth!,
|
|
25
27
|
:find_one_and_delete,
|
|
26
28
|
:find_one_and_replace,
|
|
27
29
|
:find_one_and_update,
|
|
28
30
|
:find_or_create_by,
|
|
29
31
|
:find_or_create_by!,
|
|
30
32
|
:find_or_initialize_by,
|
|
33
|
+
:first!,
|
|
31
34
|
:first_or_create,
|
|
32
35
|
:first_or_create!,
|
|
33
36
|
:first_or_initialize,
|
|
34
37
|
:for_js,
|
|
38
|
+
:fourth,
|
|
39
|
+
:fourth!,
|
|
35
40
|
:geo_near,
|
|
36
41
|
:includes,
|
|
42
|
+
:last!,
|
|
37
43
|
:map_reduce,
|
|
38
44
|
:max,
|
|
39
45
|
:min,
|
|
@@ -41,11 +47,19 @@ module Mongoid
|
|
|
41
47
|
:pick,
|
|
42
48
|
:pluck,
|
|
43
49
|
:read,
|
|
50
|
+
:second,
|
|
51
|
+
:second!,
|
|
52
|
+
:second_to_last,
|
|
53
|
+
:second_to_last!,
|
|
44
54
|
:sum,
|
|
45
55
|
:take,
|
|
46
56
|
:take!,
|
|
47
57
|
:tally,
|
|
48
58
|
:text_search,
|
|
59
|
+
:third,
|
|
60
|
+
:third!,
|
|
61
|
+
:third_to_last,
|
|
62
|
+
:third_to_last!,
|
|
49
63
|
:update,
|
|
50
64
|
:update_all,
|
|
51
65
|
|
|
@@ -87,9 +101,19 @@ module Mongoid
|
|
|
87
101
|
# @example Do any documents exist for the conditions?
|
|
88
102
|
# Person.exists?
|
|
89
103
|
#
|
|
104
|
+
# @example Do any documents exist for given _id.
|
|
105
|
+
# Person.exists?(BSON::ObjectId(...))
|
|
106
|
+
#
|
|
107
|
+
# @example Do any documents exist for given conditions.
|
|
108
|
+
# Person.exists?(name: "...")
|
|
109
|
+
#
|
|
110
|
+
# @param [ Hash | Object | false ] id_or_conditions an _id to
|
|
111
|
+
# search for, a hash of conditions, nil or false.
|
|
112
|
+
#
|
|
90
113
|
# @return [ true | false ] If any documents exist for the conditions.
|
|
91
|
-
|
|
92
|
-
|
|
114
|
+
# Always false if passed nil or false.
|
|
115
|
+
def exists?(id_or_conditions = :none)
|
|
116
|
+
with_default_scope.exists?(id_or_conditions)
|
|
93
117
|
end
|
|
94
118
|
|
|
95
119
|
# Finds a +Document+ or multiple documents by their _id values.
|
|
@@ -135,7 +159,7 @@ module Mongoid
|
|
|
135
159
|
# @note Each argument can be an individual id, an array of ids or
|
|
136
160
|
# a nested array. Each array will be flattened.
|
|
137
161
|
#
|
|
138
|
-
# @param [ Object | Array<Object> ] *args The
|
|
162
|
+
# @param [ [ Object | Array<Object> ]... ] *args The id(s) to find.
|
|
139
163
|
#
|
|
140
164
|
# @return [ Document | Array<Document> | nil ] A document or matching documents.
|
|
141
165
|
#
|
|
@@ -79,7 +79,7 @@ module Mongoid
|
|
|
79
79
|
# @example Run only the after save callbacks.
|
|
80
80
|
# model.run_after_callbacks(:save)
|
|
81
81
|
#
|
|
82
|
-
# @param [
|
|
82
|
+
# @param [ Symbol... ] *kinds The events that are occurring.
|
|
83
83
|
#
|
|
84
84
|
# @return [ Object ] The result of the chain executing.
|
|
85
85
|
def run_after_callbacks(*kinds)
|
|
@@ -96,7 +96,7 @@ module Mongoid
|
|
|
96
96
|
# @example Run only the before save callbacks.
|
|
97
97
|
# model.run_before_callbacks(:save, :create)
|
|
98
98
|
#
|
|
99
|
-
# @param [
|
|
99
|
+
# @param [ Symbol... ] *kinds The events that are occurring.
|
|
100
100
|
#
|
|
101
101
|
# @return [ Object ] The result of the chain executing.
|
|
102
102
|
def run_before_callbacks(*kinds)
|
|
@@ -134,19 +134,20 @@ module Mongoid
|
|
|
134
134
|
# Run the callbacks for embedded documents.
|
|
135
135
|
#
|
|
136
136
|
# @param [ Symbol ] kind The type of callback to execute.
|
|
137
|
-
# @param [ Array<Document> ] children Children to
|
|
137
|
+
# @param [ Array<Document> ] children Children to execute callbacks on. If
|
|
138
138
|
# nil, callbacks will be executed on all cascadable children of
|
|
139
139
|
# the document.
|
|
140
140
|
#
|
|
141
141
|
# @api private
|
|
142
142
|
def _mongoid_run_child_callbacks(kind, children: nil, &block)
|
|
143
143
|
child, *tail = (children || cascadable_children(kind))
|
|
144
|
+
with_children = !Mongoid::Config.prevent_multiple_calls_of_embedded_callbacks
|
|
144
145
|
if child.nil?
|
|
145
|
-
|
|
146
|
+
block&.call
|
|
146
147
|
elsif tail.empty?
|
|
147
|
-
|
|
148
|
+
child.run_callbacks(child_callback_type(kind, child), with_children: with_children, &block)
|
|
148
149
|
else
|
|
149
|
-
|
|
150
|
+
child.run_callbacks(child_callback_type(kind, child), with_children: with_children) do
|
|
150
151
|
_mongoid_run_child_callbacks(kind, children: tail, &block)
|
|
151
152
|
end
|
|
152
153
|
end
|
|
@@ -46,7 +46,7 @@ module Mongoid
|
|
|
46
46
|
end
|
|
47
47
|
end
|
|
48
48
|
|
|
49
|
-
# Per https://
|
|
49
|
+
# Per https://www.mongodb.com/docs/ruby-driver/current/tutorials/bson-v4/#time-instances,
|
|
50
50
|
# > Times in BSON (and MongoDB) can only have millisecond precision. When Ruby Time instances
|
|
51
51
|
# are serialized to BSON or Extended JSON, the times are floored to the nearest millisecond.
|
|
52
52
|
#
|
data/lib/mongoid/matcher/type.rb
CHANGED
data/lib/mongoid/matcher.rb
CHANGED
|
@@ -2,7 +2,6 @@ module Mongoid
|
|
|
2
2
|
|
|
3
3
|
# @api private
|
|
4
4
|
module Matcher
|
|
5
|
-
|
|
6
5
|
# Extracts field values in the document at the specified key.
|
|
7
6
|
#
|
|
8
7
|
# The document can be a Hash or a model instance.
|
|
@@ -45,7 +44,7 @@ module Mongoid
|
|
|
45
44
|
# If a document has hash fields, as_attributes would keep those fields
|
|
46
45
|
# as Hash instances which do not offer indifferent access.
|
|
47
46
|
# Convert to BSON::Document to get indifferent access on hash fields.
|
|
48
|
-
document =
|
|
47
|
+
document = document.send(:as_attributes)
|
|
49
48
|
end
|
|
50
49
|
|
|
51
50
|
current = [document]
|
|
@@ -55,8 +54,9 @@ module Mongoid
|
|
|
55
54
|
current.each do |doc|
|
|
56
55
|
case doc
|
|
57
56
|
when Hash
|
|
58
|
-
|
|
59
|
-
|
|
57
|
+
actual_key = find_exact_key(doc, field)
|
|
58
|
+
if !actual_key.nil?
|
|
59
|
+
new << doc[actual_key]
|
|
60
60
|
end
|
|
61
61
|
when Array
|
|
62
62
|
if (index = field.to_i).to_s == field
|
|
@@ -66,8 +66,9 @@ module Mongoid
|
|
|
66
66
|
end
|
|
67
67
|
doc.each do |subdoc|
|
|
68
68
|
if Hash === subdoc
|
|
69
|
-
|
|
70
|
-
|
|
69
|
+
actual_key = find_exact_key(subdoc, field)
|
|
70
|
+
if !actual_key.nil?
|
|
71
|
+
new << subdoc[actual_key]
|
|
71
72
|
end
|
|
72
73
|
end
|
|
73
74
|
end
|
|
@@ -79,6 +80,20 @@ module Mongoid
|
|
|
79
80
|
|
|
80
81
|
current
|
|
81
82
|
end
|
|
83
|
+
|
|
84
|
+
# Indifferent string or symbol key lookup, returning the exact key.
|
|
85
|
+
#
|
|
86
|
+
# @param [ Hash ] hash The input hash.
|
|
87
|
+
# @param [ String | Symbol ] key The key to perform indifferent lookups with.
|
|
88
|
+
#
|
|
89
|
+
# @return [ String | Symbol | nil ] The exact key (with the correct type) that exists in the hash, or nil if the key does not exist.
|
|
90
|
+
module_function def find_exact_key(hash, key)
|
|
91
|
+
key_s = key.to_s
|
|
92
|
+
return key_s if hash.key?(key_s)
|
|
93
|
+
|
|
94
|
+
key_sym = key.to_sym
|
|
95
|
+
hash.key?(key_sym) ? key_sym : nil
|
|
96
|
+
end
|
|
82
97
|
end
|
|
83
98
|
end
|
|
84
99
|
|
|
@@ -100,6 +100,7 @@ module Mongoid
|
|
|
100
100
|
#
|
|
101
101
|
# @return [ Document ] The document.
|
|
102
102
|
def prepare_insert(options = {})
|
|
103
|
+
raise Errors::ReadonlyDocument.new(self.class) if readonly? && !Mongoid.legacy_readonly
|
|
103
104
|
return self if performing_validations?(options) &&
|
|
104
105
|
invalid?(options[:context] || :create)
|
|
105
106
|
run_callbacks(:save, with_children: false) do
|
|
@@ -16,7 +16,6 @@ module Mongoid
|
|
|
16
16
|
#
|
|
17
17
|
# @return [ TrueClass ] True.
|
|
18
18
|
def delete(options = {})
|
|
19
|
-
raise Errors::ReadonlyDocument.new(self.class) if readonly?
|
|
20
19
|
prepare_delete do
|
|
21
20
|
unless options[:persist] == false
|
|
22
21
|
if embedded?
|
|
@@ -102,6 +101,7 @@ module Mongoid
|
|
|
102
101
|
#
|
|
103
102
|
# @return [ Object ] The result of the block.
|
|
104
103
|
def prepare_delete
|
|
104
|
+
raise Errors::ReadonlyDocument.new(self.class) if readonly?
|
|
105
105
|
yield(self)
|
|
106
106
|
freeze
|
|
107
107
|
self.destroyed = true
|
|
@@ -14,7 +14,13 @@ module Mongoid
|
|
|
14
14
|
#
|
|
15
15
|
# @param [ Hash ] options Options to pass to the save.
|
|
16
16
|
#
|
|
17
|
-
# @
|
|
17
|
+
# @option options [ true | false ] :touch Whether or not the updated_at
|
|
18
|
+
# attribute will be updated with the current time. When this option is
|
|
19
|
+
# false, none of the embedded documents will be touched. This option is
|
|
20
|
+
# ignored when saving a new document, and the created_at and updated_at
|
|
21
|
+
# will be set to the current time.
|
|
22
|
+
#
|
|
23
|
+
# @return [ true | false ] True if success, false if not.
|
|
18
24
|
def save(options = {})
|
|
19
25
|
if new_record?
|
|
20
26
|
!insert(options).new_record?
|
|
@@ -31,6 +37,12 @@ module Mongoid
|
|
|
31
37
|
#
|
|
32
38
|
# @param [ Hash ] options Options to pass to the save.
|
|
33
39
|
#
|
|
40
|
+
# @option options [ true | false ] :touch Whether or not the updated_at
|
|
41
|
+
# attribute will be updated with the current time. When this option is
|
|
42
|
+
# false, none of the embedded documents will be touched.This option is
|
|
43
|
+
# ignored when saving a new document, and the created_at and updated_at
|
|
44
|
+
# will be set to the current time.
|
|
45
|
+
#
|
|
34
46
|
# @raise [ Errors::Validations ] If validation failed.
|
|
35
47
|
# @raise [ Errors::Callback ] If a callback returns false.
|
|
36
48
|
#
|
|
@@ -13,8 +13,8 @@ module Mongoid
|
|
|
13
13
|
# @example Unset the values.
|
|
14
14
|
# document.unset(:first_name, :last_name, :middle)
|
|
15
15
|
#
|
|
16
|
-
# @param [ Array<String | Symbol> ] fields
|
|
17
|
-
# unset.
|
|
16
|
+
# @param [ [ String | Symbol | Array<String | Symbol>]... ] *fields
|
|
17
|
+
# The names of the field(s) to unset.
|
|
18
18
|
#
|
|
19
19
|
# @return [ Document ] The document.
|
|
20
20
|
def unset(*fields)
|
|
@@ -91,16 +91,23 @@ module Mongoid
|
|
|
91
91
|
#
|
|
92
92
|
# @param [ Hash ] options The options.
|
|
93
93
|
#
|
|
94
|
+
# @option options [ true | false ] :touch Whether or not the updated_at
|
|
95
|
+
# attribute will be updated with the current time.
|
|
96
|
+
#
|
|
94
97
|
# @return [ true | false ] The result of the update.
|
|
95
98
|
def prepare_update(options = {})
|
|
99
|
+
raise Errors::ReadonlyDocument.new(self.class) if readonly? && !Mongoid.legacy_readonly
|
|
100
|
+
enforce_immutability_of_id_field!
|
|
96
101
|
return false if performing_validations?(options) &&
|
|
97
102
|
invalid?(options[:context] || :update)
|
|
98
103
|
process_flagged_destroys
|
|
104
|
+
update_children = cascadable_children(:update)
|
|
105
|
+
process_touch_option(options, update_children)
|
|
99
106
|
run_callbacks(:save, with_children: false) do
|
|
100
107
|
run_callbacks(:update, with_children: false) do
|
|
101
108
|
run_callbacks(:persist_parent, with_children: false) do
|
|
102
109
|
_mongoid_run_child_callbacks(:save) do
|
|
103
|
-
_mongoid_run_child_callbacks(:update) do
|
|
110
|
+
_mongoid_run_child_callbacks(:update, children: update_children) do
|
|
104
111
|
result = yield(self)
|
|
105
112
|
self.previously_new_record = false
|
|
106
113
|
post_process_persist(result, options)
|
|
@@ -160,6 +167,49 @@ module Mongoid
|
|
|
160
167
|
end
|
|
161
168
|
end
|
|
162
169
|
end
|
|
170
|
+
|
|
171
|
+
# If there is a touch option and it is false, this method will call the
|
|
172
|
+
# timeless method so that the updated_at attribute is not updated. It
|
|
173
|
+
# will call the timeless method on all of the cascadable children as
|
|
174
|
+
# well. Note that timeless is cleared in the before_update callback.
|
|
175
|
+
#
|
|
176
|
+
# @param [ Hash ] options The options.
|
|
177
|
+
# @param [ Array<Document> ] children The children that the :update
|
|
178
|
+
# callbacks will be executed on.
|
|
179
|
+
#
|
|
180
|
+
# @option options [ true | false ] :touch Whether or not the updated_at
|
|
181
|
+
# attribute will be updated with the current time.
|
|
182
|
+
def process_touch_option(options, children)
|
|
183
|
+
unless options.fetch(:touch, true)
|
|
184
|
+
timeless
|
|
185
|
+
children.each(&:timeless)
|
|
186
|
+
end
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
# Checks to see if the _id field has been modified. If it has, and if
|
|
190
|
+
# the document has already been persisted, this is an error. Otherwise,
|
|
191
|
+
# returns without side-effects.
|
|
192
|
+
#
|
|
193
|
+
# Note that if `Mongoid::Config.immutable_ids` is false, this will do
|
|
194
|
+
# nothing.
|
|
195
|
+
#
|
|
196
|
+
# @raise [ Errors::ImmutableAttribute ] if _id has changed, and document
|
|
197
|
+
# has been persisted.
|
|
198
|
+
def enforce_immutability_of_id_field!
|
|
199
|
+
# special case here: we *do* allow the _id to be mutated if it was
|
|
200
|
+
# previously nil. This addresses an odd case exposed in
|
|
201
|
+
# has_one/proxy_spec.rb where `person.create_address` would
|
|
202
|
+
# (somehow?) create the address with a nil _id first, before then
|
|
203
|
+
# saving it *again* with the correct _id.
|
|
204
|
+
|
|
205
|
+
if _id_changed? && !_id_was.nil? && persisted?
|
|
206
|
+
if Mongoid::Config.immutable_ids
|
|
207
|
+
raise Errors::ImmutableAttribute.new(:_id, _id)
|
|
208
|
+
else
|
|
209
|
+
Mongoid::Warnings.warn_mutable_ids
|
|
210
|
+
end
|
|
211
|
+
end
|
|
212
|
+
end
|
|
163
213
|
end
|
|
164
214
|
end
|
|
165
215
|
end
|
|
@@ -10,16 +10,32 @@ module Mongoid
|
|
|
10
10
|
# database, then Mongo will insert a new one, otherwise the fields will get
|
|
11
11
|
# overwritten with new values on the existing document.
|
|
12
12
|
#
|
|
13
|
+
# If the replace option is true, unspecified attributes will be dropped,
|
|
14
|
+
# and if it is false, unspecified attributes will be maintained. The
|
|
15
|
+
# replace option defaults to true in Mongoid 8.1 and earlier. The default
|
|
16
|
+
# will be flipped to false in Mongoid 9.
|
|
17
|
+
#
|
|
13
18
|
# @example Upsert the document.
|
|
14
19
|
# document.upsert
|
|
15
20
|
#
|
|
21
|
+
# @example Upsert the document without replace.
|
|
22
|
+
# document.upsert(replace: false)
|
|
23
|
+
#
|
|
16
24
|
# @param [ Hash ] options The validation options.
|
|
17
25
|
#
|
|
26
|
+
# @option options [ true | false ] :validate Whether or not to validate.
|
|
27
|
+
# @option options [ true | false ] :replace Whether or not to replace the document on upsert.
|
|
28
|
+
#
|
|
18
29
|
# @return [ true ] True.
|
|
19
30
|
def upsert(options = {})
|
|
20
31
|
prepare_upsert(options) do
|
|
21
|
-
|
|
32
|
+
if options.fetch(:replace, true)
|
|
33
|
+
collection.find(atomic_selector).replace_one(
|
|
22
34
|
as_attributes, upsert: true, session: _session)
|
|
35
|
+
else
|
|
36
|
+
collection.find(atomic_selector).update_one(
|
|
37
|
+
{ "$set" => as_attributes }, upsert: true, session: _session)
|
|
38
|
+
end
|
|
23
39
|
end
|
|
24
40
|
end
|
|
25
41
|
|
|
@@ -36,8 +52,11 @@ module Mongoid
|
|
|
36
52
|
#
|
|
37
53
|
# @param [ Hash ] options The options hash.
|
|
38
54
|
#
|
|
55
|
+
# @option options [ true | false ] :validate Whether or not to validate.
|
|
56
|
+
#
|
|
39
57
|
# @return [ true | false ] If the operation succeeded.
|
|
40
58
|
def prepare_upsert(options = {})
|
|
59
|
+
raise Errors::ReadonlyDocument.new(self.class) if readonly? && !Mongoid.legacy_readonly
|
|
41
60
|
return false if performing_validations?(options) && invalid?(:upsert)
|
|
42
61
|
result = run_callbacks(:upsert) do
|
|
43
62
|
yield(self)
|
data/lib/mongoid/persistable.rb
CHANGED
|
@@ -161,6 +161,8 @@ module Mongoid
|
|
|
161
161
|
# @param [ Object ] result The result of the operation.
|
|
162
162
|
# @param [ Hash ] options The options.
|
|
163
163
|
#
|
|
164
|
+
# @option options [ true | false ] :validate Whether or not to validate.
|
|
165
|
+
#
|
|
164
166
|
# @return [ true ] true.
|
|
165
167
|
def post_process_persist(result, options = {})
|
|
166
168
|
post_persist unless result == false
|
|
@@ -180,6 +182,7 @@ module Mongoid
|
|
|
180
182
|
#
|
|
181
183
|
# @return [ Object ] The result of the operation.
|
|
182
184
|
def prepare_atomic_operation
|
|
185
|
+
raise Errors::ReadonlyDocument.new(self.class) if readonly? && !Mongoid.legacy_readonly
|
|
183
186
|
operations = yield({})
|
|
184
187
|
persist_or_delay_atomic_operation(operations)
|
|
185
188
|
self
|
data/lib/mongoid/query_cache.rb
CHANGED
|
@@ -14,6 +14,7 @@ module Mongoid
|
|
|
14
14
|
#
|
|
15
15
|
# @return [ nil ] Always nil.
|
|
16
16
|
def clear_cache
|
|
17
|
+
Mongoid::Warnings.warn_mongoid_query_cache_clear
|
|
17
18
|
Mongo::QueryCache.clear
|
|
18
19
|
end
|
|
19
20
|
|
|
@@ -24,6 +25,7 @@ module Mongoid
|
|
|
24
25
|
#
|
|
25
26
|
# @param [ true | false ] value The enabled value.
|
|
26
27
|
def enabled=(value)
|
|
28
|
+
Mongoid::Warnings.warn_mongoid_query_cache
|
|
27
29
|
Mongo::QueryCache.enabled = value
|
|
28
30
|
end
|
|
29
31
|
|
|
@@ -34,6 +36,7 @@ module Mongoid
|
|
|
34
36
|
#
|
|
35
37
|
# @return [ true | false ] If the cache is enabled.
|
|
36
38
|
def enabled?
|
|
39
|
+
Mongoid::Warnings.warn_mongoid_query_cache
|
|
37
40
|
Mongo::QueryCache.enabled?
|
|
38
41
|
end
|
|
39
42
|
|
|
@@ -44,6 +47,7 @@ module Mongoid
|
|
|
44
47
|
#
|
|
45
48
|
# @return [ Object ] The result of the block.
|
|
46
49
|
def cache(&block)
|
|
50
|
+
Mongoid::Warnings.warn_mongoid_query_cache
|
|
47
51
|
Mongo::QueryCache.cache(&block)
|
|
48
52
|
end
|
|
49
53
|
|
|
@@ -54,6 +58,7 @@ module Mongoid
|
|
|
54
58
|
#
|
|
55
59
|
# @return [ Object ] The result of the block.
|
|
56
60
|
def uncached(&block)
|
|
61
|
+
Mongoid::Warnings.warn_mongoid_query_cache
|
|
57
62
|
Mongo::QueryCache.uncached(&block)
|
|
58
63
|
end
|
|
59
64
|
end
|
|
@@ -61,4 +66,3 @@ module Mongoid
|
|
|
61
66
|
Middleware = Mongo::QueryCache::Middleware
|
|
62
67
|
end
|
|
63
68
|
end
|
|
64
|
-
|
|
@@ -25,7 +25,7 @@ namespace :db do
|
|
|
25
25
|
|
|
26
26
|
unless Rake::Task.task_defined?("db:setup")
|
|
27
27
|
desc "Create the database, and initialize with the seed data"
|
|
28
|
-
task :setup => [ "db:create", "mongoid:create_indexes", "db:seed" ]
|
|
28
|
+
task :setup => [ "db:create", "mongoid:create_collections", "mongoid:create_indexes", "db:seed" ]
|
|
29
29
|
end
|
|
30
30
|
|
|
31
31
|
unless Rake::Task.task_defined?("db:reset")
|
|
@@ -55,10 +55,15 @@ namespace :db do
|
|
|
55
55
|
|
|
56
56
|
unless Rake::Task.task_defined?("db:test:prepare")
|
|
57
57
|
namespace :test do
|
|
58
|
-
task :prepare => "mongoid:create_indexes"
|
|
58
|
+
task :prepare => ["mongoid:create_collections", "mongoid:create_indexes"]
|
|
59
59
|
end
|
|
60
60
|
end
|
|
61
61
|
|
|
62
|
+
unless Rake::Task.task_defined?("db:create_collections")
|
|
63
|
+
desc "Create collections specified in Mongoid models"
|
|
64
|
+
task :create_collections => "mongoid:create_collections"
|
|
65
|
+
end
|
|
66
|
+
|
|
62
67
|
unless Rake::Task.task_defined?("db:create_indexes")
|
|
63
68
|
desc "Create indexes specified in Mongoid models"
|
|
64
69
|
task :create_indexes => "mongoid:create_indexes"
|
data/lib/mongoid/shardable.rb
CHANGED
|
@@ -47,18 +47,22 @@ module Mongoid
|
|
|
47
47
|
self.class.shard_key_fields
|
|
48
48
|
end
|
|
49
49
|
|
|
50
|
-
# Returns the selector that would match the
|
|
51
|
-
#
|
|
50
|
+
# Returns the selector that would match the defined shard keys. If
|
|
51
|
+
# `prefer_persisted` is false (the default), it uses the current values
|
|
52
|
+
# of the specified shard keys, otherwise, it will try to use whatever value
|
|
53
|
+
# was most recently persisted.
|
|
54
|
+
#
|
|
55
|
+
# @param [ true | false ] prefer_persisted Whether to use the current
|
|
56
|
+
# value of the shard key fields, or to use their most recently persisted
|
|
57
|
+
# values.
|
|
52
58
|
#
|
|
53
59
|
# @return [ Hash ] The shard key selector.
|
|
54
60
|
#
|
|
55
61
|
# @api private
|
|
56
|
-
def shard_key_selector
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
selector[field.to_s] = send(field)
|
|
62
|
+
def shard_key_selector(prefer_persisted: false)
|
|
63
|
+
shard_key_fields.each_with_object({}) do |field, selector|
|
|
64
|
+
selector[field.to_s] = shard_key_field_value(field.to_s, prefer_persisted: prefer_persisted)
|
|
60
65
|
end
|
|
61
|
-
selector
|
|
62
66
|
end
|
|
63
67
|
|
|
64
68
|
# Returns the selector that would match the existing version of this
|
|
@@ -72,11 +76,31 @@ module Mongoid
|
|
|
72
76
|
#
|
|
73
77
|
# @api private
|
|
74
78
|
def shard_key_selector_in_db
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
79
|
+
shard_key_selector(prefer_persisted: true)
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# Returns the value for the named shard key. If the field identifies
|
|
83
|
+
# an embedded document, the key will be parsed and recursively evaluated.
|
|
84
|
+
# If `prefer_persisted` is true, the value last persisted to the database
|
|
85
|
+
# will be returned, regardless of what the current value of the attribute
|
|
86
|
+
# may be.
|
|
87
|
+
#
|
|
88
|
+
# @param [String] field The name of the field to evaluate
|
|
89
|
+
# @param [ true|false ] prefer_persisted Whether or not to prefer the
|
|
90
|
+
# persisted value over the current value.
|
|
91
|
+
#
|
|
92
|
+
# @return [ Object ] The value of the named field.
|
|
93
|
+
#
|
|
94
|
+
# @api private
|
|
95
|
+
def shard_key_field_value(field, prefer_persisted:)
|
|
96
|
+
if field.include?(".")
|
|
97
|
+
relation, remaining = field.split(".", 2)
|
|
98
|
+
send(relation)&.shard_key_field_value(remaining, prefer_persisted: prefer_persisted)
|
|
99
|
+
elsif prefer_persisted && !new_record?
|
|
100
|
+
attribute_was(field)
|
|
101
|
+
else
|
|
102
|
+
send(field)
|
|
78
103
|
end
|
|
79
|
-
selector
|
|
80
104
|
end
|
|
81
105
|
|
|
82
106
|
module ClassMethods
|
data/lib/mongoid/stateful.rb
CHANGED
|
@@ -95,6 +95,23 @@ module Mongoid
|
|
|
95
95
|
!_parent.delayed_atomic_sets[atomic_path]
|
|
96
96
|
end
|
|
97
97
|
|
|
98
|
+
# Flags the document as readonly. Will cause a ReadonlyDocument error to be
|
|
99
|
+
# raised if the document is attempted to be saved, updated or destroyed.
|
|
100
|
+
#
|
|
101
|
+
# @example Flag the document as readonly.
|
|
102
|
+
# document.readonly!
|
|
103
|
+
#
|
|
104
|
+
# @return [ true | false ] true if the document was successfully marked
|
|
105
|
+
# readonly, false otherwise.
|
|
106
|
+
def readonly!
|
|
107
|
+
if Mongoid.legacy_readonly
|
|
108
|
+
Mongoid::Warnings.warn_legacy_readonly
|
|
109
|
+
false
|
|
110
|
+
else
|
|
111
|
+
@readonly = true
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
|
|
98
115
|
# Is the document readonly?
|
|
99
116
|
#
|
|
100
117
|
# @example Is the document readonly?
|
|
@@ -102,7 +119,11 @@ module Mongoid
|
|
|
102
119
|
#
|
|
103
120
|
# @return [ true | false ] If the document is readonly.
|
|
104
121
|
def readonly?
|
|
105
|
-
|
|
122
|
+
if Mongoid.legacy_readonly
|
|
123
|
+
__selected_fields != nil
|
|
124
|
+
else
|
|
125
|
+
@readonly ||= false
|
|
126
|
+
end
|
|
106
127
|
end
|
|
107
128
|
|
|
108
129
|
# Determine if the document can be set.
|
|
@@ -5,6 +5,11 @@ namespace :db do
|
|
|
5
5
|
task :load_models do
|
|
6
6
|
end
|
|
7
7
|
|
|
8
|
+
desc "Create collections for Mongoid models"
|
|
9
|
+
task :create_collections => [:environment, :load_models] do
|
|
10
|
+
::Mongoid::Tasks::Database.create_collections
|
|
11
|
+
end
|
|
12
|
+
|
|
8
13
|
desc "Create indexes specified in Mongoid models"
|
|
9
14
|
task :create_indexes => [:environment, :load_models] do
|
|
10
15
|
::Mongoid::Tasks::Database.create_indexes
|
|
@@ -34,5 +39,12 @@ namespace :db do
|
|
|
34
39
|
task :purge => :environment do
|
|
35
40
|
::Mongoid.purge!
|
|
36
41
|
end
|
|
42
|
+
|
|
43
|
+
namespace :create_collections do
|
|
44
|
+
desc "Drop and create collections for Mongoid models"
|
|
45
|
+
task :force => [:environment, :load_models] do
|
|
46
|
+
::Mongoid::Tasks::Database.create_collections(force: true)
|
|
47
|
+
end
|
|
48
|
+
end
|
|
37
49
|
end
|
|
38
50
|
end
|
|
@@ -5,6 +5,26 @@ module Mongoid
|
|
|
5
5
|
module Database
|
|
6
6
|
extend self
|
|
7
7
|
|
|
8
|
+
# Create collections for each model given the provided globs and the class is
|
|
9
|
+
# not embedded.
|
|
10
|
+
#
|
|
11
|
+
# @param [ Array<Mongoid::Document> ] models. Array of document classes for
|
|
12
|
+
# which collections should be created. Defaulted to all document classes
|
|
13
|
+
# in the application.
|
|
14
|
+
# @param [ true | false ] force If true, the method will drop existing
|
|
15
|
+
# collections before creating new ones. If false, the method will create
|
|
16
|
+
# only new collection (that do not exist in the database).
|
|
17
|
+
def create_collections(models = ::Mongoid.models, force: false)
|
|
18
|
+
models.each do |model|
|
|
19
|
+
if !model.embedded? || model.cyclic?
|
|
20
|
+
model.create_collection(force: force)
|
|
21
|
+
logger.info("MONGOID: Created collection for #{model}:")
|
|
22
|
+
else
|
|
23
|
+
logger.info("MONGOID: collection options ignored on: #{model}, please define in the root model.")
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
8
28
|
# Create indexes for each model given the provided globs and the class is
|
|
9
29
|
# not embedded.
|
|
10
30
|
#
|
data/lib/mongoid/threaded.rb
CHANGED
|
@@ -26,6 +26,10 @@ module Mongoid
|
|
|
26
26
|
hash[key] = "[mongoid]:#{key}-stack"
|
|
27
27
|
end
|
|
28
28
|
|
|
29
|
+
# The key storing the default value for whether or not callbacks are
|
|
30
|
+
# executed on documents.
|
|
31
|
+
EXECUTE_CALLBACKS = '[mongoid]:execute-callbacks'
|
|
32
|
+
|
|
29
33
|
extend self
|
|
30
34
|
|
|
31
35
|
# Begin entry into a named thread local stack.
|
|
@@ -346,5 +350,31 @@ module Mongoid
|
|
|
346
350
|
session.end_session if session
|
|
347
351
|
Thread.current["[mongoid]:session"] = nil
|
|
348
352
|
end
|
|
353
|
+
|
|
354
|
+
# Queries whether document callbacks should be executed by default for the
|
|
355
|
+
# current thread.
|
|
356
|
+
#
|
|
357
|
+
# Unless otherwise indicated (by #execute_callbacks=), this will return
|
|
358
|
+
# true.
|
|
359
|
+
#
|
|
360
|
+
# @return [ true | false ] Whether or not document callbacks should be
|
|
361
|
+
# executed by default.
|
|
362
|
+
def execute_callbacks?
|
|
363
|
+
if Thread.current.key?(EXECUTE_CALLBACKS)
|
|
364
|
+
Thread.current[EXECUTE_CALLBACKS]
|
|
365
|
+
else
|
|
366
|
+
true
|
|
367
|
+
end
|
|
368
|
+
end
|
|
369
|
+
|
|
370
|
+
# Indicates whether document callbacks should be invoked by default for
|
|
371
|
+
# the current thread. Individual documents may further override the
|
|
372
|
+
# callback behavior, but this will be used for the default behavior.
|
|
373
|
+
#
|
|
374
|
+
# @param flag [ true | false ] Whether or not document callbacks should be
|
|
375
|
+
# executed by default.
|
|
376
|
+
def execute_callbacks=(flag)
|
|
377
|
+
Thread.current[EXECUTE_CALLBACKS] = flag
|
|
378
|
+
end
|
|
349
379
|
end
|
|
350
380
|
end
|