mongoid 7.5.2 → 7.5.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/Rakefile +25 -0
- data/lib/mongoid/association/embedded/batchable.rb +20 -3
- data/lib/mongoid/atomic/paths/embedded/many.rb +19 -0
- data/lib/mongoid/contextual/mongo.rb +24 -7
- data/lib/mongoid/criteria/queryable/selector.rb +1 -1
- data/lib/mongoid/criteria/queryable/storable.rb +1 -1
- data/lib/mongoid/shardable.rb +35 -11
- data/lib/mongoid/version.rb +1 -1
- data/spec/mongoid/association/embedded/embeds_many/proxy_spec.rb +21 -0
- data/spec/mongoid/association/embedded/embeds_many_models.rb +121 -0
- data/spec/mongoid/contextual/mongo_spec.rb +23 -3
- data/spec/mongoid/criteria/queryable/selector_spec.rb +75 -2
- data/spec/mongoid/criteria/queryable/storable_spec.rb +72 -0
- data/spec/mongoid/shardable_models.rb +14 -0
- data/spec/mongoid/shardable_spec.rb +157 -51
- data/spec/mongoid_spec.rb +7 -1
- data/spec/shared/lib/mrss/docker_runner.rb +0 -4
- data/spec/shared/lib/mrss/lite_constraints.rb +8 -0
- data/spec/shared/shlib/server.sh +5 -5
- data.tar.gz.sig +0 -0
- metadata +584 -580
- metadata.gz.sig +0 -0
@@ -59,3 +59,17 @@ end
|
|
59
59
|
class SmNotSharded
|
60
60
|
include Mongoid::Document
|
61
61
|
end
|
62
|
+
|
63
|
+
class SmReviewAuthor
|
64
|
+
include Mongoid::Document
|
65
|
+
embedded_in :review, class_name: "SmReview", touch: false
|
66
|
+
field :name, type: String
|
67
|
+
end
|
68
|
+
|
69
|
+
class SmReview
|
70
|
+
include Mongoid::Document
|
71
|
+
|
72
|
+
embeds_one :author, class_name: "SmReviewAuthor"
|
73
|
+
|
74
|
+
shard_key "author.name" => 1
|
75
|
+
end
|
@@ -27,11 +27,11 @@ describe Mongoid::Shardable do
|
|
27
27
|
context 'when full syntax is used' do
|
28
28
|
context 'with symbol value' do
|
29
29
|
it 'sets shard key fields to symbol value' do
|
30
|
-
SmProducer.shard_key_fields.
|
30
|
+
expect(SmProducer.shard_key_fields).to be == %i(age gender)
|
31
31
|
end
|
32
32
|
|
33
33
|
it 'sets shard config' do
|
34
|
-
SmProducer.shard_config.
|
34
|
+
expect(SmProducer.shard_config).to be == {
|
35
35
|
key: {age: 1, gender: 'hashed'},
|
36
36
|
options: {
|
37
37
|
unique: true,
|
@@ -41,37 +41,37 @@ describe Mongoid::Shardable do
|
|
41
41
|
end
|
42
42
|
|
43
43
|
it 'keeps hashed as string' do
|
44
|
-
SmProducer.shard_config[:key][:gender].
|
44
|
+
expect(SmProducer.shard_config[:key][:gender]).to be == 'hashed'
|
45
45
|
end
|
46
46
|
end
|
47
47
|
|
48
48
|
context 'with string value' do
|
49
49
|
it 'sets shard key fields to symbol value' do
|
50
|
-
SmActor.shard_key_fields.
|
50
|
+
expect(SmActor.shard_key_fields).to be == %i(age gender hello)
|
51
51
|
end
|
52
52
|
|
53
53
|
it 'sets shard config' do
|
54
|
-
SmActor.shard_config.
|
54
|
+
expect(SmActor.shard_config).to be == {
|
55
55
|
key: {age: 1, gender: 'hashed', hello: 'hashed'},
|
56
56
|
options: {},
|
57
57
|
}
|
58
58
|
end
|
59
59
|
|
60
60
|
it 'sets hashed to string' do
|
61
|
-
SmActor.shard_config[:key][:gender].
|
61
|
+
expect(SmActor.shard_config[:key][:gender]).to be == 'hashed'
|
62
62
|
end
|
63
63
|
end
|
64
64
|
|
65
65
|
context 'when passed association name' do
|
66
66
|
it 'uses foreign key as shard key in shard config' do
|
67
|
-
SmDriver.shard_config.
|
67
|
+
expect(SmDriver.shard_config).to be == {
|
68
68
|
key: {age: 1, agency_id: 'hashed'},
|
69
69
|
options: {},
|
70
70
|
}
|
71
71
|
end
|
72
72
|
|
73
73
|
it 'uses foreign key as shard key in shard key fields' do
|
74
|
-
SmDriver.shard_key_fields.
|
74
|
+
expect(SmDriver.shard_key_fields).to be == %i(age agency_id)
|
75
75
|
end
|
76
76
|
end
|
77
77
|
end
|
@@ -79,26 +79,26 @@ describe Mongoid::Shardable do
|
|
79
79
|
context 'when shorthand syntax is used' do
|
80
80
|
context 'with symbol value' do
|
81
81
|
it 'sets shard key fields to symbol value' do
|
82
|
-
SmMovie.shard_key_fields.
|
82
|
+
expect(SmMovie.shard_key_fields).to be == %i(year)
|
83
83
|
end
|
84
84
|
end
|
85
85
|
|
86
86
|
context 'with string value' do
|
87
87
|
it 'sets shard key fields to symbol value' do
|
88
|
-
SmTrailer.shard_key_fields.
|
88
|
+
expect(SmTrailer.shard_key_fields).to be == %i(year)
|
89
89
|
end
|
90
90
|
end
|
91
91
|
|
92
92
|
context 'when passed association name' do
|
93
93
|
it 'uses foreign key as shard key in shard config' do
|
94
|
-
SmDirector.shard_config.
|
94
|
+
expect(SmDirector.shard_config).to be == {
|
95
95
|
key: {agency_id: 1},
|
96
96
|
options: {},
|
97
97
|
}
|
98
98
|
end
|
99
99
|
|
100
100
|
it 'uses foreign key as shard key in shard key fields' do
|
101
|
-
SmDirector.shard_key_fields.
|
101
|
+
expect(SmDirector.shard_key_fields).to be == %i(agency_id)
|
102
102
|
end
|
103
103
|
end
|
104
104
|
end
|
@@ -106,41 +106,80 @@ describe Mongoid::Shardable do
|
|
106
106
|
|
107
107
|
describe '#shard_key_selector' do
|
108
108
|
subject { instance.shard_key_selector }
|
109
|
-
|
110
|
-
|
109
|
+
|
110
|
+
context 'when key is an immediate attribute' do
|
111
|
+
let(:klass) { Band }
|
112
|
+
let(:value) { 'a-brand-name' }
|
111
113
|
|
112
|
-
|
114
|
+
before { klass.shard_key(:name) }
|
113
115
|
|
114
|
-
|
115
|
-
|
116
|
+
context 'when record is new' do
|
117
|
+
let(:instance) { klass.new(name: value) }
|
116
118
|
|
117
|
-
|
119
|
+
it { is_expected.to eq({ 'name' => value }) }
|
118
120
|
|
119
|
-
|
120
|
-
|
121
|
+
context 'changing shard key value' do
|
122
|
+
let(:new_value) { 'a-new-value' }
|
121
123
|
|
122
|
-
|
123
|
-
|
124
|
+
before do
|
125
|
+
instance.name = new_value
|
126
|
+
end
|
127
|
+
|
128
|
+
it { is_expected.to eq({ 'name' => new_value }) }
|
124
129
|
end
|
130
|
+
end
|
131
|
+
|
132
|
+
context 'when record is persisted' do
|
133
|
+
let(:instance) { klass.create!(name: value) }
|
134
|
+
|
135
|
+
it { is_expected.to eq({ 'name' => value }) }
|
136
|
+
|
137
|
+
context 'changing shard key value' do
|
138
|
+
let(:new_value) { 'a-new-value' }
|
139
|
+
|
140
|
+
before do
|
141
|
+
instance.name = new_value
|
142
|
+
end
|
125
143
|
|
126
|
-
|
144
|
+
it { is_expected.to eq({ 'name' => new_value }) }
|
145
|
+
end
|
127
146
|
end
|
128
147
|
end
|
129
148
|
|
130
|
-
context 'when
|
131
|
-
let(:
|
149
|
+
context 'when key is an embedded attribute' do
|
150
|
+
let(:klass) { SmReview }
|
151
|
+
let(:value) { 'Arthur Conan Doyle' }
|
152
|
+
let(:key) { 'author.name' }
|
132
153
|
|
133
|
-
|
154
|
+
context 'when record is new' do
|
155
|
+
let(:instance) { klass.new(author: { name: value }) }
|
134
156
|
|
135
|
-
|
136
|
-
let(:new_value) { 'a-new-value' }
|
157
|
+
it { is_expected.to eq({ key => value }) }
|
137
158
|
|
138
|
-
|
139
|
-
|
159
|
+
context 'changing shard key value' do
|
160
|
+
let(:new_value) { 'Jules Verne' }
|
161
|
+
|
162
|
+
before do
|
163
|
+
instance.author.name = new_value
|
164
|
+
end
|
165
|
+
|
166
|
+
it { is_expected.to eq({ key => new_value }) }
|
140
167
|
end
|
168
|
+
end
|
169
|
+
|
170
|
+
context 'when record is persisted' do
|
171
|
+
let(:instance) { klass.create!(author: { name: value }) }
|
172
|
+
|
173
|
+
it { is_expected.to eq({ key => value }) }
|
174
|
+
|
175
|
+
context 'changing shard key value' do
|
176
|
+
let(:new_value) { 'Jules Verne' }
|
177
|
+
|
178
|
+
before do
|
179
|
+
instance.author.name = new_value
|
180
|
+
end
|
141
181
|
|
142
|
-
|
143
|
-
subject.should == { 'name' => new_value }
|
182
|
+
it { is_expected.to eq({ 'author.name' => new_value }) }
|
144
183
|
end
|
145
184
|
end
|
146
185
|
end
|
@@ -148,42 +187,109 @@ describe Mongoid::Shardable do
|
|
148
187
|
|
149
188
|
describe '#shard_key_selector_in_db' do
|
150
189
|
subject { instance.shard_key_selector_in_db }
|
151
|
-
let(:klass) { Band }
|
152
|
-
let(:value) { 'a-brand-name' }
|
153
190
|
|
154
|
-
|
191
|
+
context 'when key is an immediate attribute' do
|
192
|
+
let(:klass) { Band }
|
193
|
+
let(:value) { 'a-brand-name' }
|
155
194
|
|
156
|
-
|
157
|
-
let(:instance) { klass.new(name: value) }
|
195
|
+
before { klass.shard_key(:name) }
|
158
196
|
|
159
|
-
|
197
|
+
context 'when record is new' do
|
198
|
+
let(:instance) { klass.new(name: value) }
|
160
199
|
|
161
|
-
|
162
|
-
|
200
|
+
it { is_expected.to eq({ 'name' => value }) }
|
201
|
+
|
202
|
+
context 'changing shard key value' do
|
203
|
+
let(:new_value) { 'a-new-value' }
|
204
|
+
|
205
|
+
before do
|
206
|
+
instance.name = new_value
|
207
|
+
end
|
208
|
+
|
209
|
+
it { is_expected.to eq({ 'name' => new_value }) }
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
context 'when record is persisted' do
|
214
|
+
let(:instance) { klass.create!(name: value) }
|
215
|
+
|
216
|
+
it { is_expected.to eq({ 'name' => value }) }
|
217
|
+
|
218
|
+
context 'changing shard key value' do
|
219
|
+
let(:new_value) { 'a-new-value' }
|
220
|
+
|
221
|
+
before do
|
222
|
+
instance.name = new_value
|
223
|
+
end
|
224
|
+
|
225
|
+
it { is_expected.to eq({ 'name' => value }) }
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
context "when record is not found" do
|
230
|
+
let!(:instance) { klass.create!(name: value) }
|
163
231
|
|
164
232
|
before do
|
165
|
-
instance.
|
233
|
+
instance.destroy
|
166
234
|
end
|
167
235
|
|
168
|
-
it
|
169
|
-
|
236
|
+
it "raises a DocumentNotFound error" do
|
237
|
+
expect do
|
238
|
+
instance.reload
|
239
|
+
end.to raise_error(Mongoid::Errors::DocumentNotFound)
|
170
240
|
end
|
171
241
|
end
|
172
242
|
end
|
173
243
|
|
174
|
-
context 'when
|
175
|
-
let(:
|
244
|
+
context 'when key is an embedded attribute' do
|
245
|
+
let(:klass) { SmReview }
|
246
|
+
let(:value) { 'Arthur Conan Doyle' }
|
247
|
+
let(:key) { 'author.name' }
|
176
248
|
|
177
|
-
|
249
|
+
context 'when record is new' do
|
250
|
+
let(:instance) { klass.new(author: { name: value }) }
|
178
251
|
|
179
|
-
|
180
|
-
let(:new_value) { 'a-new-value' }
|
252
|
+
it { is_expected.to eq({ key => value }) }
|
181
253
|
|
182
|
-
|
183
|
-
|
254
|
+
context 'changing shard key value' do
|
255
|
+
let(:new_value) { 'Jules Verne' }
|
256
|
+
|
257
|
+
before do
|
258
|
+
instance.author.name = new_value
|
259
|
+
end
|
260
|
+
|
261
|
+
it { is_expected.to eq({ key => new_value }) }
|
184
262
|
end
|
263
|
+
end
|
185
264
|
|
186
|
-
|
265
|
+
context 'when record is persisted' do
|
266
|
+
let(:instance) { klass.create!(author: { name: value }) }
|
267
|
+
|
268
|
+
it { is_expected.to eq({ key => value }) }
|
269
|
+
|
270
|
+
context 'changing shard key value' do
|
271
|
+
let(:new_value) { 'Jules Verne' }
|
272
|
+
|
273
|
+
before do
|
274
|
+
instance.author.name = new_value
|
275
|
+
end
|
276
|
+
|
277
|
+
it { is_expected.to eq({ key => value }) }
|
278
|
+
end
|
279
|
+
|
280
|
+
context "when record is not found" do
|
281
|
+
let!(:instance) { klass.create!(author: { name: value }) }
|
282
|
+
|
283
|
+
before do
|
284
|
+
instance.destroy
|
285
|
+
end
|
286
|
+
|
287
|
+
it "raises a DocumentNotFound error" do
|
288
|
+
expect do
|
289
|
+
instance.reload
|
290
|
+
end.to raise_error(Mongoid::Errors::DocumentNotFound)
|
291
|
+
end
|
292
|
+
end
|
187
293
|
end
|
188
294
|
end
|
189
295
|
end
|
data/spec/mongoid_spec.rb
CHANGED
@@ -51,8 +51,14 @@ describe Mongoid do
|
|
51
51
|
end
|
52
52
|
|
53
53
|
it "disconnects from all active clients" do
|
54
|
+
method_name = if Gem::Version.new(Mongo::VERSION) >= Gem::Version.new('2.19.0')
|
55
|
+
:close
|
56
|
+
else
|
57
|
+
:disconnect!
|
58
|
+
end
|
59
|
+
|
54
60
|
clients.each do |client|
|
55
|
-
expect(client.cluster).to receive(
|
61
|
+
expect(client.cluster).to receive(method_name).and_call_original
|
56
62
|
end
|
57
63
|
Mongoid.disconnect_clients
|
58
64
|
end
|
@@ -123,10 +123,6 @@ 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+/))
|
130
126
|
run_command(BASE_TEST_COMMAND + tty_arg + extra_env + [
|
131
127
|
'-e', %q`TEST_CMD=watch -x bash -c "ps awwxu |egrep 'mongo|ocsp'"`,
|
132
128
|
'-e', 'BIND_ALL=true',
|
@@ -209,6 +209,14 @@ module Mrss
|
|
209
209
|
end
|
210
210
|
end
|
211
211
|
|
212
|
+
def require_no_fallbacks
|
213
|
+
before(:all) do
|
214
|
+
if %w(yes true 1).include?((ENV['TEST_I18N_FALLBACKS'] || '').downcase)
|
215
|
+
skip 'Set TEST_I18N_FALLBACKS=0 environment variable to run these tests'
|
216
|
+
end
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
212
220
|
# This is a macro for retrying flaky tests on CI that occasionally fail.
|
213
221
|
# Note that the tests will only be retried on CI.
|
214
222
|
#
|
data/spec/shared/shlib/server.sh
CHANGED
@@ -71,12 +71,12 @@ prepare_server_from_url() {
|
|
71
71
|
export PATH="$BINDIR":$PATH
|
72
72
|
}
|
73
73
|
|
74
|
-
|
74
|
+
install_mlaunch_venv() {
|
75
75
|
python3 -V || true
|
76
|
-
if ! python3 -m
|
76
|
+
if ! python3 -m venv -h >/dev/null; then
|
77
77
|
# Current virtualenv fails with
|
78
78
|
# https://github.com/pypa/virtualenv/issues/1630
|
79
|
-
python3 -m pip install
|
79
|
+
python3 -m pip install venv --user
|
80
80
|
fi
|
81
81
|
if test "$USE_SYSTEM_PYTHON_PACKAGES" = 1 &&
|
82
82
|
python3 -m pip list |grep mtools
|
@@ -85,13 +85,13 @@ install_mlaunch_virtualenv() {
|
|
85
85
|
:
|
86
86
|
else
|
87
87
|
venvpath="$MONGO_ORCHESTRATION_HOME"/venv
|
88
|
-
python3 -m
|
88
|
+
python3 -m venv $venvpath
|
89
89
|
. $venvpath/bin/activate
|
90
90
|
# [mlaunch] does not work:
|
91
91
|
# https://github.com/rueckstiess/mtools/issues/856
|
92
92
|
# dateutil dependency is missing in mtools: https://github.com/rueckstiess/mtools/issues/864
|
93
93
|
#pip install 'mtools==1.7' 'pymongo==4.1' python-dateutil psutil
|
94
|
-
|
94
|
+
|
95
95
|
# dateutil dependency is missing in mtools: https://github.com/rueckstiess/mtools/issues/864
|
96
96
|
pip install 'mtools-legacy[mlaunch]' 'pymongo<4' python-dateutil
|
97
97
|
fi
|
data.tar.gz.sig
CHANGED
Binary file
|