mongoid 7.1.6 → 7.1.10
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.tar.gz.sig +0 -0
- data/README.md +1 -1
- data/Rakefile +31 -0
- data/lib/mongoid.rb +1 -0
- data/lib/mongoid/association/embedded/embeds_many/proxy.rb +1 -1
- data/lib/mongoid/association/proxy.rb +1 -1
- data/lib/mongoid/association/referenced/has_many/enumerable.rb +1 -1
- data/lib/mongoid/association/referenced/has_many/proxy.rb +1 -1
- data/lib/mongoid/attributes.rb +8 -1
- data/lib/mongoid/criteria.rb +1 -1
- data/lib/mongoid/criteria/queryable/selector.rb +0 -4
- data/lib/mongoid/document.rb +3 -2
- data/lib/mongoid/errors/mongoid_error.rb +1 -1
- data/lib/mongoid/interceptable.rb +4 -2
- data/lib/mongoid/reloadable.rb +5 -0
- data/lib/mongoid/validatable/associated.rb +1 -1
- data/lib/mongoid/validatable/presence.rb +3 -3
- data/lib/mongoid/validatable/uniqueness.rb +1 -1
- data/lib/mongoid/version.rb +1 -1
- data/lib/rails/generators/mongoid/config/config_generator.rb +8 -1
- data/lib/rails/generators/mongoid/config/templates/mongoid.yml +1 -1
- data/spec/app/models/address.rb +4 -0
- data/spec/app/models/customer.rb +11 -0
- data/spec/app/models/customer_address.rb +12 -0
- data/spec/app/models/dictionary.rb +6 -0
- data/spec/app/models/person.rb +9 -0
- data/spec/integration/app_spec.rb +178 -88
- data/spec/integration/callbacks_models.rb +49 -0
- data/spec/integration/callbacks_spec.rb +216 -0
- data/spec/integration/document_spec.rb +21 -0
- data/spec/lite_spec_helper.rb +6 -6
- data/spec/mongoid/association/embedded/embedded_in/proxy_spec.rb +50 -0
- data/spec/mongoid/association/embedded/embeds_many/proxy_spec.rb +17 -4
- data/spec/mongoid/association/referenced/belongs_to/proxy_spec.rb +17 -0
- data/spec/mongoid/atomic/paths_spec.rb +41 -0
- data/spec/mongoid/attributes_spec.rb +241 -0
- data/spec/mongoid/clients/options_spec.rb +2 -0
- data/spec/mongoid/contextual/atomic_spec.rb +17 -4
- data/spec/mongoid/criteria/queryable/selectable_logical_spec.rb +36 -0
- data/spec/mongoid/criteria_spec.rb +4 -0
- data/spec/mongoid/document_query_spec.rb +51 -0
- data/spec/mongoid/errors/mongoid_error_spec.rb +20 -8
- data/spec/mongoid/factory_spec.rb +2 -2
- data/spec/mongoid/persistable/savable_spec.rb +4 -4
- data/spec/mongoid/persistable/settable_spec.rb +30 -0
- data/spec/mongoid/persistable_spec.rb +2 -2
- data/spec/shared/bin/get-mongodb-download-url +17 -0
- data/spec/shared/bin/s3-copy +45 -0
- data/spec/shared/bin/s3-upload +69 -0
- data/spec/shared/lib/mrss/cluster_config.rb +19 -4
- data/spec/shared/lib/mrss/constraints.rb +62 -6
- data/spec/shared/lib/mrss/docker_runner.rb +271 -0
- data/spec/shared/lib/mrss/lite_constraints.rb +16 -0
- data/spec/shared/lib/mrss/server_version_registry.rb +115 -0
- data/spec/shared/lib/mrss/spec_organizer.rb +32 -2
- data/spec/shared/lib/mrss/utils.rb +15 -0
- data/spec/shared/share/Dockerfile.erb +322 -0
- data/spec/shared/share/haproxy-1.conf +16 -0
- data/spec/shared/share/haproxy-2.conf +17 -0
- data/spec/shared/shlib/distro.sh +73 -0
- data/spec/shared/shlib/server.sh +317 -0
- data/spec/shared/shlib/set_env.sh +131 -0
- data/spec/spec_helper.rb +3 -1
- data/spec/support/constraints.rb +0 -226
- data/spec/support/spec_config.rb +8 -0
- metadata +542 -480
- metadata.gz.sig +0 -0
- data/spec/support/child_process_helper.rb +0 -76
- data/spec/support/lite_constraints.rb +0 -22
@@ -245,6 +245,97 @@ describe Mongoid::Attributes do
|
|
245
245
|
end
|
246
246
|
end
|
247
247
|
|
248
|
+
context "when the field was not explicitly defined" do
|
249
|
+
|
250
|
+
context "when excluding with only and the field was not excluded" do
|
251
|
+
|
252
|
+
let(:from_db) do
|
253
|
+
Person.only(:_id).first
|
254
|
+
end
|
255
|
+
|
256
|
+
it "raises an error" do
|
257
|
+
expect {
|
258
|
+
from_db[:undefined_field]
|
259
|
+
}.to raise_error(ActiveModel::MissingAttributeError)
|
260
|
+
end
|
261
|
+
end
|
262
|
+
|
263
|
+
context "when excluding with without and the field was excluded" do
|
264
|
+
|
265
|
+
let(:from_db) do
|
266
|
+
Person.without(:title).first
|
267
|
+
end
|
268
|
+
|
269
|
+
it "raises an error" do
|
270
|
+
expect {
|
271
|
+
from_db[:title]
|
272
|
+
}.to raise_error(ActiveModel::MissingAttributeError)
|
273
|
+
end
|
274
|
+
end
|
275
|
+
|
276
|
+
context "when excluding with without and the field was not excluded" do
|
277
|
+
|
278
|
+
let(:from_db) do
|
279
|
+
Person.without(:title).first
|
280
|
+
end
|
281
|
+
|
282
|
+
it "returns nil" do
|
283
|
+
from_db[:undefined_field].should be nil
|
284
|
+
end
|
285
|
+
end
|
286
|
+
end
|
287
|
+
|
288
|
+
context 'when projecting with #only' do
|
289
|
+
let!(:person) do
|
290
|
+
Person.create(title: 'sir', name: { first_name: 'Jose', language: { name: 'es' } })
|
291
|
+
end
|
292
|
+
|
293
|
+
context 'when projecting an embedded association' do
|
294
|
+
let(:from_db) do
|
295
|
+
Person.only(:name).first
|
296
|
+
end
|
297
|
+
|
298
|
+
context 'when retrieving a field of the association using the dot notation' do
|
299
|
+
|
300
|
+
it 'retrieves the field' do
|
301
|
+
pending 'MONGOID-5032, fixed in 7.3'
|
302
|
+
|
303
|
+
expect(from_db['name.first_name']).to eq 'Jose'
|
304
|
+
end
|
305
|
+
end
|
306
|
+
|
307
|
+
context 'when retrieving a field of a nested association using the dot notation' do
|
308
|
+
it 'retrieves the field' do
|
309
|
+
pending 'MONGOID-5032, fixed in 7.3'
|
310
|
+
|
311
|
+
expect(from_db['name.language.name']).to eq 'es'
|
312
|
+
end
|
313
|
+
end
|
314
|
+
end
|
315
|
+
|
316
|
+
context 'when projecting a sub-association of an embedded association' do
|
317
|
+
let(:from_db) do
|
318
|
+
Person.only('name.language').first
|
319
|
+
end
|
320
|
+
|
321
|
+
context 'when retrieving a field under the projected sub-association' do
|
322
|
+
it 'retrieves the field' do
|
323
|
+
pending 'MONGOID-5032, fixed in 7.3'
|
324
|
+
|
325
|
+
expect(from_db['name.language.name']).to eq 'es'
|
326
|
+
end
|
327
|
+
end
|
328
|
+
|
329
|
+
context 'when retrieving a non-projected field' do
|
330
|
+
it 'raises MissingAttributeError' do
|
331
|
+
expect do
|
332
|
+
from_db['name.first_name']
|
333
|
+
end.to raise_error(ActiveModel::MissingAttributeError)
|
334
|
+
end
|
335
|
+
end
|
336
|
+
end
|
337
|
+
end
|
338
|
+
|
248
339
|
context "when the attribute does not exist" do
|
249
340
|
|
250
341
|
before do
|
@@ -329,6 +420,67 @@ describe Mongoid::Attributes do
|
|
329
420
|
expect(terms).to eq(true)
|
330
421
|
end
|
331
422
|
end
|
423
|
+
|
424
|
+
context 'when the field is not explicitly defined' do
|
425
|
+
let(:bar) { Bar.new }
|
426
|
+
|
427
|
+
before do
|
428
|
+
bar['missing_field'] = 42
|
429
|
+
end
|
430
|
+
|
431
|
+
it 'writes the value into attributes' do
|
432
|
+
bar.attributes.should == {'_id' => bar.id, 'missing_field' => 42}
|
433
|
+
end
|
434
|
+
|
435
|
+
it 'makes the attribute accessible via []' do
|
436
|
+
bar['missing_field'].should == 42
|
437
|
+
end
|
438
|
+
|
439
|
+
context 'when writing fields on a document with projection' do
|
440
|
+
|
441
|
+
let!(:person) do
|
442
|
+
Person.create(title: "sir")
|
443
|
+
end
|
444
|
+
|
445
|
+
context "when excluding with only and the field was not excluded" do
|
446
|
+
|
447
|
+
let(:from_db) do
|
448
|
+
Person.only(:_id).first
|
449
|
+
end
|
450
|
+
|
451
|
+
it "raises an error" do
|
452
|
+
expect {
|
453
|
+
from_db[:undefined_field] = 'x'
|
454
|
+
}.to raise_error(ActiveModel::MissingAttributeError)
|
455
|
+
end
|
456
|
+
end
|
457
|
+
|
458
|
+
context "when excluding with without and the field was excluded" do
|
459
|
+
|
460
|
+
let(:from_db) do
|
461
|
+
Person.without(:title).first
|
462
|
+
end
|
463
|
+
|
464
|
+
it "raises an error" do
|
465
|
+
expect {
|
466
|
+
from_db[:title] = 'x'
|
467
|
+
}.to raise_error(ActiveModel::MissingAttributeError)
|
468
|
+
end
|
469
|
+
end
|
470
|
+
|
471
|
+
context "when excluding with without and the field was not excluded" do
|
472
|
+
|
473
|
+
let(:from_db) do
|
474
|
+
Person.without(:title).first
|
475
|
+
end
|
476
|
+
|
477
|
+
it "writes the value" do
|
478
|
+
from_db[:undefined_field] = 'x'
|
479
|
+
from_db[:undefined_field].should == 'x'
|
480
|
+
end
|
481
|
+
end
|
482
|
+
end
|
483
|
+
end
|
332
484
|
end
|
333
485
|
|
334
486
|
describe "#_id" do
|
@@ -893,6 +1045,50 @@ describe Mongoid::Attributes do
|
|
893
1045
|
expect(person.age_before_type_cast).to eq("old")
|
894
1046
|
end
|
895
1047
|
end
|
1048
|
+
|
1049
|
+
context 'when reading fields on a document with projection' do
|
1050
|
+
|
1051
|
+
let!(:person) do
|
1052
|
+
Person.create(title: "sir")
|
1053
|
+
end
|
1054
|
+
|
1055
|
+
context "when excluding with only and the field was not excluded" do
|
1056
|
+
|
1057
|
+
let(:from_db) do
|
1058
|
+
Person.only(:_id).first
|
1059
|
+
end
|
1060
|
+
|
1061
|
+
it "raises an error" do
|
1062
|
+
expect {
|
1063
|
+
from_db.read_attribute(:undefined_field)
|
1064
|
+
}.to raise_error(ActiveModel::MissingAttributeError)
|
1065
|
+
end
|
1066
|
+
end
|
1067
|
+
|
1068
|
+
context "when excluding with without and the field was excluded" do
|
1069
|
+
|
1070
|
+
let(:from_db) do
|
1071
|
+
Person.without(:title).first
|
1072
|
+
end
|
1073
|
+
|
1074
|
+
it "raises an error" do
|
1075
|
+
expect {
|
1076
|
+
from_db.read_attribute(:title)
|
1077
|
+
}.to raise_error(ActiveModel::MissingAttributeError)
|
1078
|
+
end
|
1079
|
+
end
|
1080
|
+
|
1081
|
+
context "when excluding with without and the field was not excluded" do
|
1082
|
+
|
1083
|
+
let(:from_db) do
|
1084
|
+
Person.without(:title).first
|
1085
|
+
end
|
1086
|
+
|
1087
|
+
it "returns nil" do
|
1088
|
+
from_db.read_attribute(:undefined_field).should be nil
|
1089
|
+
end
|
1090
|
+
end
|
1091
|
+
end
|
896
1092
|
end
|
897
1093
|
|
898
1094
|
describe "#attribute_present?" do
|
@@ -1398,6 +1594,51 @@ describe Mongoid::Attributes do
|
|
1398
1594
|
expect(dictionary.description).to eq('foo')
|
1399
1595
|
end
|
1400
1596
|
end
|
1597
|
+
|
1598
|
+
context 'when writing fields on a document with projection' do
|
1599
|
+
|
1600
|
+
let!(:person) do
|
1601
|
+
Person.create(title: "sir")
|
1602
|
+
end
|
1603
|
+
|
1604
|
+
context "when excluding with only and the field was not excluded" do
|
1605
|
+
|
1606
|
+
let(:from_db) do
|
1607
|
+
Person.only(:_id).first
|
1608
|
+
end
|
1609
|
+
|
1610
|
+
it "raises an error" do
|
1611
|
+
expect {
|
1612
|
+
from_db.write_attribute(:undefined_field, 'x')
|
1613
|
+
}.to raise_error(ActiveModel::MissingAttributeError)
|
1614
|
+
end
|
1615
|
+
end
|
1616
|
+
|
1617
|
+
context "when excluding with without and the field was excluded" do
|
1618
|
+
|
1619
|
+
let(:from_db) do
|
1620
|
+
Person.without(:title).first
|
1621
|
+
end
|
1622
|
+
|
1623
|
+
it "raises an error" do
|
1624
|
+
expect {
|
1625
|
+
from_db.write_attribute(:title, 'x')
|
1626
|
+
}.to raise_error(ActiveModel::MissingAttributeError)
|
1627
|
+
end
|
1628
|
+
end
|
1629
|
+
|
1630
|
+
context "when excluding with without and the field was not excluded" do
|
1631
|
+
|
1632
|
+
let(:from_db) do
|
1633
|
+
Person.without(:title).first
|
1634
|
+
end
|
1635
|
+
|
1636
|
+
it "writes the value" do
|
1637
|
+
from_db.write_attribute(:undefined_field, 'x')
|
1638
|
+
from_db.read_attribute(:undefined_field).should == 'x'
|
1639
|
+
end
|
1640
|
+
end
|
1641
|
+
end
|
1401
1642
|
end
|
1402
1643
|
|
1403
1644
|
describe "#typed_value_for" do
|
@@ -141,6 +141,8 @@ describe Mongoid::Clients::Options, retry: 3 do
|
|
141
141
|
end
|
142
142
|
|
143
143
|
it 'does not disconnect the original cluster' do
|
144
|
+
skip 'https://jira.mongodb.org/browse/MONGOID-5130'
|
145
|
+
|
144
146
|
expect(connections_after).to eq(connections_before)
|
145
147
|
expect(cluster_before).to be(cluster_after)
|
146
148
|
end
|
@@ -753,12 +753,25 @@ describe Mongoid::Contextual::Atomic do
|
|
753
753
|
context.set(name: "Recoil")
|
754
754
|
end
|
755
755
|
|
756
|
-
|
757
|
-
|
756
|
+
shared_examples 'writes as expected' do
|
757
|
+
it "sets existing fields" do
|
758
|
+
expect(depeche_mode.reload.name).to eq("Recoil")
|
759
|
+
end
|
760
|
+
|
761
|
+
it "sets non existent fields" do
|
762
|
+
expect(smiths.reload.name).to eq("Recoil")
|
763
|
+
end
|
758
764
|
end
|
759
765
|
|
760
|
-
|
761
|
-
|
766
|
+
include_examples 'writes as expected'
|
767
|
+
|
768
|
+
context 'when fields being set have been projected out' do
|
769
|
+
|
770
|
+
let(:criteria) do
|
771
|
+
Band.only(:genres)
|
772
|
+
end
|
773
|
+
|
774
|
+
include_examples 'writes as expected'
|
762
775
|
end
|
763
776
|
end
|
764
777
|
|
@@ -1447,6 +1447,42 @@ describe Mongoid::Criteria::Queryable::Selectable do
|
|
1447
1447
|
end
|
1448
1448
|
end
|
1449
1449
|
end
|
1450
|
+
|
1451
|
+
context 'when using multiple criteria and symbol operators' do
|
1452
|
+
context 'when using fields that meaningfully evolve values' do
|
1453
|
+
|
1454
|
+
let(:query) do
|
1455
|
+
Dictionary.any_of({a: 1}, :published.gt => Date.new(2020, 2, 3))
|
1456
|
+
end
|
1457
|
+
|
1458
|
+
it 'generates the expected query' do
|
1459
|
+
query.selector.should == {'$or' => [
|
1460
|
+
{'a' => 1},
|
1461
|
+
# Date instance is converted to a Time instance in local time,
|
1462
|
+
# because we are querying on a Time field and dates are interpreted
|
1463
|
+
# in local time when assigning to Time fields
|
1464
|
+
{'published' => {'$gt' => Time.local(2020, 2, 3)}},
|
1465
|
+
]}
|
1466
|
+
end
|
1467
|
+
end
|
1468
|
+
|
1469
|
+
context 'when using fields that do not meaningfully evolve values' do
|
1470
|
+
|
1471
|
+
let(:query) do
|
1472
|
+
Dictionary.any_of({a: 1}, :submitted_on.gt => Date.new(2020, 2, 3))
|
1473
|
+
end
|
1474
|
+
|
1475
|
+
it 'generates the expected query' do
|
1476
|
+
query.selector.should == {'$or' => [
|
1477
|
+
{'a' => 1},
|
1478
|
+
# Date instance is converted to a Time instance in UTC,
|
1479
|
+
# because we are querying on a Date field and dates are interpreted
|
1480
|
+
# in UTC when persisted as dates by Mongoid
|
1481
|
+
{'submitted_on' => {'$gt' => Time.utc(2020, 2, 3)}},
|
1482
|
+
]}
|
1483
|
+
end
|
1484
|
+
end
|
1485
|
+
end
|
1450
1486
|
end
|
1451
1487
|
|
1452
1488
|
describe "#not" do
|
@@ -3645,10 +3645,14 @@ describe Mongoid::Criteria do
|
|
3645
3645
|
|
3646
3646
|
before do
|
3647
3647
|
expect(Person).to receive(:minor).and_call_original
|
3648
|
+
expect(Person).to receive(:older_than).and_call_original
|
3648
3649
|
end
|
3649
3650
|
|
3650
3651
|
it "calls the method on the class" do
|
3651
3652
|
expect(criteria.minor).to be_empty
|
3653
|
+
expect do
|
3654
|
+
criteria.older_than(age: 25)
|
3655
|
+
end.not_to raise_error
|
3652
3656
|
end
|
3653
3657
|
end
|
3654
3658
|
|
@@ -36,4 +36,55 @@ describe Mongoid::Document do
|
|
36
36
|
expect(_person.age).to be 42
|
37
37
|
end
|
38
38
|
end
|
39
|
+
|
40
|
+
context 'when projecting with #without' do
|
41
|
+
before do
|
42
|
+
duck = Pet.new(name: 'Duck')
|
43
|
+
Person.create!(username: 'Dev', title: 'CEO', pet: duck)
|
44
|
+
end
|
45
|
+
|
46
|
+
let(:person) { Person.where(username: 'Dev').without(:title).first }
|
47
|
+
|
48
|
+
it 'allows access to attribute of embedded document' do
|
49
|
+
expect(person.pet.name).to eq 'Duck'
|
50
|
+
end
|
51
|
+
|
52
|
+
context 'when exclusion starts with association name but is not the association' do
|
53
|
+
|
54
|
+
let(:person) { Person.where(username: 'Dev').without(:pet_).first }
|
55
|
+
|
56
|
+
it 'allows access to attribute of embedded document' do
|
57
|
+
expect(person.pet.name).to eq 'Duck'
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
context 'when exclusion starts with prefix of association name' do
|
62
|
+
|
63
|
+
let(:person) { Person.where(username: 'Dev').without(:pe).first }
|
64
|
+
|
65
|
+
it 'allows access to attribute of embedded document' do
|
66
|
+
expect(person.pet.name).to eq 'Duck'
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
context 'when another attribute of the association is excluded' do
|
71
|
+
|
72
|
+
let(:person) { Person.where(username: 'Dev').without('pet.weight').first }
|
73
|
+
|
74
|
+
it 'allows access to non-excluded attribute of embedded document' do
|
75
|
+
expect(person.pet.name).to eq 'Duck'
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
context 'when the excluded attribute of the association is retrieved' do
|
80
|
+
|
81
|
+
let(:person) { Person.where(username: 'Dev').without('pet.name').first }
|
82
|
+
|
83
|
+
it 'prohibits the retrieval' do
|
84
|
+
lambda do
|
85
|
+
person.pet.name
|
86
|
+
end.should raise_error(ActiveModel::MissingAttributeError)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
39
90
|
end
|
@@ -10,14 +10,26 @@ describe Mongoid::Errors::MongoidError do
|
|
10
10
|
let(:options) { {} }
|
11
11
|
|
12
12
|
before do
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
13
|
+
if RUBY_VERSION.start_with?('3.', '2.7')
|
14
|
+
{"message_title" => "message", "summary_title" => "summary", "resolution_title" => "resolution"}.each do |key, name|
|
15
|
+
expect(::I18n).to receive(:translate).with("mongoid.errors.messages.#{key}", **{}).and_return(name)
|
16
|
+
end
|
17
|
+
|
18
|
+
["message", "summary", "resolution"].each do |name|
|
19
|
+
expect(::I18n).to receive(:translate).
|
20
|
+
with("mongoid.errors.messages.#{key}.#{name}", **{}).
|
21
|
+
and_return(name)
|
22
|
+
end
|
23
|
+
else
|
24
|
+
{"message_title" => "message", "summary_title" => "summary", "resolution_title" => "resolution"}.each do |key, name|
|
25
|
+
expect(::I18n).to receive(:translate).with("mongoid.errors.messages.#{key}", {}).and_return(name)
|
26
|
+
end
|
27
|
+
|
28
|
+
["message", "summary", "resolution"].each do |name|
|
29
|
+
expect(::I18n).to receive(:translate).
|
30
|
+
with("mongoid.errors.messages.#{key}.#{name}", {}).
|
31
|
+
and_return(name)
|
32
|
+
end
|
21
33
|
end
|
22
34
|
|
23
35
|
error.compose_message(key, options)
|