mongoid 6.4.1 → 6.4.8
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 +5 -5
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +1 -3
- data/Rakefile +26 -0
- data/lib/mongoid.rb +1 -1
- data/lib/mongoid/contextual/map_reduce.rb +1 -1
- data/lib/mongoid/criteria/modifiable.rb +12 -2
- data/lib/mongoid/criteria/queryable/selectable.rb +34 -7
- data/lib/mongoid/document.rb +4 -4
- data/lib/mongoid/extensions/big_decimal.rb +1 -1
- data/lib/mongoid/extensions/regexp.rb +1 -0
- data/lib/mongoid/extensions/string.rb +3 -1
- data/lib/mongoid/matchable.rb +3 -0
- data/lib/mongoid/matchable/nor.rb +37 -0
- data/lib/mongoid/persistable/settable.rb +5 -5
- data/lib/mongoid/persistence_context.rb +4 -0
- data/lib/mongoid/query_cache.rb +64 -19
- data/lib/mongoid/railtie.rb +17 -0
- data/lib/mongoid/railties/controller_runtime.rb +86 -0
- data/lib/mongoid/scopable.rb +3 -3
- data/lib/mongoid/threaded.rb +36 -0
- data/lib/mongoid/version.rb +1 -1
- data/spec/app/models/array_field.rb +7 -0
- data/spec/app/models/delegating_patient.rb +16 -0
- data/spec/integration/document_spec.rb +22 -0
- data/spec/mongoid/clients/factory_spec.rb +52 -28
- data/spec/mongoid/clients/options_spec.rb +30 -15
- data/spec/mongoid/clients/sessions_spec.rb +12 -3
- data/spec/mongoid/contextual/geo_near_spec.rb +1 -0
- data/spec/mongoid/contextual/mongo_spec.rb +2 -2
- data/spec/mongoid/criteria/modifiable_spec.rb +59 -10
- data/spec/mongoid/criteria/queryable/extensions/big_decimal_spec.rb +3 -3
- data/spec/mongoid/criteria/queryable/selectable_spec.rb +42 -3
- data/spec/mongoid/criteria/queryable/selector_spec.rb +2 -2
- data/spec/mongoid/criteria/scopable_spec.rb +81 -0
- data/spec/mongoid/criteria_spec.rb +4 -1
- data/spec/mongoid/document_spec.rb +54 -0
- data/spec/mongoid/extensions/big_decimal_spec.rb +9 -9
- data/spec/mongoid/extensions/regexp_spec.rb +23 -0
- data/spec/mongoid/extensions/string_spec.rb +35 -7
- data/spec/mongoid/fields_spec.rb +1 -1
- data/spec/mongoid/findable_spec.rb +1 -1
- data/spec/mongoid/matchable/nor_spec.rb +209 -0
- data/spec/mongoid/matchable_spec.rb +26 -1
- data/spec/mongoid/persistable/incrementable_spec.rb +6 -6
- data/spec/mongoid/persistable/settable_spec.rb +19 -0
- data/spec/mongoid/query_cache_spec.rb +87 -18
- data/spec/mongoid/scopable_spec.rb +13 -0
- data/spec/mongoid/threaded_spec.rb +68 -0
- data/spec/rails/controller_extension/controller_runtime_spec.rb +110 -0
- data/spec/spec_helper.rb +10 -0
- data/spec/support/cluster_config.rb +158 -0
- data/spec/support/constraints.rb +101 -0
- data/spec/support/macros.rb +20 -0
- data/spec/support/session_registry.rb +50 -0
- data/spec/support/spec_config.rb +42 -0
- metadata +43 -23
- metadata.gz.sig +0 -0
@@ -16,17 +16,26 @@ describe Mongoid::Clients::Sessions do
|
|
16
16
|
end
|
17
17
|
|
18
18
|
let(:subscriber) do
|
19
|
-
Mongoid::Clients.with_name(:other)
|
19
|
+
client = Mongoid::Clients.with_name(:other)
|
20
|
+
monitoring = if client.respond_to?(:monitoring, true)
|
21
|
+
client.send(:monitoring)
|
22
|
+
else
|
23
|
+
# driver 2.5
|
24
|
+
client.instance_variable_get('@monitoring')
|
25
|
+
end
|
26
|
+
monitoring.subscribers['Command'].find do |s|
|
20
27
|
s.is_a?(EventSubscriber)
|
21
28
|
end
|
22
29
|
end
|
23
30
|
|
24
31
|
let(:insert_events) do
|
25
|
-
|
32
|
+
# Driver 2.5 sends command_name as a symbol
|
33
|
+
subscriber.started_events.select { |event| event.command_name.to_s == 'insert' }
|
26
34
|
end
|
27
35
|
|
28
36
|
let(:update_events) do
|
29
|
-
|
37
|
+
# Driver 2.5 sends command_name as a symbol
|
38
|
+
subscriber.started_events.select { |event| event.command_name.to_s == 'update' }
|
30
39
|
end
|
31
40
|
|
32
41
|
context 'when a session is used on a model class' do
|
@@ -451,7 +451,7 @@ describe Mongoid::Contextual::Mongo do
|
|
451
451
|
end
|
452
452
|
|
453
453
|
it "returns the distinct field values" do
|
454
|
-
expect(context.distinct(:years)).to eq([
|
454
|
+
expect(context.distinct(:years).sort).to eq([ 25, 30 ])
|
455
455
|
end
|
456
456
|
end
|
457
457
|
|
@@ -2363,7 +2363,7 @@ describe Mongoid::Contextual::Mongo do
|
|
2363
2363
|
end
|
2364
2364
|
|
2365
2365
|
it 'creates a pipeline with the selector as one of the $match criteria' do
|
2366
|
-
expect(pipeline_match).to include({
|
2366
|
+
expect(pipeline_match).to include({ '$text' => { '$search' => "New Order" } })
|
2367
2367
|
end
|
2368
2368
|
|
2369
2369
|
it 'creates a pipeline with the $exists operator as one of the $match criteria' do
|
@@ -1471,11 +1471,15 @@ describe Mongoid::Criteria::Modifiable do
|
|
1471
1471
|
{ 'username' => 'Turnip' }
|
1472
1472
|
end
|
1473
1473
|
|
1474
|
-
it '
|
1475
|
-
expect(Person.create_with(attrs).selector).to
|
1474
|
+
it 'does not modify the selector' do
|
1475
|
+
expect(Person.create_with(attrs).selector[:username]).to be_nil
|
1476
1476
|
end
|
1477
1477
|
|
1478
|
-
|
1478
|
+
it 'create_attrs is modified' do
|
1479
|
+
expect(Person.create_with(attrs).create_attrs).to eq(attrs)
|
1480
|
+
end
|
1481
|
+
|
1482
|
+
context 'when a create is chained' do
|
1479
1483
|
|
1480
1484
|
context 'when a write method is chained' do
|
1481
1485
|
|
@@ -1499,6 +1503,25 @@ describe Mongoid::Criteria::Modifiable do
|
|
1499
1503
|
expect(new_person.age).to eq(50)
|
1500
1504
|
end
|
1501
1505
|
|
1506
|
+
context 'when a matching document is already in the collection' do
|
1507
|
+
let(:query) do
|
1508
|
+
{ 'username' => 'foo', 'age' => 12 }
|
1509
|
+
end
|
1510
|
+
|
1511
|
+
let(:person) do
|
1512
|
+
Person.create!(query)
|
1513
|
+
end
|
1514
|
+
|
1515
|
+
let(:found_person) do
|
1516
|
+
Person.create_with(attrs).find_or_create_by(query)
|
1517
|
+
end
|
1518
|
+
|
1519
|
+
it 'finds the matching document' do
|
1520
|
+
person
|
1521
|
+
expect(found_person.id).to eq(person.id)
|
1522
|
+
end
|
1523
|
+
end
|
1524
|
+
|
1502
1525
|
context 'when the attributes are shared with the write method args' do
|
1503
1526
|
|
1504
1527
|
let(:query) do
|
@@ -1509,7 +1532,7 @@ describe Mongoid::Criteria::Modifiable do
|
|
1509
1532
|
Person.create_with(attrs).find_or_create_by(query)
|
1510
1533
|
end
|
1511
1534
|
|
1512
|
-
it 'gives the
|
1535
|
+
it 'gives the find method args precedence' do
|
1513
1536
|
expect(new_person.username).to eq('Beet')
|
1514
1537
|
expect(new_person.age).to eq(50)
|
1515
1538
|
end
|
@@ -1536,8 +1559,12 @@ describe Mongoid::Criteria::Modifiable do
|
|
1536
1559
|
{ 'username' => 'Beet', 'age' => 50 }
|
1537
1560
|
end
|
1538
1561
|
|
1562
|
+
it 'does not modify the selector' do
|
1563
|
+
expect(criteria.create_with(attrs).selector).to eq(criteria_selector)
|
1564
|
+
end
|
1565
|
+
|
1539
1566
|
it 'overwrites all the original attributes' do
|
1540
|
-
expect(criteria.create_with(attrs).
|
1567
|
+
expect(criteria.create_with(attrs).create_attrs).to eq(attrs)
|
1541
1568
|
end
|
1542
1569
|
end
|
1543
1570
|
end
|
@@ -1548,8 +1575,12 @@ describe Mongoid::Criteria::Modifiable do
|
|
1548
1575
|
{ 'username' => 'Beet' }
|
1549
1576
|
end
|
1550
1577
|
|
1578
|
+
it 'does not modify the selector' do
|
1579
|
+
expect(criteria.create_with(attrs).selector).to eq(criteria_selector)
|
1580
|
+
end
|
1581
|
+
|
1551
1582
|
it 'only overwrites the shared attributes' do
|
1552
|
-
expect(criteria.create_with(attrs).
|
1583
|
+
expect(criteria.create_with(attrs).create_attrs).to eq(attrs)
|
1553
1584
|
end
|
1554
1585
|
end
|
1555
1586
|
|
@@ -1558,12 +1589,11 @@ describe Mongoid::Criteria::Modifiable do
|
|
1558
1589
|
let(:attrs) do
|
1559
1590
|
{ 'username' => 'Turnip' }
|
1560
1591
|
end
|
1561
|
-
|
1562
1592
|
let(:query) do
|
1563
1593
|
{ 'username' => 'Beet', 'age' => 50 }
|
1564
1594
|
end
|
1565
1595
|
|
1566
|
-
context 'when a
|
1596
|
+
context 'when a create method is chained' do
|
1567
1597
|
|
1568
1598
|
it 'executes the method' do
|
1569
1599
|
expect(criteria.create_with(attrs).new.username).to eq('Turnip')
|
@@ -1577,9 +1607,28 @@ describe Mongoid::Criteria::Modifiable do
|
|
1577
1607
|
criteria.create_with(attrs).find_or_create_by(query)
|
1578
1608
|
end
|
1579
1609
|
|
1580
|
-
it '
|
1610
|
+
it 'gives the find method arg precedence' do
|
1581
1611
|
expect(new_person.username).to eq('Beet')
|
1582
|
-
expect(new_person.age).to
|
1612
|
+
expect(new_person.age).to be(50)
|
1613
|
+
end
|
1614
|
+
|
1615
|
+
context 'when a matching document is already in the collection' do
|
1616
|
+
let(:query) do
|
1617
|
+
{ 'username' => 'foo', 'age' => 12 }
|
1618
|
+
end
|
1619
|
+
|
1620
|
+
let(:person) do
|
1621
|
+
Person.create!(query)
|
1622
|
+
end
|
1623
|
+
|
1624
|
+
let(:found_person) do
|
1625
|
+
criteria.create_with(attrs).find_or_create_by(query)
|
1626
|
+
end
|
1627
|
+
|
1628
|
+
it 'finds the matching document' do
|
1629
|
+
person
|
1630
|
+
expect(found_person.id).to eq(person.id)
|
1631
|
+
end
|
1583
1632
|
end
|
1584
1633
|
end
|
1585
1634
|
end
|
@@ -7,7 +7,7 @@ describe BigDecimal do
|
|
7
7
|
context "when provided a big decimal" do
|
8
8
|
|
9
9
|
let(:big_decimal) do
|
10
|
-
BigDecimal
|
10
|
+
BigDecimal("123456.789")
|
11
11
|
end
|
12
12
|
|
13
13
|
it "returns the decimal as a string" do
|
@@ -25,11 +25,11 @@ describe BigDecimal do
|
|
25
25
|
context "when provided an array of big decimals" do
|
26
26
|
|
27
27
|
let(:bd_one) do
|
28
|
-
BigDecimal
|
28
|
+
BigDecimal("123456.789")
|
29
29
|
end
|
30
30
|
|
31
31
|
let(:bd_two) do
|
32
|
-
BigDecimal
|
32
|
+
BigDecimal("123333.789")
|
33
33
|
end
|
34
34
|
|
35
35
|
let(:array) do
|
@@ -1073,6 +1073,26 @@ describe Mongoid::Criteria::Queryable::Selectable do
|
|
1073
1073
|
})
|
1074
1074
|
end
|
1075
1075
|
|
1076
|
+
context "when used with the $box operator ($geoWithin query) " do
|
1077
|
+
let(:selection) do
|
1078
|
+
query.geo_spacial(
|
1079
|
+
:location.within_box => [[ 1, 10 ], [ 2, 10 ]]
|
1080
|
+
)
|
1081
|
+
end
|
1082
|
+
|
1083
|
+
it "adds the $geoIntersects expression" do
|
1084
|
+
expect(selection.selector).to eq({
|
1085
|
+
"location" => {
|
1086
|
+
"$geoWithin" => {
|
1087
|
+
"$box" => [
|
1088
|
+
[ 1, 10 ], [ 2, 10 ]
|
1089
|
+
]
|
1090
|
+
}
|
1091
|
+
}
|
1092
|
+
})
|
1093
|
+
end
|
1094
|
+
end
|
1095
|
+
|
1076
1096
|
it_behaves_like "a cloning selection"
|
1077
1097
|
end
|
1078
1098
|
end
|
@@ -3369,7 +3389,7 @@ describe Mongoid::Criteria::Queryable::Selectable do
|
|
3369
3389
|
end
|
3370
3390
|
|
3371
3391
|
it "constructs a text search document" do
|
3372
|
-
expect(selection.selector).to eq({
|
3392
|
+
expect(selection.selector).to eq({ '$text' => { '$search' => "testing" }})
|
3373
3393
|
end
|
3374
3394
|
|
3375
3395
|
it "returns the cloned selectable" do
|
@@ -3383,16 +3403,35 @@ describe Mongoid::Criteria::Queryable::Selectable do
|
|
3383
3403
|
end
|
3384
3404
|
|
3385
3405
|
it "constructs a text search document" do
|
3386
|
-
expect(selection.selector[
|
3406
|
+
expect(selection.selector['$text']['$search']).to eq("essais")
|
3387
3407
|
end
|
3388
3408
|
|
3389
3409
|
it "add the options to the text search document" do
|
3390
|
-
expect(selection.selector[
|
3410
|
+
expect(selection.selector['$text'][:$language]).to eq("fr")
|
3391
3411
|
end
|
3392
3412
|
|
3393
3413
|
it_behaves_like "a cloning selection"
|
3394
3414
|
end
|
3395
3415
|
end
|
3416
|
+
|
3417
|
+
context 'when given more than once' do
|
3418
|
+
let(:selection) do
|
3419
|
+
query.text_search("one").text_search('two')
|
3420
|
+
end
|
3421
|
+
|
3422
|
+
# MongoDB server can only handle one text expression at a time,
|
3423
|
+
# per https://docs.mongodb.com/manual/reference/operator/query/text/.
|
3424
|
+
# Nonetheless we test that the query is built correctly when
|
3425
|
+
# a user supplies more than one text condition.
|
3426
|
+
it 'merges conditions' do
|
3427
|
+
expect(Mongoid.logger).to receive(:warn)
|
3428
|
+
expect(selection.selector).to eq('$and' => [
|
3429
|
+
{'$text' => {'$search' => 'one'}}
|
3430
|
+
],
|
3431
|
+
'$text' => {'$search' => 'two'},
|
3432
|
+
)
|
3433
|
+
end
|
3434
|
+
end
|
3396
3435
|
end
|
3397
3436
|
|
3398
3437
|
describe "#where" do
|
@@ -370,11 +370,11 @@ describe Mongoid::Criteria::Queryable::Selector do
|
|
370
370
|
context "when providing an array" do
|
371
371
|
|
372
372
|
let(:big_one) do
|
373
|
-
BigDecimal
|
373
|
+
BigDecimal("1.2321")
|
374
374
|
end
|
375
375
|
|
376
376
|
let(:big_two) do
|
377
|
-
BigDecimal
|
377
|
+
BigDecimal("4.2222")
|
378
378
|
end
|
379
379
|
|
380
380
|
let(:array) do
|
@@ -388,4 +388,85 @@ describe Mongoid::Criteria::Scopable do
|
|
388
388
|
end
|
389
389
|
end
|
390
390
|
end
|
391
|
+
|
392
|
+
describe 'scope and where' do
|
393
|
+
class ScopeWhereModel
|
394
|
+
include Mongoid::Document
|
395
|
+
|
396
|
+
scope :foo, -> { where(foo: true) }
|
397
|
+
end
|
398
|
+
|
399
|
+
shared_examples_for 'restricts to both' do
|
400
|
+
it 'restricts to both' do
|
401
|
+
expect(result.selector['foo']).to eq(true)
|
402
|
+
expect(result.selector['hello']).to eq('world')
|
403
|
+
end
|
404
|
+
end
|
405
|
+
|
406
|
+
context 'scope is given first' do
|
407
|
+
let(:result) { ScopeWhereModel.foo.where(hello: 'world') }
|
408
|
+
|
409
|
+
it_behaves_like 'restricts to both'
|
410
|
+
end
|
411
|
+
|
412
|
+
context 'where is given first' do
|
413
|
+
let(:result) { ScopeWhereModel.where(hello: 'world').foo }
|
414
|
+
|
415
|
+
it_behaves_like 'restricts to both'
|
416
|
+
end
|
417
|
+
end
|
418
|
+
|
419
|
+
describe 'scope with argument and where' do
|
420
|
+
class ArgumentScopeWhereModel
|
421
|
+
include Mongoid::Document
|
422
|
+
|
423
|
+
scope :my_text_search, ->(search) { where('$text' => {'$search' => search}) }
|
424
|
+
end
|
425
|
+
|
426
|
+
shared_examples_for 'restricts to both' do
|
427
|
+
it 'restricts to both' do
|
428
|
+
expect(result.selector['$text']).to eq({'$search' => 'bar'})
|
429
|
+
expect(result.selector['hello']).to eq('world')
|
430
|
+
end
|
431
|
+
end
|
432
|
+
|
433
|
+
context 'scope is given first' do
|
434
|
+
let(:result) { ArgumentScopeWhereModel.my_text_search('bar').where(hello: 'world') }
|
435
|
+
|
436
|
+
it_behaves_like 'restricts to both'
|
437
|
+
end
|
438
|
+
|
439
|
+
context 'where is given first' do
|
440
|
+
let(:result) { ArgumentScopeWhereModel.where(hello: 'world').my_text_search('bar') }
|
441
|
+
|
442
|
+
it_behaves_like 'restricts to both'
|
443
|
+
end
|
444
|
+
end
|
445
|
+
|
446
|
+
describe 'built in text search scope and where' do
|
447
|
+
class TextSearchScopeWhereModel
|
448
|
+
include Mongoid::Document
|
449
|
+
|
450
|
+
# using the default text_search scope
|
451
|
+
end
|
452
|
+
|
453
|
+
shared_examples_for 'restricts to both' do
|
454
|
+
it 'restricts to both' do
|
455
|
+
expect(result.selector['$text']).to eq({'$search' => 'bar'})
|
456
|
+
expect(result.selector['hello']).to eq('world')
|
457
|
+
end
|
458
|
+
end
|
459
|
+
|
460
|
+
context 'scope is given first' do
|
461
|
+
let(:result) { TextSearchScopeWhereModel.text_search('bar').where(hello: 'world') }
|
462
|
+
|
463
|
+
it_behaves_like 'restricts to both'
|
464
|
+
end
|
465
|
+
|
466
|
+
context 'where is given first' do
|
467
|
+
let(:result) { TextSearchScopeWhereModel.where(hello: 'world').text_search('bar') }
|
468
|
+
|
469
|
+
it_behaves_like 'restricts to both'
|
470
|
+
end
|
471
|
+
end
|
391
472
|
end
|
@@ -975,6 +975,7 @@ describe Mongoid::Criteria do
|
|
975
975
|
end
|
976
976
|
|
977
977
|
describe "#geo_near" do
|
978
|
+
max_server_version '4.0'
|
978
979
|
|
979
980
|
before do
|
980
981
|
Bar.create_indexes
|
@@ -3321,6 +3322,8 @@ describe Mongoid::Criteria do
|
|
3321
3322
|
end
|
3322
3323
|
|
3323
3324
|
describe "#max_scan" do
|
3325
|
+
max_server_version '4.0'
|
3326
|
+
|
3324
3327
|
let!(:band) do
|
3325
3328
|
Band.create(name: "Depeche Mode")
|
3326
3329
|
end
|
@@ -3465,7 +3468,7 @@ describe Mongoid::Criteria do
|
|
3465
3468
|
context "when querying on a big decimal" do
|
3466
3469
|
|
3467
3470
|
let(:sales) do
|
3468
|
-
BigDecimal
|
3471
|
+
BigDecimal('0.1')
|
3469
3472
|
end
|
3470
3473
|
|
3471
3474
|
let!(:band) do
|
@@ -433,6 +433,60 @@ describe Mongoid::Document do
|
|
433
433
|
end
|
434
434
|
end
|
435
435
|
end
|
436
|
+
|
437
|
+
context ':compact option' do
|
438
|
+
|
439
|
+
before do
|
440
|
+
# These tests require a specific set of defined attributes
|
441
|
+
# on the model
|
442
|
+
expect(church.as_json.keys.sort).to eq(%w(_id location name))
|
443
|
+
end
|
444
|
+
|
445
|
+
context 'there is a nil valued attribute' do
|
446
|
+
let(:church) do
|
447
|
+
Church.create!(name: 'St. Basil')
|
448
|
+
end
|
449
|
+
|
450
|
+
it 'returns non-nil fields and _id only' do
|
451
|
+
actual = church.as_json(compact: true)
|
452
|
+
expect(actual).to eq('_id' => church.id, 'name' => 'St. Basil')
|
453
|
+
end
|
454
|
+
end
|
455
|
+
|
456
|
+
context 'all attrbutes are nil valued' do
|
457
|
+
let(:church) do
|
458
|
+
Church.create!
|
459
|
+
end
|
460
|
+
|
461
|
+
it 'returns a hash with _id only' do
|
462
|
+
actual = church.as_json(compact: true)
|
463
|
+
expect(actual).to eq('_id' => church.id)
|
464
|
+
end
|
465
|
+
end
|
466
|
+
|
467
|
+
context 'there are no nil valued attributes' do
|
468
|
+
let(:church) do
|
469
|
+
Church.create!(name: 'St. Basil', location: {})
|
470
|
+
end
|
471
|
+
|
472
|
+
it 'returns all fields and _id' do
|
473
|
+
actual = church.as_json(compact: true)
|
474
|
+
expect(actual).to eq('_id' => church.id, 'name' => 'St. Basil',
|
475
|
+
'location' => {})
|
476
|
+
end
|
477
|
+
end
|
478
|
+
|
479
|
+
context 'when option is specified as a truthy value' do
|
480
|
+
let(:church) do
|
481
|
+
Church.create!(name: 'St. Basil')
|
482
|
+
end
|
483
|
+
|
484
|
+
it 'returns non-nil fields and _id only' do
|
485
|
+
actual = church.as_json(compact: 1)
|
486
|
+
expect(actual).to eq('_id' => church.id, 'name' => 'St. Basil')
|
487
|
+
end
|
488
|
+
end
|
489
|
+
end
|
436
490
|
end
|
437
491
|
|
438
492
|
describe "#as_document" do
|