mongoid 7.5.0 → 7.5.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 32597c6d6b536f273850be1989db0d876026d2bffda067d7923f173c3966faa6
4
- data.tar.gz: 97fffa62c90ae5c20e7dcf00eb151b557c26ab5ae676c45b5651efa5143cf34c
3
+ metadata.gz: e67e9eccd518e5c987bbca2d4943a461d7ceaf382abd091842806fb300dffb1e
4
+ data.tar.gz: 441f04f551b51c8b5f3300e4158fd7d0b6b0c3406b39dfa073bf1ce11cead324
5
5
  SHA512:
6
- metadata.gz: dbe0c003a7e058f5ab6ac5592170ef1a26e02bf9be729b889c55a3a70af4e0c8b6e52f7157cc9b40879545689972769bae5deabf6814ce1ebeb97fdf1a128212
7
- data.tar.gz: d696cd95560d51b34318e7f25467450dde8461383dd17830f1177363cbf006c863b1268a2b79616e563343a3fd0e388c9d3bde67821b698b4cf0035bbfc9b719
6
+ metadata.gz: 31d1d76cbe4923b0cb2a54a62d3758183a80ef8c8833448760115d2299153724e8cb2e6160745989357f6a4bbd3e6873380e73f500e13ffb14b307dfa503a3a9
7
+ data.tar.gz: 9c3acad387939c0bfe4746102e73e24124597bf311adbd3ce301bfe9a6882a066dadbb67ccb05a470a983c6b0d55ca43cce01f247111cd9d64efb2653614fbd8
checksums.yaml.gz.sig CHANGED
Binary file
@@ -15,7 +15,7 @@ module Mongoid
15
15
  # plural model name.
16
16
  #
17
17
  # If new_record? - will append /new
18
- # If not - will append /id-updated_at.to_s(cache_timestamp_format)
18
+ # If not - will append /id-updated_at.to_formatted_s(cache_timestamp_format)
19
19
  # Without updated_at - will append /id
20
20
  #
21
21
  # This is usually called inside a cache() block
@@ -26,7 +26,7 @@ module Mongoid
26
26
  # @return [ String ] the string with or without updated_at
27
27
  def cache_key
28
28
  return "#{model_key}/new" if new_record?
29
- return "#{model_key}/#{_id}-#{updated_at.utc.to_s(cache_timestamp_format)}" if do_or_do_not(:updated_at)
29
+ return "#{model_key}/#{_id}-#{updated_at.utc.to_formatted_s(cache_timestamp_format)}" if do_or_do_not(:updated_at)
30
30
  "#{model_key}/#{_id}"
31
31
  end
32
32
  end
@@ -116,6 +116,12 @@ module Mongoid
116
116
  # using and's instead of overwriting them.
117
117
  option :overwrite_chained_operators, default: true
118
118
 
119
+ # When this flag is true, the attributes method on a document will return
120
+ # a BSON::Document when that document is retrieved from the database, and
121
+ # a Hash otherwise. When this flag is false, the attributes method will
122
+ # always return a Hash.
123
+ option :legacy_attributes, default: true
124
+
119
125
  # Has Mongoid been configured? This is checking that at least a valid
120
126
  # client config exists.
121
127
  #
@@ -277,8 +277,15 @@ module Mongoid
277
277
  # criteria.
278
278
  #
279
279
  # @return [ Document ] A new document.
280
+ #
281
+ # @api private
280
282
  def instantiate(attrs = nil, selected_fields = nil)
281
- attributes = attrs || {}
283
+ attributes = if Mongoid.legacy_attributes
284
+ attrs
285
+ else
286
+ attrs&.to_h
287
+ end || {}
288
+
282
289
  doc = allocate
283
290
  doc.__selected_fields = selected_fields
284
291
  doc.instance_variable_set(:@attributes, attributes)
@@ -44,9 +44,9 @@ module Mongoid
44
44
  # @return [ true, false ] True if the classes are equal, false if not.
45
45
  def ===(other)
46
46
  if Mongoid.legacy_triple_equals
47
- super
48
- else
49
47
  other.class == Class ? self.class === other : self == other
48
+ else
49
+ super
50
50
  end
51
51
  end
52
52
 
@@ -73,9 +73,9 @@ module Mongoid
73
73
  # @return [ true, false ] True if the classes are equal, false if not.
74
74
  def ===(other)
75
75
  if Mongoid.legacy_triple_equals
76
- other.is_a?(self)
77
- else
78
76
  other.class == Class ? self <= other : other.is_a?(self)
77
+ else
78
+ other.is_a?(self)
79
79
  end
