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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e3c168797ecc312fa19fb9e5e411faac9d8d0386
4
- data.tar.gz: d8221f9f5edf4199630a5951169150ed864830af
3
+ metadata.gz: 5c7e1fbb3fda280fb0e0f74c312b36b7a73dad79
4
+ data.tar.gz: 92dcab3023e9005560efd4209e3eecd26032b259
5
5
  SHA512:
6
- metadata.gz: 8f7acb7b8783289ff4a2986353e4eeb0443643d4b957ed15752a37045a7e906bda3cb5cc5ebf3d75c222ce8926aee29176b38cab2baad80e663fc83eb0bb1b02
7
- data.tar.gz: 45304b581fdcca4076ce109db08926de9e30917f9ac439f94b2bd51fbfe3939d32dce787f48236738cd015c0c0b2e90c7d68905dd5744b08ec33adb3a8ccaae2
6
+ metadata.gz: 44e65ba1446fc7c42e545b38223d4122e798f85d26aeb93103b85c45e7a4abc17e3b7da9f60853a7a38a24b5d4a258338111759d0b22bb4e5f99611e002eaa0f
7
+ data.tar.gz: 25b84f09ac4fb6366a0d9782d0865a0a1ae214234fbdbde4ce57146d8bf740823b66f15d4871e4a45b0d3fc5f0557b9f91dd743501713ae6920a430e90bab62e
@@ -1,2 +1,3 @@
1
- y~zL�|tT��נq'��`�B~gg�%�U�&?U�Ů�;����@nWɞ����H����ۄ�\{6�!$u�42{�8�GC���W�Q8����9�]�c~+,*�V{{��@=*ȴ��7�$_b���2�`���dQ7���#-g�**w�v����7���૏~��Q�?�A���;^IԪFN�ARm?��)7�����1��Y�
2
- �Ċ�;]����%D������y:<H����/�PTu�,O%�s��1��Dۯ
1
+ kpQ5NePGlt
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
- �v��qz�G�"�:�~�,X�{h�;(�!�E2�Ç ����ct�W�^G�%@ ��Y�ª�e֚�=~m�/�(� �"��6ɯ��%|vC$��u�����/'΃!�86���'{n!h6�:��טr)!Aޜk�������nw}�{*�ٰ��G�#�>�X��#ӝM�?d�1;>�� "$�����p긚]����}k�� U���9�P����H~R���)�jHUK�HQ�0}��
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-+\��
@@ -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 $pushAll, for example) conflict if:
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 $pushAll
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 $pushAll operations.
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
- value.each do |val|
122
- mods[field].push(val)
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["$pushAll"] ||= {}
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 $pushAll operations or intialize a new one.
284
+ # Get the $push/$each operations or initialize a new one.
281
285
  #
282
- # @example Get the $pushAll operations.
286
+ # @example Get the $push/$each operations.
283
287
  # modifiers.pushes
284
288
  #
285
- # @return [ Hash ] The $pushAll operations.
289
+ # @return [ Hash ] The $push/$each operations.
286
290
  #
287
291
  # @since 2.1.0
288
292
  def pushes
289
- self["$pushAll"] ||= {}
293
+ self["$push"] ||= {}
290
294
  end
291
295
 
292
296
  # Get the $set operations or intialize a new one.
@@ -84,6 +84,7 @@ module Mongoid
84
84
  Validatable,
85
85
  Equality,
86
86
  Relations::Synchronization,
87
+ Relations::Macros,
87
88
  ActiveModel::Model,
88
89
  ActiveModel::Validations
89
90
  ]
@@ -106,10 +106,10 @@ module Mongoid
106
106
  view.update_many("$push" => collect_operations(pushes))
107
107
  end
108
108
 
109
- # Perform an atomic $pushAll operation on the matching documents.
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.push(members: [ "Alan", "Fletch" ])
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
- view.update_many("$pushAll" => collect_operations(pushes))
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.
@@ -17,7 +17,8 @@ module Mongoid
17
17
  #
18
18
  # @return [ Document ] The instantiated document.
19
19
  def build(klass, attributes = nil)
20
- type = (attributes || {})[TYPE]
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
- # Get the persistence context for a particular class or model instance.
198
+ # Clear the persistence context for a particular class or model instance.
199
199
  #
200
- # @example Get the persistence context for a class or model instance.
201
- # PersistenceContext.get(model)
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
@@ -222,9 +222,11 @@ module Mongoid
222
222
  super
223
223
  else
224
224
  unless cursor = cached_cursor
225
- server = read.select_server(cluster)
226
- cursor = CachedCursor.new(view, send_initial_query(server), server)
227
- QueryCache.cache_table[cache_key] = cursor
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 ($pushAll). This ensures that
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
- execute_batch_insert(docs, "$pushAll")
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 = execute_batch_insert(docs, "$set")
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 the supplied
120
- # operation.
119
+ # Perform a batch persist of the provided documents with a $set.
121
120
  #
122
121
  # @api private
123
122
  #
124
- # @example Perform a batch operation.
125
- # batchable.execute_batch(docs, "$set")
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 3.0.0
133
- def execute_batch_insert(docs, operation)
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
- positionally(selector, operation => { path => inserts })
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 $pushAll from 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
 
@@ -1,4 +1,4 @@
1
1
  # encoding: utf-8
2
2
  module Mongoid
3
- VERSION = "6.2.1"
3
+ VERSION = "6.3.0"
4
4
  end
@@ -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
- { "$pushAll" =>
215
- { "addresses" => [
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
- { "$pushAll" =>
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: { "$pushAll" =>
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: { "$pushAll" =>
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
- { "$pushAll" => {
332
- "addresses.0.locations" => [{ "street" => "Bond St" }]},
333
- conflicts: { "$pushAll" =>
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
  }