mongoid 9.0.1 → 9.0.3
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
|