80
80
  end
81
81
  end
@@ -122,6 +122,21 @@ module Mongoid
122
122
  options == other.options
123
123
  end
124
124
 
125
+ # Whether the client of the context can be reused later, and therefore should
126
+ # not be closed.
127
+ #
128
+ # If the persistence context is requested with :client option only, it means
129
+ # that the context should use a client configured in mongoid.yml.
130
+ # Such clients should not be closed when the context is cleared since they
131
+ # will be reused later.
132
+ #
133
+ # @return [ true | false ] True if client can be reused, otherwise false.
134
+ #
135
+ # @api private
136
+ def reusable_client?
137
+ @options.keys == [:client]
138
+ end
139
+
125
140
  private
126
141
 
127
142
  def set_options!(opts)
@@ -172,8 +187,7 @@ module Mongoid
172
187
  #
173
188
  # @return [ Mongoid::PersistenceContext ] The persistence context for the object.
174
189
  def set(object, options_or_context)
175
- key = "[mongoid][#{object.object_id}]:context"
176
- existing_context = Thread.current[key]
190
+ existing_context = get_context(object)
177
191
  existing_options = if existing_context
178
192
  existing_context.options
179
193
  else
@@ -184,7 +198,7 @@ module Mongoid
184
198
  end
185
199
  new_options = existing_options.merge(options_or_context)
186
200
  context = PersistenceContext.new(object, new_options)
187
- Thread.current[key] = context
201
+ store_context(object, context)
188
202
  end
189
203
 
190
204
  # Get the persistence context for a particular class or model instance.
@@ -196,7 +210,7 @@ module Mongoid
196
210
  #
197
211
  # @return [ Mongoid::PersistenceContext ] The persistence context for the object.
198
212
  def get(object)
199
- Thread.current["[mongoid][#{object.object_id}]:context"]
213
+ get_context(object)
200
214
  end
201
215
 
202
216
  # Clear the persistence context for a particular class or model instance.
@@ -211,11 +225,48 @@ module Mongoid
211
225
  def clear(object, cluster = nil, original_context = nil)
212
226
  if context = get(object)
213
227
  unless cluster.nil? || context.cluster.equal?(cluster)
214
- context.client.close
228
+ context.client.close unless context.reusable_client?
215
229
  end
216
230
  end
217
231
  ensure
218
- Thread.current["[mongoid][#{object.object_id}]:context"] = original_context
232
+ store_context(object, original_context)
233
+ end
234
+
235
+ private
236
+
237
+ # Key to store persistence contexts in the thread local storage.
238
+ #
239
+ # @api private
240
+ PERSISTENCE_CONTEXT_KEY = :"[mongoid]:persistence_context"
241
+
242
+ # Get the persistence context for a given object from the thread local
243
+ # storage.
244
+ #
245
+ # @param [ Object ] object Object to get the persistance context for.
246
+ #
247
+ # @return [ Mongoid::PersistenceContext | nil ] The persistence context
248
+ # for the object if previously stored, otherwise nil.
249
+ #
250
+ # @api private
251
+ def get_context(object)
252
+ Thread.current[PERSISTENCE_CONTEXT_KEY] ||= {}
253
+ Thread.current[PERSISTENCE_CONTEXT_KEY][object.object_id]
254
+ end
255
+
256
+ # Store persistence context for a given object in the thread local
257
+ # storage.
258
+ #
259
+ # @param [ Object ] object Object to store the persistance context for.
260
+ # @param [ Mongoid::PersistenceContext ] context Context to store
261
+ #
262
+ # @api private
263
+ def store_context(object, context)
264
+ if context.nil?
265
+ Thread.current[PERSISTENCE_CONTEXT_KEY]&.delete(object.object_id)
266
+ else
267
+ Thread.current[PERSISTENCE_CONTEXT_KEY] ||= {}
268
+ Thread.current[PERSISTENCE_CONTEXT_KEY][object.object_id] = context
269
+ end
219
270
  end
220
271
  end
221
272
  end
@@ -289,15 +289,17 @@ module Mongoid
289
289
  # @return [ Method ] The defined method.
290
290
  def define_scope_method(name)
291
291
  singleton_class.class_eval do
