mongoid 9.0.1 → 9.0.3
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
- data/lib/config/locales/en.yml +16 -0
- data/lib/mongoid/association/accessors.rb +7 -2
- data/lib/mongoid/association/nested/one.rb +14 -1
- data/lib/mongoid/association/referenced/belongs_to/binding.rb +7 -1
- data/lib/mongoid/association/referenced/belongs_to/buildable.rb +1 -1
- data/lib/mongoid/association/referenced/belongs_to.rb +15 -0
- data/lib/mongoid/association/referenced/has_many.rb +9 -8
- data/lib/mongoid/association/referenced/has_one/buildable.rb +3 -8
- data/lib/mongoid/association/referenced/with_polymorphic_criteria.rb +41 -0
- data/lib/mongoid/attributes/nested.rb +2 -1
- data/lib/mongoid/clients/options.rb +14 -1
- data/lib/mongoid/clients/sessions.rb +13 -15
- data/lib/mongoid/composable.rb +2 -0
- data/lib/mongoid/document.rb +2 -0
- data/lib/mongoid/errors/unrecognized_model_alias.rb +53 -0
- data/lib/mongoid/errors/unrecognized_resolver.rb +27 -0
- data/lib/mongoid/errors/unregistered_class.rb +47 -0
- data/lib/mongoid/errors.rb +3 -0
- data/lib/mongoid/identifiable.rb +28 -0
- data/lib/mongoid/matcher.rb +15 -1
- data/lib/mongoid/model_resolver.rb +154 -0
- data/lib/mongoid/persistence_context.rb +15 -9
- data/lib/mongoid/railties/controller_runtime.rb +2 -2
- data/lib/mongoid/serializable.rb +7 -7
- data/lib/mongoid/threaded.rb +96 -28
- data/lib/mongoid/timestamps/timeless.rb +4 -1
- data/lib/mongoid/touchable.rb +1 -1
- data/lib/mongoid/traversable.rb +11 -2
- data/lib/mongoid/validatable/associated.rb +5 -2
- data/lib/mongoid/version.rb +1 -1
- data/spec/integration/active_job_spec.rb +24 -20
- data/spec/integration/app_spec.rb +9 -1
- data/spec/integration/associations/belongs_to_spec.rb +129 -0
- data/spec/integration/persistence/collection_options_spec.rb +36 -0
- data/spec/mongoid/association/embedded/embeds_many_query_spec.rb +4 -0
- data/spec/mongoid/association/referenced/belongs_to/proxy_spec.rb +5 -0
- data/spec/mongoid/association/referenced/belongs_to_spec.rb +58 -21
- data/spec/mongoid/association/referenced/has_many/buildable_spec.rb +4 -0
- data/spec/mongoid/attributes/nested_spec.rb +1 -0
- data/spec/mongoid/clients/options_spec.rb +127 -2
- data/spec/mongoid/clients/transactions_spec.rb +2 -2
- data/spec/mongoid/interceptable_spec.rb +12 -0
- data/spec/mongoid/interceptable_spec_models.rb +12 -0
- data/spec/mongoid/model_resolver_spec.rb +167 -0
- data/spec/mongoid/monkey_patches_spec.rb +1 -1
- data/spec/mongoid/persistence_context_spec.rb +48 -4
- data/spec/mongoid/railties/bson_object_id_serializer_spec.rb +18 -12
- data/spec/mongoid/serializable_spec.rb +16 -9
- data/spec/mongoid/threaded_spec.rb +24 -5
- data/spec/mongoid/validatable/associated_spec.rb +14 -4
- data/spec/rails/controller_extension/controller_runtime_spec.rb +14 -14
- metadata +14 -4
@@ -36,6 +36,8 @@ describe 'Mongoid application tests' do
|
|
36
36
|
context 'demo application' do
|
37
37
|
context 'sinatra' do
|
38
38
|
it 'runs' do
|
39
|
+
skip 'https://jira.mongodb.org/browse/MONGOID-5826'
|
40
|
+
|
39
41
|
clone_application(
|
40
42
|
'https://github.com/mongoid/mongoid-demo',
|
41
43
|
subdir: 'sinatra-minimal',
|
@@ -55,6 +57,8 @@ describe 'Mongoid application tests' do
|
|
55
57
|
|
56
58
|
context 'rails-api' do
|
57
59
|
it 'runs' do
|
60
|
+
skip 'https://jira.mongodb.org/browse/MONGOID-5826'
|
61
|
+
|
58
62
|
clone_application(
|
59
63
|
'https://github.com/mongoid/mongoid-demo',
|
60
64
|
subdir: 'rails-api',
|
@@ -172,7 +176,7 @@ describe 'Mongoid application tests' do
|
|
172
176
|
if (rails_version = SpecConfig.instance.rails_version) == 'master'
|
173
177
|
else
|
174
178
|
check_call(%w(gem list))
|
175
|
-
check_call(%w(gem install rails --no-document -v) + ["~> #{rails_version}.0"])
|
179
|
+
check_call(%w(gem install rails --no-document --force -v) + ["~> #{rails_version}.0"])
|
176
180
|
end
|
177
181
|
end
|
178
182
|
|
@@ -319,6 +323,10 @@ describe 'Mongoid application tests' do
|
|
319
323
|
end
|
320
324
|
|
321
325
|
def adjust_rails_defaults(rails_version: SpecConfig.instance.rails_version)
|
326
|
+
if !rails_version.match?(/^\d+\.\d+$/)
|
327
|
+
# This must be pre-release version, we trim it
|
328
|
+
rails_version = rails_version.split('.')[0..1].join('.')
|
329
|
+
end
|
322
330
|
if File.exist?('config/application.rb')
|
323
331
|
lines = IO.readlines('config/application.rb')
|
324
332
|
lines.each do |line|
|
@@ -2,8 +2,40 @@
|
|
2
2
|
# rubocop:todo all
|
3
3
|
|
4
4
|
require 'spec_helper'
|
5
|
+
require 'support/feature_sandbox'
|
6
|
+
|
5
7
|
require_relative '../../mongoid/association/referenced/has_one_models'
|
6
8
|
|
9
|
+
def quarantine(context, polymorphic:, dept_aliases:, team_aliases:)
|
10
|
+
state = {}
|
11
|
+
|
12
|
+
context.before(:context) do
|
13
|
+
state[:quarantine] = FeatureSandbox.start_quarantine
|
14
|
+
|
15
|
+
# Have to eval this, because otherwise we get syntax errors when defining a class
|
16
|
+
# inside a method.
|
17
|
+
#
|
18
|
+
# I know the scissors are sharp! But I want to run with them anwyay!
|
19
|
+
Object.class_eval <<-RUBY
|
20
|
+
class SandboxManager; include Mongoid::Document; end
|
21
|
+
class SandboxDepartment; include Mongoid::Document; end
|
22
|
+
class SandboxTeam; include Mongoid::Document; end
|
23
|
+
RUBY
|
24
|
+
|
25
|
+
SandboxManager.belongs_to :unit, polymorphic: polymorphic
|
26
|
+
|
27
|
+
SandboxDepartment.identify_as *dept_aliases, resolver: polymorphic
|
28
|
+
SandboxDepartment.has_many :sandbox_managers, as: :unit
|
29
|
+
|
30
|
+
SandboxTeam.identify_as *team_aliases, resolver: polymorphic
|
31
|
+
SandboxTeam.has_one :sandbox_manager, as: :unit
|
32
|
+
end
|
33
|
+
|
34
|
+
context.after(:context) do
|
35
|
+
FeatureSandbox.end_quarantine(state[:quarantine])
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
7
39
|
describe 'belongs_to associations' do
|
8
40
|
context 'referencing top level classes when source class is namespaced' do
|
9
41
|
let(:college) { HomCollege.create! }
|
@@ -31,4 +63,101 @@ describe 'belongs_to associations' do
|
|
31
63
|
expect(instance.movie).to eq movie
|
32
64
|
end
|
33
65
|
end
|
66
|
+
|
67
|
+
context 'when the association is polymorphic' do
|
68
|
+
let(:dept_manager) { SandboxManager.create(unit: department) }
|
69
|
+
let(:team_manager) { SandboxManager.create(unit: team) }
|
70
|
+
let(:department) { SandboxDepartment.create }
|
71
|
+
let(:team) { SandboxTeam.create }
|
72
|
+
|
73
|
+
shared_context 'it finds the associated records' do
|
74
|
+
it 'successfully finds the manager\'s unit' do
|
75
|
+
expect(dept_manager.reload.unit).to be == department
|
76
|
+
expect(team_manager.reload.unit).to be == team
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'successfully finds the unit\'s manager' do
|
80
|
+
dept_manager; team_manager # make sure these are created first...
|
81
|
+
|
82
|
+
expect(department.reload.sandbox_managers).to be == [ dept_manager ]
|
83
|
+
expect(team.reload.sandbox_manager).to be == team_manager
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
shared_context 'it searches for alternative aliases' do
|
88
|
+
it 'successfully finds the corresponding unit when unit_type is a different alias' do
|
89
|
+
dept_manager.update unit_type: 'sandbox_dept'
|
90
|
+
dept_manager.reload
|
91
|
+
|
92
|
+
team_manager.update unit_type: 'group'
|
93
|
+
team_manager.reload
|
94
|
+
|
95
|
+
expect(dept_manager.reload.unit_type).to be == 'sandbox_dept'
|
96
|
+
expect(dept_manager.unit).to be == department
|
97
|
+
|
98
|
+
expect(team_manager.reload.unit_type).to be == 'group'
|
99
|
+
expect(team_manager.unit).to be == team
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
context 'when the association uses the default resolver' do
|
104
|
+
context 'when there are no aliases given' do
|
105
|
+
quarantine(self, polymorphic: true, dept_aliases: [], team_aliases: [])
|
106
|
+
|
107
|
+
it 'populates the unit_type with the class name' do
|
108
|
+
expect(dept_manager.unit_type).to be == 'SandboxDepartment'
|
109
|
+
expect(team_manager.unit_type).to be == 'SandboxTeam'
|
110
|
+
end
|
111
|
+
|
112
|
+
it_behaves_like 'it finds the associated records'
|
113
|
+
end
|
114
|
+
|
115
|
+
context 'when there are multiple aliases given' do
|
116
|
+
quarantine(self, polymorphic: true, dept_aliases: %w[ dept sandbox_dept ], team_aliases: %w[ team group ])
|
117
|
+
|
118
|
+
it 'populates the unit_type with the first alias' do
|
119
|
+
expect(dept_manager.unit_type).to be == 'dept'
|
120
|
+
expect(team_manager.unit_type).to be == 'team'
|
121
|
+
end
|
122
|
+
|
123
|
+
it_behaves_like 'it finds the associated records'
|
124
|
+
it_behaves_like 'it searches for alternative aliases'
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
context 'when the association uses a registered resolver' do
|
129
|
+
before(:context) { Mongoid::ModelResolver.register_resolver Mongoid::ModelResolver.new, :sandbox }
|
130
|
+
quarantine(self, polymorphic: :sandbox, dept_aliases: %w[ dept sandbox_dept ], team_aliases: %w[ team group ])
|
131
|
+
|
132
|
+
it 'does not include the aliases in the default resolver' do
|
133
|
+
expect(Mongoid::ModelResolver.instance.keys_for(SandboxDepartment.new)).not_to include('dept')
|
134
|
+
end
|
135
|
+
|
136
|
+
it 'populates the unit_type with the first alias' do
|
137
|
+
expect(dept_manager.unit_type).to be == 'dept'
|
138
|
+
expect(team_manager.unit_type).to be == 'team'
|
139
|
+
end
|
140
|
+
|
141
|
+
it_behaves_like 'it finds the associated records'
|
142
|
+
it_behaves_like 'it searches for alternative aliases'
|
143
|
+
end
|
144
|
+
|
145
|
+
context 'when the association uses an unregistered resolver' do
|
146
|
+
quarantine(self, polymorphic: Mongoid::ModelResolver.new,
|
147
|
+
dept_aliases: %w[ dept sandbox_dept ],
|
148
|
+
team_aliases: %w[ team group ])
|
149
|
+
|
150
|
+
it 'does not include the aliases in the default resolver' do
|
151
|
+
expect(Mongoid::ModelResolver.instance.keys_for(SandboxDepartment.new)).not_to include('dept')
|
152
|
+
end
|
153
|
+
|
154
|
+
it 'populates the unit_type with the first alias' do
|
155
|
+
expect(dept_manager.unit_type).to be == 'dept'
|
156
|
+
expect(team_manager.unit_type).to be == 'team'
|
157
|
+
end
|
158
|
+
|
159
|
+
it_behaves_like 'it finds the associated records'
|
160
|
+
it_behaves_like 'it searches for alternative aliases'
|
161
|
+
end
|
162
|
+
end
|
34
163
|
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
# rubocop:disable RSpec/LeakyConstantDeclaration
|
6
|
+
# rubocop:disable Lint/ConstantDefinitionInBlock
|
7
|
+
describe 'Collection options' do
|
8
|
+
before(:all) do
|
9
|
+
class CollectionOptionsCapped
|
10
|
+
include Mongoid::Document
|
11
|
+
|
12
|
+
store_in collection_options: {
|
13
|
+
capped: true,
|
14
|
+
size: 25_600
|
15
|
+
}
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
after(:all) do
|
20
|
+
CollectionOptionsCapped.collection.drop
|
21
|
+
Mongoid.deregister_model(CollectionOptionsCapped)
|
22
|
+
Object.send(:remove_const, :CollectionOptionsCapped)
|
23
|
+
end
|
24
|
+
|
25
|
+
before do
|
26
|
+
CollectionOptionsCapped.collection.drop
|
27
|
+
# We should create the collection explicitly to apply collection options.
|
28
|
+
CollectionOptionsCapped.create_collection
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'creates a document' do
|
32
|
+
expect { CollectionOptionsCapped.create! }.not_to raise_error
|
33
|
+
end
|
34
|
+
end
|
35
|
+
# rubocop:enable Lint/ConstantDefinitionInBlock
|
36
|
+
# rubocop:enable RSpec/LeakyConstantDeclaration
|
@@ -28,6 +28,10 @@ describe Mongoid::Association::Embedded::EmbedsMany do
|
|
28
28
|
expect(legislator.attributes.keys).to eq(['_id', 'a'])
|
29
29
|
end
|
30
30
|
|
31
|
+
it 'allows accessing the parent' do
|
32
|
+
expect { legislator.congress }.not_to raise_error
|
33
|
+
end
|
34
|
+
|
31
35
|
context 'when using only with $' do
|
32
36
|
before do
|
33
37
|
Patient.destroy_all
|
@@ -2,6 +2,7 @@
|
|
2
2
|
# rubocop:todo all
|
3
3
|
|
4
4
|
require "spec_helper"
|
5
|
+
require 'support/models/canvas'
|
5
6
|
require_relative '../belongs_to_models.rb'
|
6
7
|
|
7
8
|
describe Mongoid::Association::Referenced::BelongsTo::Proxy do
|
@@ -750,6 +751,10 @@ describe Mongoid::Association::Referenced::BelongsTo::Proxy do
|
|
750
751
|
person.save!
|
751
752
|
end
|
752
753
|
|
754
|
+
# NOTE: there as a bad interdependency here, with the auto_save_spec.rb
|
755
|
+
# file. If auto_save_spec.rb runs before this, the following specs fail
|
756
|
+
# with "undefined method `nullify' for an instance of Person".
|
757
|
+
|
753
758
|
context "when parent exists" do
|
754
759
|
|
755
760
|
context "when child is destroyed" do
|
@@ -4,6 +4,10 @@
|
|
4
4
|
require "spec_helper"
|
5
5
|
require_relative './has_one_models'
|
6
6
|
|
7
|
+
BELONGS_TO_RESOLVER_ID__ = :__belongs_to_resolver_id
|
8
|
+
BELONGS_TO_RESOLVER = Mongoid::ModelResolver.new
|
9
|
+
Mongoid::ModelResolver.register_resolver BELONGS_TO_RESOLVER, BELONGS_TO_RESOLVER_ID__
|
10
|
+
|
7
11
|
describe Mongoid::Association::Referenced::BelongsTo do
|
8
12
|
|
9
13
|
before do
|
@@ -199,47 +203,76 @@ describe Mongoid::Association::Referenced::BelongsTo do
|
|
199
203
|
|
200
204
|
context 'when the polymorphic option is provided' do
|
201
205
|
|
202
|
-
|
206
|
+
[ true, :default ].each do |opt|
|
207
|
+
context "when the polymorphic option is #{opt.inspect}" do
|
208
|
+
let(:options) { { polymorphic: opt } }
|
209
|
+
before { association }
|
203
210
|
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
211
|
+
it 'set the polymorphic attribute on the owner class' do
|
212
|
+
expect(belonging_class.polymorphic).to be(true)
|
213
|
+
end
|
214
|
+
|
215
|
+
it 'sets up a field for the inverse type' do
|
216
|
+
expect(belonging_class.fields.keys).to include(association.inverse_type)
|
217
|
+
end
|
218
|
+
|
219
|
+
it 'uses the default resolver' do
|
220
|
+
expect(association.resolver).to be == Mongoid::ModelResolver.instance
|
221
|
+
end
|
208
222
|
end
|
223
|
+
end
|
209
224
|
|
210
|
-
|
211
|
-
|
225
|
+
[ false, nil ].each do |opt|
|
226
|
+
context "when the polymorphic option is #{opt.inspect}" do
|
227
|
+
let(:options) { { polymorphic: opt } }
|
228
|
+
|
229
|
+
it 'does not set the polymorphic attribute on the owner class' do
|
230
|
+
expect(belonging_class.polymorphic).to be(false)
|
231
|
+
end
|
232
|
+
|
233
|
+
it 'does not set up a field for the inverse type' do
|
234
|
+
expect(belonging_class.fields.keys).not_to include(association.inverse_type)
|
235
|
+
end
|
236
|
+
|
237
|
+
it 'does not use a resolver' do
|
238
|
+
expect(association.resolver).to be_nil
|
239
|
+
end
|
212
240
|
end
|
241
|
+
end
|
213
242
|
|
214
|
-
|
215
|
-
|
243
|
+
context 'when the polymorphic option is set to an unregistered id' do
|
244
|
+
let(:options) { { polymorphic: :bogus } }
|
245
|
+
|
246
|
+
# This behavior is intentional, so that the resolver can be registered after the classes
|
247
|
+
# are loaded.
|
248
|
+
it 'does not immediately raise an exception' do
|
249
|
+
expect { association }.not_to raise_error
|
216
250
|
end
|
217
251
|
|
218
|
-
it '
|
219
|
-
expect
|
252
|
+
it 'raises error when resolver is accessed' do
|
253
|
+
expect { association.resolver }.to raise_error(Mongoid::Errors::UnrecognizedResolver)
|
220
254
|
end
|
221
255
|
end
|
222
256
|
|
223
|
-
context 'when the polymorphic option is
|
257
|
+
context 'when the polymorphic option is set to a registered id' do
|
258
|
+
let(:options) { { polymorphic: BELONGS_TO_RESOLVER_ID__ } }
|
259
|
+
before { association }
|
224
260
|
|
225
|
-
|
226
|
-
|
227
|
-
polymorphic: false
|
228
|
-
}
|
261
|
+
it 'set the polymorphic attribute on the owner class' do
|
262
|
+
expect(belonging_class.polymorphic).to be(true)
|
229
263
|
end
|
230
264
|
|
231
|
-
it '
|
232
|
-
expect(belonging_class.
|
265
|
+
it 'sets up a field for the inverse type' do
|
266
|
+
expect(belonging_class.fields.keys).to include(association.inverse_type)
|
233
267
|
end
|
234
268
|
|
235
|
-
it '
|
236
|
-
expect(
|
269
|
+
it 'connects the association to the corresponding resolver' do
|
270
|
+
expect(association.resolver).to be == BELONGS_TO_RESOLVER
|
237
271
|
end
|
238
272
|
end
|
239
273
|
end
|
240
274
|
|
241
275
|
context 'when the polymorphic option is not provided' do
|
242
|
-
|
243
276
|
it 'does not set the polymorphic attribute on the owner class' do
|
244
277
|
expect(belonging_class.polymorphic).to be(false)
|
245
278
|
end
|
@@ -247,6 +280,10 @@ describe Mongoid::Association::Referenced::BelongsTo do
|
|
247
280
|
it 'does not set up a field for the inverse type' do
|
248
281
|
expect(belonging_class.fields.keys).not_to include(association.inverse_type)
|
249
282
|
end
|
283
|
+
|
284
|
+
it 'does not use a resolver' do
|
285
|
+
expect(association.resolver).to be_nil
|
286
|
+
end
|
250
287
|
end
|
251
288
|
end
|
252
289
|
|
@@ -100,6 +100,10 @@ describe Mongoid::Association::Referenced::HasMany::Buildable do
|
|
100
100
|
Post.where(association.foreign_key => object, 'ratable_type' => 'Rating')
|
101
101
|
end
|
102
102
|
|
103
|
+
before do
|
104
|
+
Post.belongs_to :ratable, polymorphic: true
|
105
|
+
end
|
106
|
+
|
103
107
|
it "adds the type to the criteria" do
|
104
108
|
expect(documents).to eq(criteria)
|
105
109
|
end
|
@@ -27,7 +27,7 @@ describe Mongoid::Clients::Options, retry: 3 do
|
|
27
27
|
let(:options) { { database: 'other' } }
|
28
28
|
|
29
29
|
it 'sets the options on the client' do
|
30
|
-
expect(persistence_context.client.options['database']).to eq(options[:database])
|
30
|
+
expect(persistence_context.client.options['database'].to_s).to eq(options[:database].to_s)
|
31
31
|
end
|
32
32
|
|
33
33
|
it 'does not set the options on class level' do
|
@@ -319,7 +319,7 @@ describe Mongoid::Clients::Options, retry: 3 do
|
|
319
319
|
end
|
320
320
|
|
321
321
|
it 'sets the options on the client' do
|
322
|
-
expect(persistence_context.client.options['database']).to eq(options[:database])
|
322
|
+
expect(persistence_context.client.options['database'].to_s).to eq(options[:database].to_s)
|
323
323
|
end
|
324
324
|
|
325
325
|
it 'does not set the options on instance level' do
|
@@ -522,4 +522,129 @@ describe Mongoid::Clients::Options, retry: 3 do
|
|
522
522
|
end
|
523
523
|
end
|
524
524
|
end
|
525
|
+
|
526
|
+
context 'with global overrides' do
|
527
|
+
let(:default_subscriber) do
|
528
|
+
Mrss::EventSubscriber.new
|
529
|
+
end
|
530
|
+
|
531
|
+
let(:override_subscriber) do
|
532
|
+
Mrss::EventSubscriber.new
|
533
|
+
end
|
534
|
+
|
535
|
+
context 'when global client is overridden' do
|
536
|
+
before do
|
537
|
+
Mongoid.clients['override_client'] = { hosts: SpecConfig.instance.addresses, database: 'default_override_database' }
|
538
|
+
Mongoid.override_client('override_client')
|
539
|
+
Mongoid.client(:default).subscribe(Mongo::Monitoring::COMMAND, default_subscriber)
|
540
|
+
Mongoid.client('override_client').subscribe(Mongo::Monitoring::COMMAND, override_subscriber)
|
541
|
+
end
|
542
|
+
|
543
|
+
after do
|
544
|
+
Mongoid.client(:default).unsubscribe(Mongo::Monitoring::COMMAND, default_subscriber)
|
545
|
+
Mongoid.client('override_client').unsubscribe(Mongo::Monitoring::COMMAND, override_subscriber)
|
546
|
+
Mongoid.override_client(nil)
|
547
|
+
Mongoid.clients['override_client'] = nil
|
548
|
+
end
|
549
|
+
|
550
|
+
it 'uses the overridden client for create' do
|
551
|
+
Minim.create!
|
552
|
+
|
553
|
+
expect(override_subscriber.single_command_started_event('insert').database_name).to eq('default_override_database')
|
554
|
+
expect(default_subscriber.command_started_events('insert')).to be_empty
|
555
|
+
end
|
556
|
+
|
557
|
+
it 'uses the overridden client for queries' do
|
558
|
+
Minim.where(name: 'Dmitry').to_a
|
559
|
+
|
560
|
+
expect(override_subscriber.single_command_started_event('find').database_name).to eq('default_override_database')
|
561
|
+
expect(default_subscriber.command_started_events('find')).to be_empty
|
562
|
+
end
|
563
|
+
|
564
|
+
context 'when the client is set on the model level' do
|
565
|
+
let(:model_level_subscriber) do
|
566
|
+
Mrss::EventSubscriber.new
|
567
|
+
end
|
568
|
+
|
569
|
+
around(:example) do |example|
|
570
|
+
opts = Minim.storage_options
|
571
|
+
Minim.storage_options = Minim.storage_options.merge( { client: 'model_level_client' } )
|
572
|
+
Mongoid.clients['model_level_client'] = { hosts: SpecConfig.instance.addresses, database: 'model_level_database' }
|
573
|
+
Mongoid.client('model_level_client').subscribe(Mongo::Monitoring::COMMAND, override_subscriber)
|
574
|
+
example.run
|
575
|
+
Mongoid.client('model_level_client').unsubscribe(Mongo::Monitoring::COMMAND, override_subscriber)
|
576
|
+
Mongoid.clients['model_level_client'] = nil
|
577
|
+
Minim.storage_options = opts
|
578
|
+
end
|
579
|
+
|
580
|
+
# This behaviour is consistent with 8.x
|
581
|
+
it 'uses the overridden client for create' do
|
582
|
+
Minim.create!
|
583
|
+
|
584
|
+
expect(override_subscriber.single_command_started_event('insert').database_name).to eq('default_override_database')
|
585
|
+
expect(default_subscriber.command_started_events('insert')).to be_empty
|
586
|
+
expect(model_level_subscriber.command_started_events('insert')).to be_empty
|
587
|
+
end
|
588
|
+
|
589
|
+
# This behaviour is consistent with 8.x
|
590
|
+
it 'uses the overridden client for queries' do
|
591
|
+
Minim.where(name: 'Dmitry').to_a
|
592
|
+
|
593
|
+
expect(override_subscriber.single_command_started_event('find').database_name).to eq('default_override_database')
|
594
|
+
expect(default_subscriber.command_started_events('find')).to be_empty
|
595
|
+
expect(model_level_subscriber.command_started_events('find')).to be_empty
|
596
|
+
end
|
597
|
+
end
|
598
|
+
end
|
599
|
+
|
600
|
+
context 'when global database is overridden' do
|
601
|
+
before do
|
602
|
+
Mongoid.override_database('override_database')
|
603
|
+
Mongoid.client(:default).subscribe(Mongo::Monitoring::COMMAND, default_subscriber)
|
604
|
+
end
|
605
|
+
|
606
|
+
after do
|
607
|
+
Mongoid.client(:default).unsubscribe(Mongo::Monitoring::COMMAND, default_subscriber)
|
608
|
+
Mongoid.override_database(nil)
|
609
|
+
end
|
610
|
+
|
611
|
+
it 'uses the overridden database for create' do
|
612
|
+
Minim.create!
|
613
|
+
|
614
|
+
expect(default_subscriber.single_command_started_event('insert').database_name).to eq('override_database')
|
615
|
+
end
|
616
|
+
|
617
|
+
it 'uses the overridden database for queries' do
|
618
|
+
Minim.where(name: 'Dmitry').to_a
|
619
|
+
|
620
|
+
expect(default_subscriber.single_command_started_event('find').database_name).to eq('override_database')
|
621
|
+
end
|
622
|
+
|
623
|
+
context 'when the database is set on the model level' do
|
624
|
+
around(:example) do |example|
|
625
|
+
opts = Minim.storage_options
|
626
|
+
Minim.storage_options = Minim.storage_options.merge( { database: 'model_level_database' } )
|
627
|
+
Mongoid.clients['model_level_client'] = { hosts: SpecConfig.instance.addresses, database: 'model_level_database' }
|
628
|
+
Mongoid.client(:default).subscribe(Mongo::Monitoring::COMMAND, default_subscriber)
|
629
|
+
example.run
|
630
|
+
Mongoid.client(:default).unsubscribe(Mongo::Monitoring::COMMAND, default_subscriber)
|
631
|
+
Mongoid.clients['model_level_client'] = nil
|
632
|
+
Minim.storage_options = opts
|
633
|
+
end
|
634
|
+
|
635
|
+
# This behaviour is consistent with 8.x
|
636
|
+
it 'uses the overridden database for create' do
|
637
|
+
Minim.create!
|
638
|
+
|
639
|
+
expect(default_subscriber.single_command_started_event('insert').database_name).to eq('override_database')
|
640
|
+
end
|
641
|
+
|
642
|
+
it 'uses the overridden database for queries' do
|
643
|
+
Minim.where(name: 'Dmitry').to_a
|
644
|
+
|
645
|
+
expect(default_subscriber.single_command_started_event('find').database_name).to eq('override_database')
|
646
|
+
end
|
647
|
+
end
|
648
|
+
end
|
649
|
+
end
|
525
650
|
end
|
@@ -282,7 +282,7 @@ describe Mongoid::Clients::Sessions do
|
|
282
282
|
end
|
283
283
|
end
|
284
284
|
|
285
|
-
include_examples 'it aborts the transaction', Mongoid::Errors::
|
285
|
+
include_examples 'it aborts the transaction', Mongoid::Errors::TransactionError
|
286
286
|
end
|
287
287
|
end
|
288
288
|
end
|
@@ -591,7 +591,7 @@ describe Mongoid::Clients::Sessions do
|
|
591
591
|
end
|
592
592
|
|
593
593
|
it 'raises an error' do
|
594
|
-
expect(error).to be_a(Mongoid::Errors::
|
594
|
+
expect(error).to be_a(Mongoid::Errors::TransactionError)
|
595
595
|
end
|
596
596
|
|
597
597
|
it 'does not execute any operations' do
|
@@ -1789,6 +1789,12 @@ describe Mongoid::Interceptable do
|
|
1789
1789
|
context 'with around callbacks' do
|
1790
1790
|
config_override :around_callbacks_for_embeds, true
|
1791
1791
|
|
1792
|
+
after do
|
1793
|
+
Mongoid::Threaded.stack('interceptable').clear
|
1794
|
+
end
|
1795
|
+
|
1796
|
+
let(:stack) { Mongoid::Threaded.stack('interceptable') }
|
1797
|
+
|
1792
1798
|
let(:expected) do
|
1793
1799
|
[
|
1794
1800
|
[InterceptableSpec::CbCascadedChild, :before_validation],
|
@@ -1824,6 +1830,12 @@ describe Mongoid::Interceptable do
|
|
1824
1830
|
parent.save!
|
1825
1831
|
expect(registry.calls).to eq expected
|
1826
1832
|
end
|
1833
|
+
|
1834
|
+
it 'shows that cascaded callbacks can access Mongoid state' do
|
1835
|
+
expect(stack).to be_empty
|
1836
|
+
parent.save!
|
1837
|
+
expect(stack).not_to be_empty
|
1838
|
+
end
|
1827
1839
|
end
|
1828
1840
|
|
1829
1841
|
context 'without around callbacks' do
|
@@ -224,7 +224,19 @@ module InterceptableSpec
|
|
224
224
|
|
225
225
|
attr_accessor :callback_registry
|
226
226
|
|
227
|
+
before_save :test_mongoid_state
|
228
|
+
|
227
229
|
include CallbackTracking
|
230
|
+
|
231
|
+
private
|
232
|
+
|
233
|
+
# Helps test that cascading child callbacks have access to the Mongoid
|
234
|
+
# state objects; if the implementation uses fiber-local (instead of truly
|
235
|
+
# thread-local) variables, the related tests will fail because the
|
236
|
+
# cascading child callbacks use fibers to linearize the recursion.
|
237
|
+
def test_mongoid_state
|
238
|
+
Mongoid::Threaded.stack('interceptable').push(self)
|
239
|
+
end
|
228
240
|
end
|
229
241
|
end
|
230
242
|
|