mongoid 6.2.1 → 6.3.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 +3 -2
- data.tar.gz.sig +2 -2
- data/lib/mongoid/atomic.rb +3 -3
- data/lib/mongoid/atomic/modifiers.rb +12 -8
- data/lib/mongoid/composable.rb +1 -0
- data/lib/mongoid/contextual/atomic.rb +6 -3
- data/lib/mongoid/contextual/mongo.rb +14 -6
- data/lib/mongoid/factory.rb +2 -1
- data/lib/mongoid/persistence_context.rb +5 -4
- data/lib/mongoid/query_cache.rb +5 -3
- data/lib/mongoid/relations/embedded/batchable.rb +32 -12
- data/lib/mongoid/relations/synchronization.rb +1 -1
- data/lib/mongoid/relations/targets/enumerable.rb +24 -4
- data/lib/mongoid/version.rb +1 -1
- data/spec/app/models/band.rb +1 -0
- data/spec/mongoid/atomic/modifiers_spec.rb +17 -17
- data/spec/mongoid/atomic_spec.rb +17 -17
- data/spec/mongoid/contextual/mongo_spec.rb +70 -0
- data/spec/mongoid/factory_spec.rb +11 -0
- data/spec/mongoid/persistable/savable_spec.rb +2 -2
- data/spec/mongoid/persistable/updatable_spec.rb +2 -2
- data/spec/mongoid/persistence_context_spec.rb +14 -0
- data/spec/mongoid/positional_spec.rb +10 -10
- data/spec/mongoid/relations/macros_spec.rb +20 -0
- data/spec/mongoid/relations/targets/enumerable_spec.rb +108 -0
- data/spec/spec_helper.rb +4 -0
- metadata +460 -460
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5c7e1fbb3fda280fb0e0f74c312b36b7a73dad79
|
4
|
+
data.tar.gz: 92dcab3023e9005560efd4209e3eecd26032b259
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 44e65ba1446fc7c42e545b38223d4122e798f85d26aeb93103b85c45e7a4abc17e3b7da9f60853a7a38a24b5d4a258338111759d0b22bb4e5f99611e002eaa0f
|
7
|
+
data.tar.gz: 25b84f09ac4fb6366a0d9782d0865a0a1ae214234fbdbde4ce57146d8bf740823b66f15d4871e4a45b0d3fc5f0557b9f91dd743501713ae6920a430e90bab62e
|
checksums.yaml.gz.sig
CHANGED
@@ -1,2 +1,3 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
kpQ5�N�ePGlt�
|
2
|
+
���#$[?�)�}� �A�����!�QV��+i�t�[=w
|
3
|
+
�->dƩHR�uǖ{v�|��G\bS$���l��g���=�82���̵�� W��>��BL+�Z�cS�E9�����c����Ox��)�6Ũ�Nd#���'ĝc,��5������h���UfO\LE*�{��'%��d�\@�Y���z�c�N��W�?���@�:�e3Ҟv-��
|
data.tar.gz.sig
CHANGED
@@ -1,2 +1,2 @@
|
|
1
|
-
|
2
|
-
��
|
1
|
+
��2�{&r�<`��?R��|$���L�����Yک�}NGbf�Đ���R܀6>��t�������8�I�_�^a�@:vt����ލ�}����G����`�?�;b9}
|
2
|
+
-�.�ɮog@B���M�F�0��_e_�Bc�9yY�M-+\��
|
data/lib/mongoid/atomic.rb
CHANGED
@@ -110,10 +110,10 @@ module Mongoid
|
|
110
110
|
# performed in a single operation. Conflicting modifications are
|
111
111
|
# detected by the 'haveConflictingMod' function in MongoDB.
|
112
112
|
# Examination of the code suggests that two modifications (a $set
|
113
|
-
# and a $
|
113
|
+
# and a $push with $each, for example) conflict if:
|
114
114
|
# (1) the key paths being modified are equal.
|
115
115
|
# (2) one key path is a prefix of the other.
|
116
|
-
# So a $set of 'addresses.0.street' will conflict with a $
|
116
|
+
# So a $set of 'addresses.0.street' will conflict with a $push and $each
|
117
117
|
# to 'addresses', and we will need to split our update into two
|
118
118
|
# pieces. We do not, however, attempt to match MongoDB's logic
|
119
119
|
# exactly. Instead, we assume that two updates conflict if the
|
@@ -218,7 +218,7 @@ module Mongoid
|
|
218
218
|
# @example Get the pushes.
|
219
219
|
# person.atomic_pushes
|
220
220
|
#
|
221
|
-
# @return [ Hash ] The $
|
221
|
+
# @return [ Hash ] The The $push and $each operations.
|
222
222
|
#
|
223
223
|
# @since 2.1.0
|
224
224
|
def atomic_pushes
|
@@ -68,7 +68,7 @@ module Mongoid
|
|
68
68
|
modifications.each_pair do |field, value|
|
69
69
|
push_fields[field] = field
|
70
70
|
mods = push_conflict?(field) ? conflicting_pushes : pushes
|
71
|
-
add_operation(mods, field, Array.wrap(value))
|
71
|
+
add_operation(mods, field, { '$each' => Array.wrap(value) })
|
72
72
|
end
|
73
73
|
end
|
74
74
|
|
@@ -118,8 +118,12 @@ module Mongoid
|
|
118
118
|
# @since 2.2.0
|
119
119
|
def add_operation(mods, field, value)
|
120
120
|
if mods.has_key?(field)
|
121
|
-
|
122
|
-
|
121
|
+
if mods[field].is_a?(Array)
|
122
|
+
value.each do |val|
|
123
|
+
mods[field].push(val)
|
124
|
+
end
|
125
|
+
elsif mods[field]['$each']
|
126
|
+
mods[field]['$each'].concat(value['$each'])
|
123
127
|
end
|
124
128
|
else
|
125
129
|
mods[field] = value
|
@@ -190,7 +194,7 @@ module Mongoid
|
|
190
194
|
#
|
191
195
|
# @since 2.2.0
|
192
196
|
def conflicting_pushes
|
193
|
-
conflicts["$
|
197
|
+
conflicts["$push"] ||= {}
|
194
198
|
end
|
195
199
|
|
196
200
|
# Get the conflicting set modifications.
|
@@ -277,16 +281,16 @@ module Mongoid
|
|
277
281
|
self["$pull"] ||= {}
|
278
282
|
end
|
279
283
|
|
280
|
-
# Get the $
|
284
|
+
# Get the $push/$each operations or initialize a new one.
|
281
285
|
#
|
282
|
-
# @example Get the $
|
286
|
+
# @example Get the $push/$each operations.
|
283
287
|
# modifiers.pushes
|
284
288
|
#
|
285
|
-
# @return [ Hash ] The $
|
289
|
+
# @return [ Hash ] The $push/$each operations.
|
286
290
|
#
|
287
291
|
# @since 2.1.0
|
288
292
|
def pushes
|
289
|
-
self["$
|
293
|
+
self["$push"] ||= {}
|
290
294
|
end
|
291
295
|
|
292
296
|
# Get the $set operations or intialize a new one.
|
data/lib/mongoid/composable.rb
CHANGED
@@ -106,10 +106,10 @@ module Mongoid
|
|
106
106
|
view.update_many("$push" => collect_operations(pushes))
|
107
107
|
end
|
108
108
|
|
109
|
-
# Perform an atomic $
|
109
|
+
# Perform an atomic $push/$each operation on the matching documents.
|
110
110
|
#
|
111
111
|
# @example Push the values to the matching docs.
|
112
|
-
# context.
|
112
|
+
# context.push_all(members: [ "Alan", "Fletch" ])
|
113
113
|
#
|
114
114
|
# @param [ Hash ] pushes The operations.
|
115
115
|
#
|
@@ -117,7 +117,10 @@ module Mongoid
|
|
117
117
|
#
|
118
118
|
# @since 3.0.0
|
119
119
|
def push_all(pushes)
|
120
|
-
|
120
|
+
push_each_updates = collect_operations(pushes).each.inject({}) do |ops, (field, elements)|
|
121
|
+
ops.merge!(field => {'$each' => elements})
|
122
|
+
end
|
123
|
+
view.update_many("$push" => push_each_updates)
|
121
124
|
end
|
122
125
|
|
123
126
|
# Perform an atomic $rename of fields on the matching documents.
|
@@ -486,12 +486,16 @@ module Mongoid
|
|
486
486
|
# context.update({ "$set" => { name: "Smiths" }})
|
487
487
|
#
|
488
488
|
# @param [ Hash ] attributes The new attributes for the document.
|
489
|
+
# @param [ Hash ] opts The update operation options.
|
490
|
+
#
|
491
|
+
# @option opts [ Array ] :array_filters A set of filters specifying to which array elements
|
492
|
+
# an update should apply.
|
489
493
|
#
|
490
494
|
# @return [ nil, false ] False if no attributes were provided.
|
491
495
|
#
|
492
496
|
# @since 3.0.0
|
493
|
-
def update(attributes = nil)
|
494
|
-
update_documents(attributes)
|
497
|
+
def update(attributes = nil, opts = {})
|
498
|
+
update_documents(attributes, :update_one, opts)
|
495
499
|
end
|
496
500
|
|
497
501
|
# Update all the matching documents atomically.
|
@@ -500,12 +504,16 @@ module Mongoid
|
|
500
504
|
# context.update_all({ "$set" => { name: "Smiths" }})
|
501
505
|
#
|
502
506
|
# @param [ Hash ] attributes The new attributes for each document.
|
507
|
+
# @param [ Hash ] opts The update operation options.
|
508
|
+
#
|
509
|
+
# @option opts [ Array ] :array_filters A set of filters specifying to which array elements
|
510
|
+
# an update should apply.
|
503
511
|
#
|
504
512
|
# @return [ nil, false ] False if no attributes were provided.
|
505
513
|
#
|
506
514
|
# @since 3.0.0
|
507
|
-
def update_all(attributes = nil)
|
508
|
-
update_documents(attributes, :update_many)
|
515
|
+
def update_all(attributes = nil, opts = {})
|
516
|
+
update_documents(attributes, :update_many, opts)
|
509
517
|
end
|
510
518
|
|
511
519
|
private
|
@@ -541,10 +549,10 @@ module Mongoid
|
|
541
549
|
# @return [ true, false ] If the update succeeded.
|
542
550
|
#
|
543
551
|
# @since 3.0.4
|
544
|
-
def update_documents(attributes, method = :update_one)
|
552
|
+
def update_documents(attributes, method = :update_one, opts = {})
|
545
553
|
return false unless attributes
|
546
554
|
attributes = Hash[attributes.map { |k, v| [klass.database_field_name(k.to_s), v] }]
|
547
|
-
view.send(method, attributes.__consolidate__(klass))
|
555
|
+
view.send(method, attributes.__consolidate__(klass), opts)
|
548
556
|
end
|
549
557
|
|
550
558
|
# Apply the field limitations.
|
data/lib/mongoid/factory.rb
CHANGED
@@ -17,7 +17,8 @@ module Mongoid
|
|
17
17
|
#
|
18
18
|
# @return [ Document ] The instantiated document.
|
19
19
|
def build(klass, attributes = nil)
|
20
|
-
|
20
|
+
attributes ||= {}
|
21
|
+
type = attributes[TYPE] || attributes[TYPE.to_sym]
|
21
22
|
if type && klass._types.include?(type)
|
22
23
|
type.constantize.new(attributes)
|
23
24
|
else
|
@@ -195,10 +195,10 @@ module Mongoid
|
|
195
195
|
Thread.current["[mongoid][#{object.object_id}]:context"]
|
196
196
|
end
|
197
197
|
|
198
|
-
#
|
198
|
+
# Clear the persistence context for a particular class or model instance.
|
199
199
|
#
|
200
|
-
# @example
|
201
|
-
# PersistenceContext.
|
200
|
+
# @example Clear the persistence context for a class or model instance.
|
201
|
+
# PersistenceContext.clear(model)
|
202
202
|
#
|
203
203
|
# @param [ Class, Object ] object The class or model instance.
|
204
204
|
# @param [ Mongo::Cluster ] cluster The original cluster before this context was used.
|
@@ -208,8 +208,9 @@ module Mongoid
|
|
208
208
|
if context = get(object)
|
209
209
|
context.client.close unless (context.cluster.equal?(cluster) || cluster.nil?)
|
210
210
|
end
|
211
|
+
ensure
|
211
212
|
Thread.current["[mongoid][#{object.object_id}]:context"] = nil
|
212
213
|
end
|
213
214
|
end
|
214
215
|
end
|
215
|
-
end
|
216
|
+
end
|
data/lib/mongoid/query_cache.rb
CHANGED
@@ -222,9 +222,11 @@ module Mongoid
|
|
222
222
|
super
|
223
223
|
else
|
224
224
|
unless cursor = cached_cursor
|
225
|
-
|
226
|
-
|
227
|
-
|
225
|
+
read_with_retry do
|
226
|
+
server = server_selector.select_server(cluster)
|
227
|
+
cursor = CachedCursor.new(view, send_initial_query(server), server)
|
228
|
+
QueryCache.cache_table[cache_key] = cursor
|
229
|
+
end
|
228
230
|
end
|
229
231
|
cursor.each do |doc|
|
230
232
|
yield doc
|
@@ -8,7 +8,7 @@ module Mongoid
|
|
8
8
|
module Batchable
|
9
9
|
include Positional
|
10
10
|
|
11
|
-
# Insert new documents as a batch push ($
|
11
|
+
# Insert new documents as a batch push ($push with $each). This ensures that
|
12
12
|
# all callbacks are run at the appropriate time and only 1 request is
|
13
13
|
# made to the database.
|
14
14
|
#
|
@@ -21,7 +21,7 @@ module Mongoid
|
|
21
21
|
#
|
22
22
|
# @since 3.0.0
|
23
23
|
def batch_insert(docs)
|
24
|
-
|
24
|
+
execute_batch_push(docs)
|
25
25
|
end
|
26
26
|
|
27
27
|
# Clear all of the docs out of the relation in a single swipe.
|
@@ -89,7 +89,7 @@ module Mongoid
|
|
89
89
|
base.delayed_atomic_sets.clear unless _assigning?
|
90
90
|
docs = normalize_docs(docs).compact
|
91
91
|
target.clear and _unscoped.clear
|
92
|
-
inserts =
|
92
|
+
inserts = execute_batch_set(docs)
|
93
93
|
add_atomic_sets(inserts)
|
94
94
|
end
|
95
95
|
end
|
@@ -116,32 +116,52 @@ module Mongoid
|
|
116
116
|
end
|
117
117
|
end
|
118
118
|
|
119
|
-
# Perform a batch persist of the provided documents with
|
120
|
-
# operation.
|
119
|
+
# Perform a batch persist of the provided documents with a $set.
|
121
120
|
#
|
122
121
|
# @api private
|
123
122
|
#
|
124
|
-
|
125
|
-
# batchable.
|
123
|
+
#@example Perform a batch $set.
|
124
|
+
# batchable.execute_batch_set(docs)
|
126
125
|
#
|
127
126
|
# @param [ Array<Document> ] docs The docs to persist.
|
128
|
-
# @param [ String ] operation The atomic operation.
|
129
127
|
#
|
130
128
|
# @return [ Array<Hash> ] The inserts.
|
131
129
|
#
|
132
|
-
# @since
|
133
|
-
def
|
130
|
+
# @since 7.0.0
|
131
|
+
def execute_batch_set(docs)
|
134
132
|
self.inserts_valid = true
|
135
133
|
inserts = pre_process_batch_insert(docs)
|
136
134
|
if insertable?
|
137
135
|
collection.find(selector).update_one(
|
138
|
-
|
139
|
-
)
|
136
|
+
positionally(selector, '$set' => { path => inserts }))
|
140
137
|
post_process_batch_insert(docs)
|
141
138
|
end
|
142
139
|
inserts
|
143
140
|
end
|
144
141
|
|
142
|
+
# Perform a batch persist of the provided documents with $push and $each.
|
143
|
+
#
|
144
|
+
# @api private
|
145
|
+
#
|
146
|
+
# @example Perform a batch push.
|
147
|
+
# batchable.execute_batch_push(docs)
|
148
|
+
#
|
149
|
+
# @param [ Array<Document> ] docs The docs to persist.
|
150
|
+
#
|
151
|
+
# @return [ Array<Hash> ] The inserts.
|
152
|
+
#
|
153
|
+
# @since 7.0.0
|
154
|
+
def execute_batch_push(docs)
|
155
|
+
self.inserts_valid = true
|
156
|
+
pushes = pre_process_batch_insert(docs)
|
157
|
+
if insertable?
|
158
|
+
collection.find(selector).update_one(
|
159
|
+
positionally(selector, '$push' => { path => { '$each' => pushes } }))
|
160
|
+
post_process_batch_insert(docs)
|
161
|
+
end
|
162
|
+
pushes
|
163
|
+
end
|
164
|
+
|
145
165
|
# Are we in a state to be able to batch insert?
|
146
166
|
#
|
147
167
|
# @api private
|
@@ -81,7 +81,7 @@ module Mongoid
|
|
81
81
|
adds, subs = new - (old || []), (old || []) - new
|
82
82
|
|
83
83
|
# If we are autosaving we don't want a duplicate to get added - the
|
84
|
-
# $addToSet would run previously and then the $
|
84
|
+
# $addToSet would run previously and then the $push and $each from the
|
85
85
|
# inverse on the autosave would cause this. We delete each id from
|
86
86
|
# what's in memory in case a mix of id addition and object addition
|
87
87
|
# had occurred.
|
@@ -214,12 +214,22 @@ module Mongoid
|
|
214
214
|
# @example Get the first document.
|
215
215
|
# enumerable.first
|
216
216
|
#
|
217
|
+
# @note Automatically adding a sort on _id when no other sort is
|
218
|
+
# defined on the criteria has the potential to cause bad performance issues.
|
219
|
+
# If you experience unexpected poor performance when using #first or #last,
|
220
|
+
# use the option { id_sort: :none }.
|
221
|
+
# Be aware that #first/#last won't guarantee order in this case.
|
222
|
+
#
|
223
|
+
# @param [ Hash ] opts The options for the query returning the first document.
|
224
|
+
#
|
225
|
+
# @option opts [ :none ] :id_sort Don't apply a sort on _id.
|
226
|
+
#
|
217
227
|
# @return [ Document ] The first document found.
|
218
228
|
#
|
219
229
|
# @since 2.1.0
|
220
|
-
def first
|
230
|
+
def first(opts = {})
|
221
231
|
_loaded.try(:values).try(:first) ||
|
222
|
-
_added[(ul = _unloaded.try(:first)).try(:id)] ||
|
232
|
+
_added[(ul = _unloaded.try(:first, opts)).try(:id)] ||
|
223
233
|
ul ||
|
224
234
|
_added.values.try(:first)
|
225
235
|
end
|
@@ -298,13 +308,23 @@ module Mongoid
|
|
298
308
|
# @example Get the last document.
|
299
309
|
# enumerable.last
|
300
310
|
#
|
311
|
+
# @note Automatically adding a sort on _id when no other sort is
|
312
|
+
# defined on the criteria has the potential to cause bad performance issues.
|
313
|
+
# If you experience unexpected poor performance when using #first or #last,
|
314
|
+
# use the option { id_sort: :none }.
|
315
|
+
# Be aware that #first/#last won't guarantee order in this case.
|
316
|
+
#
|
317
|
+
# @param [ Hash ] opts The options for the query returning the first document.
|
318
|
+
#
|
319
|
+
# @option opts [ :none ] :id_sort Don't apply a sort on _id.
|
320
|
+
#
|
301
321
|
# @return [ Document ] The last document found.
|
302
322
|
#
|
303
323
|
# @since 2.1.0
|
304
|
-
def last
|
324
|
+
def last(opts = {})
|
305
325
|
_added.values.try(:last) ||
|
306
326
|
_loaded.try(:values).try(:last) ||
|
307
|
-
_added[(ul = _unloaded.try(:last)).try(:id)] ||
|
327
|
+
_added[(ul = _unloaded.try(:last, opts)).try(:id)] ||
|
308
328
|
ul
|
309
329
|
end
|
310
330
|
|
data/lib/mongoid/version.rb
CHANGED
data/spec/app/models/band.rb
CHANGED
@@ -20,6 +20,7 @@ class Band
|
|
20
20
|
|
21
21
|
embeds_many :records, cascade_callbacks: true
|
22
22
|
embeds_many :notes, as: :noteable, cascade_callbacks: true, validate: false
|
23
|
+
embeds_many :labels
|
23
24
|
embeds_one :label, cascade_callbacks: true
|
24
25
|
|
25
26
|
has_many :same_name, class_name: 'Agent', inverse_of: :same_name
|
@@ -211,10 +211,10 @@ describe Mongoid::Atomic::Modifiers do
|
|
211
211
|
|
212
212
|
it "adds the push all modifiers" do
|
213
213
|
expect(modifiers).to eq(
|
214
|
-
{ "$
|
215
|
-
|
214
|
+
{ "$push" =>
|
215
|
+
{ "addresses" => { '$each' => [
|
216
216
|
{ "street" => "Oxford St" }
|
217
|
-
]
|
217
|
+
] }
|
218
218
|
}
|
219
219
|
}
|
220
220
|
)
|
@@ -238,11 +238,11 @@ describe Mongoid::Atomic::Modifiers do
|
|
238
238
|
|
239
239
|
it "adds the push all modifiers" do
|
240
240
|
expect(modifiers).to eq(
|
241
|
-
{ "$
|
242
|
-
{ "addresses" => [
|
241
|
+
{ "$push" =>
|
242
|
+
{ "addresses" => { '$each' => [
|
243
243
|
{ "street" => "Hobrechtstr." },
|
244
244
|
{ "street" => "Pflugerstr." }
|
245
|
-
]
|
245
|
+
] }
|
246
246
|
}
|
247
247
|
}
|
248
248
|
)
|
@@ -270,10 +270,10 @@ describe Mongoid::Atomic::Modifiers do
|
|
270
270
|
it "adds the push all modifiers to the conflicts hash" do
|
271
271
|
expect(modifiers).to eq(
|
272
272
|
{ "$set" => { "addresses.0.street" => "Bond" },
|
273
|
-
conflicts: { "$
|
274
|
-
{ "addresses" => [
|
273
|
+
conflicts: { "$push" =>
|
274
|
+
{ "addresses" => { '$each' => [
|
275
275
|
{ "street" => "Oxford St" }
|
276
|
-
]
|
276
|
+
] }
|
277
277
|
}
|
278
278
|
}
|
279
279
|
}
|
@@ -300,10 +300,10 @@ describe Mongoid::Atomic::Modifiers do
|
|
300
300
|
expect(modifiers).to eq(
|
301
301
|
{ "$pullAll" => {
|
302
302
|
"addresses" => { "street" => "Bond St" }},
|
303
|
-
conflicts: { "$
|
304
|
-
{ "addresses" => [
|
303
|
+
conflicts: { "$push" =>
|
304
|
+
{ "addresses" => { '$each' => [
|
305
305
|
{ "street" => "Oxford St" }
|
306
|
-
]
|
306
|
+
] }
|
307
307
|
}
|
308
308
|
}
|
309
309
|
}
|
@@ -328,12 +328,12 @@ describe Mongoid::Atomic::Modifiers do
|
|
328
328
|
|
329
329
|
it "adds the push all modifiers to the conflicts hash" do
|
330
330
|
expect(modifiers).to eq(
|
331
|
-
{ "$
|
332
|
-
"addresses.0.locations" => [{ "street" => "Bond St" }]},
|
333
|
-
conflicts: { "$
|
334
|
-
{ "addresses" => [
|
331
|
+
{ "$push" => {
|
332
|
+
"addresses.0.locations" => { '$each' => [{ "street" => "Bond St" }] } },
|
333
|
+
conflicts: { "$push" =>
|
334
|
+
{ "addresses" => { '$each' => [
|
335
335
|
{ "street" => "Oxford St" }
|
336
|
-
]
|
336
|
+
] }
|
337
337
|
}
|
338
338
|
}
|
339
339
|
}
|