292
- define_method(name) do |*args|
293
- scoping = _declared_scopes[name]
294
- scope = instance_exec(*args, &scoping[:scope])
295
- extension = scoping[:extension]
296
- to_merge = scope || queryable
297
- criteria = to_merge.empty_and_chainable? ? to_merge : with_default_scope.merge(to_merge)
298
- criteria.extend(extension)
299
- criteria
300
- end
292
+ ruby2_keywords(
293
+ define_method(name) do |*args|
294
+ scoping = _declared_scopes[name]
295
+ scope = instance_exec(*args, &scoping[:scope])
296
+ extension = scoping[:extension]
297
+ to_merge = scope || queryable
298
+ criteria = to_merge.empty_and_chainable? ? to_merge : with_default_scope.merge(to_merge)
299
+ criteria.extend(extension)
300
+ criteria
301
+ end
302
+ )
301
303
  end
302
304
  end
303
305
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mongoid
4
- VERSION = "7.5.0"
4
+ VERSION = "7.5.2"
5
5
  end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "spec_helper"
4
+ require_relative "../has_and_belongs_to_many_models.rb"
4
5
 
5
6
  describe Mongoid::Association::Referenced::HasAndBelongsToMany::Proxy do
6
7
 
@@ -3770,4 +3771,33 @@ describe Mongoid::Association::Referenced::HasAndBelongsToMany::Proxy do
3770
3771
  expect(p2.d_ids).to match_array([d2.id])
3771
3772
  end
3772
3773
  end
3774
+
3775
+ # This test is for MONGOID-5344 which tests that the initial call to
3776
+ # signature_ids refers to the same array as subsequent calls to signature_ids.
3777
+ # Prior to the change in that ticket, this test broke because the array
3778
+ # returned from write_attribute (which is triggered the first time the
3779
+ # foreign key array is referenced, to set the default), refers to a different
3780
+ # array to the one stored in the attributes hash. This happened because,
3781
+ # when retrieving a document from the database, the attributes hash is actually
3782
+ # a BSON::Document, which applies a transformation to the array before
3783
+ # storing it.
3784
+ context "when executing concat on foreign key array from the db" do
3785
+ config_override :legacy_attributes, false
3786
+
3787
+ before do
3788
+ HabtmmContract.create!
3789
+ HabtmmSignature.create!
3790
+ end
3791
+
3792
+ let!(:contract) { HabtmmContract.first }
3793
+ let!(:signature) { HabtmmSignature.first }
3794
+
3795
+ before do
3796
+ contract.signature_ids.concat([signature.id])
3797
+ end
3798
+
3799
+ it "works on the first attempt" do
3800
+ expect(contract.signature_ids).to eq([signature.id])
3801
+ end
3802
+ end
3773
3803
  end
@@ -4089,4 +4089,24 @@ describe Mongoid::Association::Referenced::HasMany::Proxy do
4089
4089
  expect(band.same_name).to eq([agent])
4090
4090
  end
4091
4091
  end
4092
+
4093
+ context "when executing concat on foreign key array from the db" do
4094
+ config_override :legacy_attributes, false
4095
+
4096
+ before do
4097
+ Agent.create!
4098
+ Basic.create!
4099
+ end
4100
+
4101
+ let!(:agent) { Agent.first }
4102
+ let!(:basic) { Basic.first }
4103
+
4104
+ before do
4105
+ agent.basic_ids.concat([basic.id])
4106
+ end
4107
+
4108
+ it "works on the first attempt" do
4109
+ expect(agent.basic_ids).to eq([basic.id])
4110
+ end
4111
+ end
4092
4112
  end
@@ -1675,6 +1675,50 @@ describe Mongoid::Attributes do
1675
1675
  end
1676
1676
  end
1677
1677
  end
1678
+
1679
+ context "when comparing the object_ids of the written value" do
1680
+ config_override :legacy_attributes, false
1681
+
1682
+ before do
1683
+ Person.create!
1684
+ end
1685
+
1686
+ let(:person) do
1687
+ Person.first
1688
+ end
1689
+
1690
+ context "when the field is not resizable" do
1691
+ let(:test) do
1692
+ person.write_attribute(:test, "aliased field to test")
1693
+ end
1694
+
1695
+ it "has the same object_id as the attributes hash value" do
1696
+ expect(test.object_id).to eq(person.test.object_id)
1697
+ end
1698
+ end
1699
+
1700
+ context "when the field is resizable" do
1701
+
1702
+ let(:arrays) do
1703
+ person.write_attribute(:arrays, [])
1704
+ end
1705
+
1706
+ it "has the same object_id as the attributes hash value" do
1707
+ expect(arrays.object_id).to eq(person.arrays.object_id)
1708
+ end
1709
+ end
1710
+
1711
+ context "when the field is a HABTM foreign key array" do
1712
+
1713
+ let(:preference_ids) do
1714
+ person.write_attribute(:preference_ids, [])
1715
+ end
1716
+
1717
+ it "has the same object_id as the attributes hash value" do
1718
+ expect(preference_ids.object_id).to eq(person.preference_ids.object_id)
1719
+ end
1720
+ end
1721
+ end
1678
1722
  end
