mongoid 7.5.0 → 7.5.2

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
  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