1679
1723
 
1680
1724
  describe "#typed_value_for" do
@@ -45,7 +45,7 @@ describe Mongoid::Cacheable do
45
45
  context "with the default cache_timestamp_format" do
46
46
 
47
47
  let!(:updated_at) do
48
- document.updated_at.utc.to_s(:nsec)
48
+ document.updated_at.utc.to_formatted_s(:nsec)
49
49
  end
50
50
 
51
51
  it "has the id and updated_at key name" do
@@ -64,7 +64,7 @@ describe Mongoid::Cacheable do
64
64
  end
65
65
 
66
66
  let!(:updated_at) do
67
- document.updated_at.utc.to_s(:number)
67
+ document.updated_at.utc.to_formatted_s(:number)
68
68
  end
69
69
 
70
70
  it "has the id and updated_at key name" do
@@ -103,7 +103,7 @@ describe Mongoid::Cacheable do
103
103
  end
104
104
 
105
105
  let!(:updated_at) do
106
- agent.updated_at.utc.to_s(:nsec)
106
+ agent.updated_at.utc.to_formatted_s(:nsec)
107
107
  end
108
108
 
109
109
  it "has the id and updated_at key name" do
@@ -1012,6 +1012,36 @@ describe Mongoid::Clients do
1012
1012
  end
1013
1013
  end
1014
1014
  end
1015
+
1016
+ context 'when requesting named client' do
1017
+ let(:secondary_client) do
1018
+ double(Mongo::Client).tap do |client|
1019
+ allow(client).to receive(:cluster).and_return(double("cluster"))
1020
+ end
1021
+ end
1022
+
1023
+ before do
1024
+ expect(Mongoid::Clients::Factory).to receive(:create)
1025
+ .with(:secondary)
1026
+ .and_return(secondary_client)
1027
+ end
1028
+
1029
+ after do
1030
+ Mongoid::Clients.clients.delete(:secondary)
1031
+ end
1032
+
1033
+ it 'does not close the client' do
1034
+ expect(secondary_client).not_to receive(:close)
1035
+
1036
+ Band.with(client: :default) do |klass|
1037
+ klass.mongo_client
1038
+ end
1039
+
1040
+ Band.with(client: :secondary) do |klass|
1041
+ klass.mongo_client
1042
+ end
1043
+ end
1044
+ end
1015
1045
  end
1016
1046
 
1017
1047
  context "when overriding the default database" do
@@ -335,6 +335,13 @@ describe Mongoid::Config do
335
335
  it_behaves_like "a config option"
336
336
  end
337
337
 
338
+ context 'when setting the legacy_attributes option in the config' do
339
+ let(:option) { :legacy_attributes }
340
+ let(:default) { true }
341
+
342
+ it_behaves_like "a config option"
343
+ end
344
+
338
345
  describe "#load!" do
339
346
 
340
347
  before(:all) do
@@ -85,8 +85,8 @@ describe Mongoid::Equality do
85
85
 
86
86
  describe ".===" do
87
87
 
88
- context "when legacy_triple_equals is set" do
89
- config_override :legacy_triple_equals, true
88
+ context "when legacy_triple_equals is not set" do
89
+ config_override :legacy_triple_equals, false
90
90
 
91
91
  context "when comparable is an instance of this document" do
92
92
 
@@ -128,8 +128,8 @@ describe Mongoid::Equality do
128
128
  end
129
129
  end
130
130
 
131
- context "when legacy_triple_equals is not set" do
132
- config_override :legacy_triple_equals, false
131
+ context "when legacy_triple_equals is set" do
132
+ config_override :legacy_triple_equals, true
133
133
 
134
134
  context "when comparable is an instance of this document" do
135
135
 
@@ -205,8 +205,8 @@ describe Mongoid::Equality do
205
205
 
206
206
  context "when the class is the same" do
207
207
 
208
- it "returns false" do
209
- expect(person === Person).to be false
208
+ it "returns true" do
209
+ expect(person === Person).to be true
210
210
  end
211
211
  end
212
212
 
@@ -219,8 +219,8 @@ describe Mongoid::Equality do
219
219
 
220
220
  context "when the class is a superclass" do
221
221
 
222
- it "returns false" do
223
- expect(Doctor.new === Person).to be false
222
+ it "returns true" do
223
+ expect(Doctor.new === Person).to be true
224
224
  end
225
225
  end
226
226
  end
@@ -256,8 +256,8 @@ describe Mongoid::Equality do
256
256
  context "when comparing to a class" do
257
257
  context "when the class is the same" do
258
258
 
259
- it "returns true" do
260
- expect(person === Person).to be true
259
+ it "returns false" do
260
+ expect(person === Person).to be false
261
261
  end
262
262
  end
263
263
 
@@ -270,8 +270,8 @@ describe Mongoid::Equality do
270
270
 
271
271
  context "when the class is a superclass" do
272
272
 
273
- it "returns true" do
274
- expect(Doctor.new === Person).to be true
273
+ it "returns false" do
274
+ expect(Doctor.new === Person).to be false
275
275
  end
276
276
  end
277
277
  end
@@ -39,7 +39,6 @@ describe Mongoid::PersistenceContext do
39
39
  end
40
40
  end
41
41
 
42
-
43
42
  describe '.get' do
44
43
 
45
44
  let(:options) do
@@ -134,6 +133,32 @@ describe Mongoid::PersistenceContext do
134
133
  end
135
134
  end
136
135
  end
136
+
137
+ context 'with reusable client' do
138
+ let(:options) do
139
+ {client: :some_client}
140
+ end
141
+
142
+ let(:cluster) do
143
+ double(Mongo::Cluster)
144
+ end
145
+
146
+ let(:client) do
147
+ double(Mongo::Client).tap do |client|
148
+ allow(client).to receive(:cluster).and_return(cluster)
149
+ end
150
+ end
151
+
152
+ before do
153
+ expect(Mongoid::Clients).to receive(:with_name).with(:some_client).and_return(client)
154
+ expect(client).not_to receive(:close)
155
+ end
156
+
157
+ it 'does not close the client' do
158
+ described_class.set(object, options)
159
+ described_class.clear(object, cluster.dup)
160
+ end
161
+ end
137
162
  end
138
163
 
139
164
  describe '#initialize' do
@@ -481,27 +481,45 @@ describe Mongoid::Scopable do
481
481
 
482
482
  context "when a block is provided" do
483
483
 
484
- before do
485
- Band.scope(:active, ->{ Band.where(active: true) }) do
486
- def add_origin
487
- tap { |c| c.selector[:origin] = "Deutschland" }
488
- end
484
+ context "when with optional and keyword arguments" do
485
+ before do
486
+ Band.scope(:named_by, ->(name, deleted: false) {
487
+ Band.where(name: name, deleted: deleted)
488
+ })
489
489
  end
490
- end
491
490
 
492
- after do
493
- class << Band
494
- undef_method :active
491
+ let(:scope) do
492
+ Band.named_by("Emily", deleted: true)
495
493
  end
496
- Band._declared_scopes.clear
497
- end
498
494
 
499
- let(:scope) do
500
- Band.active.add_origin
495
+ it "sets the conditions from keyword arguments" do
496
+ scope.selector.should == {'name' => 'Emily', 'deleted' => true}
497
+ end
501
498
  end
502
499
 
503
- it "adds the extension to the scope" do
504
- expect(scope.selector).to eq({ "active" => true, "origin" => "Deutschland" })
500
+ context "when without arguments" do
501
+ before do
502
+ Band.scope(:active, ->{ Band.where(active: true) }) do
503
+ def add_origin
504
+ tap { |c| c.selector[:origin] = "Deutschland" }
505
+ end
506
+ end
507
+ end
508
+
509
+ after do
510
+ class << Band
511
+ undef_method :active
512
+ end
513
+ Band._declared_scopes.clear
514
+ end
515
+
516
+ let(:scope) do
517
+ Band.active.add_origin
518
+ end
519
+
520
+ it "adds the extension to the scope" do
521
+ expect(scope.selector).to eq({ "active" => true, "origin" => "Deutschland" })
522
+ end
505
523
  end
506
524
  end
507
525
 
@@ -123,6 +123,10 @@ module Mrss
123
123
  end
124
124
 
125
125
  def run_deployment
126
+ puts(BASE_TEST_COMMAND + tty_arg + extra_env + [
127
+ '-e', %q`TEST_CMD=watch -x bash -c "ps awwxu |egrep 'mongo|ocsp'"`,
128
+ '-e', 'BIND_ALL=true',
129
+ ] + port_forwards + [image_tag] + script.split(/\s+/))
126
130
  run_command(BASE_TEST_COMMAND + tty_arg + extra_env + [
127
131
  '-e', %q`TEST_CMD=watch -x bash -c "ps awwxu |egrep 'mongo|ocsp'"`,
128
132
  '-e', 'BIND_ALL=true',
data.tar.gz.sig CHANGED
Binary file