mongoid 9.1.0 → 9.1.1
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 +49 -0
- data/lib/mongoid/association/accessors.rb +9 -1
- data/lib/mongoid/association/depending.rb +14 -10
- data/lib/mongoid/association/eager.rb +9 -0
- data/lib/mongoid/association/eager_load/discriminated_inclusion.rb +88 -0
- data/lib/mongoid/association/eager_load/embedded_distributor.rb +151 -0
- data/lib/mongoid/association/eager_load/inclusion.rb +173 -0
- data/lib/mongoid/association/eager_load/inclusion_tree.rb +96 -0
- data/lib/mongoid/association/eager_load/lookup_pipeline.rb +121 -0
- data/lib/mongoid/association/eager_load/polymorphic_preloader.rb +61 -0
- data/lib/mongoid/association/eager_load/polymorphic_targets.rb +151 -0
- data/lib/mongoid/association/eager_loadable.rb +57 -100
- data/lib/mongoid/association/embedded/embeds_many/proxy.rb +6 -1
- data/lib/mongoid/association/embedded/embeds_one.rb +1 -0
- data/lib/mongoid/association/macros.rb +13 -1
- data/lib/mongoid/association/nested/many.rb +34 -5
- data/lib/mongoid/association/nested/nested_buildable.rb +14 -0
- data/lib/mongoid/association/nested/one.rb +6 -1
- data/lib/mongoid/association/options.rb +17 -0
- data/lib/mongoid/association/referenced/belongs_to/eager.rb +6 -1
- data/lib/mongoid/association/referenced/belongs_to.rb +1 -0
- data/lib/mongoid/association/referenced/counter_cache.rb +3 -3
- data/lib/mongoid/association/referenced/has_and_belongs_to_many.rb +5 -0
- data/lib/mongoid/association/referenced/has_many/enumerable.rb +3 -1
- data/lib/mongoid/association/referenced/has_many/proxy.rb +100 -1
- data/lib/mongoid/association/referenced/has_many_through/eager.rb +99 -0
- data/lib/mongoid/association/referenced/has_many_through/proxy.rb +68 -0
- data/lib/mongoid/association/referenced/has_many_through.rb +201 -0
- data/lib/mongoid/association/referenced/has_one.rb +1 -0
- data/lib/mongoid/association/referenced/has_one_through/eager.rb +65 -0
- data/lib/mongoid/association/referenced/has_one_through/proxy.rb +30 -0
- data/lib/mongoid/association/referenced/has_one_through.rb +167 -0
- data/lib/mongoid/association/referenced.rb +2 -0
- data/lib/mongoid/association/relatable.rb +40 -0
- data/lib/mongoid/association.rb +7 -0
- data/lib/mongoid/clients/factory.rb +7 -13
- data/lib/mongoid/collection_configurable.rb +8 -0
- data/lib/mongoid/config/defaults.rb +0 -1
- data/lib/mongoid/config/encryption.rb +36 -19
- data/lib/mongoid/config.rb +56 -5
- data/lib/mongoid/contextual/aggregable/memory.rb +6 -2
- data/lib/mongoid/contextual/memory.rb +18 -7
- data/lib/mongoid/criteria/includable.rb +35 -11
- data/lib/mongoid/criteria/queryable/mergeable.rb +4 -0
- data/lib/mongoid/criteria/queryable/selectable.rb +123 -7
- data/lib/mongoid/deprecable.rb +45 -2
- data/lib/mongoid/encryptable.rb +46 -0
- data/lib/mongoid/errors/config_redactor.rb +43 -0
- data/lib/mongoid/errors/in_memory_regexp_timeout.rb +26 -0
- data/lib/mongoid/errors/mixed_client_configuration.rb +1 -1
- data/lib/mongoid/errors/no_client_database.rb +1 -1
- data/lib/mongoid/errors/no_client_hosts.rb +1 -1
- data/lib/mongoid/errors/no_encryption_schema.rb +28 -0
- data/lib/mongoid/errors/readonly_association.rb +29 -0
- data/lib/mongoid/errors.rb +4 -0
- data/lib/mongoid/extensions/vector.rb +64 -0
- data/lib/mongoid/extensions.rb +1 -0
- data/lib/mongoid/field_readable.rb +69 -0
- data/lib/mongoid/indexable.rb +38 -26
- data/lib/mongoid/matchable.rb +6 -1
- data/lib/mongoid/matcher/eq_impl_with_regexp.rb +2 -4
- data/lib/mongoid/matcher/regex.rb +11 -12
- data/lib/mongoid/matcher/regexp_budget.rb +372 -0
- data/lib/mongoid/matcher.rb +1 -0
- data/lib/mongoid/persistable/creatable.rb +1 -1
- data/lib/mongoid/persistable/updatable.rb +9 -11
- data/lib/mongoid/persistence_context.rb +35 -0
- data/lib/mongoid/search_indexable.rb +64 -23
- data/lib/mongoid/serializable.rb +12 -4
- data/lib/mongoid/tasks/database.rb +23 -9
- data/lib/mongoid/threaded.rb +36 -0
- data/lib/mongoid/timestamps/timeless.rb +84 -10
- data/lib/mongoid/traversable.rb +2 -2
- data/lib/mongoid/validatable/associated.rb +18 -2
- data/lib/mongoid/version.rb +1 -1
- data/spec/integration/app_spec.rb +7 -1
- data/spec/integration/associations/belongs_to_spec.rb +13 -0
- data/spec/integration/associations/has_and_belongs_to_many_spec.rb +17 -2
- data/spec/integration/dots_and_dollars_spec.rb +12 -2
- data/spec/integration/encryption_spec.rb +151 -0
- data/spec/integration/matcher_operator_data/regex.yml +21 -0
- data/spec/integration/matcher_regexp_timeout_spec.rb +215 -0
- data/spec/integration/query_operator_guard_spec.rb +89 -0
- data/spec/mongoid/association/eager_loadable_spec.rb +47 -0
- data/spec/mongoid/association/eager_spec.rb +2 -2
- data/spec/mongoid/association/embedded/embeds_many/proxy_spec.rb +33 -0
- data/spec/mongoid/association/fallback_spec.rb +425 -0
- data/spec/mongoid/association/macros_spec.rb +26 -0
- data/spec/mongoid/association/referenced/belongs_to/eager_spec.rb +17 -0
- data/spec/mongoid/association/referenced/has_and_belongs_to_many/proxy_spec.rb +48 -0
- data/spec/mongoid/association/referenced/has_and_belongs_to_many_spec.rb +50 -0
- data/spec/mongoid/association/referenced/has_many/eager_spec.rb +33 -0
- data/spec/mongoid/association/referenced/has_many/proxy_spec.rb +145 -0
- data/spec/mongoid/association/referenced/has_many_through/eager_spec.rb +58 -0
- data/spec/mongoid/association/referenced/has_many_through/proxy_spec.rb +62 -0
- data/spec/mongoid/association/referenced/has_many_through_spec.rb +399 -0
- data/spec/mongoid/association/referenced/has_one_through/eager_spec.rb +58 -0
- data/spec/mongoid/association/referenced/has_one_through/proxy_spec.rb +49 -0
- data/spec/mongoid/association/referenced/has_one_through_spec.rb +211 -0
- data/spec/mongoid/attributes/nested_spec.rb +249 -8
- data/spec/mongoid/config/defaults_spec.rb +33 -0
- data/spec/mongoid/config/encryption_spec.rb +228 -0
- data/spec/mongoid/contextual/aggregable/memory_spec.rb +91 -0
- data/spec/mongoid/contextual/memory_spec.rb +177 -0
- data/spec/mongoid/criteria/includable_spec.rb +875 -0
- data/spec/mongoid/criteria/queryable/selectable_logical_spec.rb +15 -1
- data/spec/mongoid/criteria/queryable/selectable_where_spec.rb +201 -0
- data/spec/mongoid/criteria_spec.rb +3 -0
- data/spec/mongoid/encryptable_spec.rb +61 -0
- data/spec/mongoid/errors/config_redactor_spec.rb +112 -0
- data/spec/mongoid/errors/mixed_client_configuration_spec.rb +31 -0
- data/spec/mongoid/errors/no_client_database_spec.rb +29 -0
- data/spec/mongoid/errors/no_client_hosts_spec.rb +26 -0
- data/spec/mongoid/errors/readonly_association_spec.rb +34 -0
- data/spec/mongoid/extensions/vector_spec.rb +175 -0
- data/spec/mongoid/matcher/regexp_budget_spec.rb +570 -0
- data/spec/mongoid/search_indexable_spec.rb +295 -9
- data/spec/mongoid/tasks/database_spec.rb +18 -0
- data/spec/mongoid/timestamps/timeless_spec.rb +197 -5
- data/spec/mongoid/touchable_spec.rb +25 -0
- data/spec/mongoid/touchable_spec_models.rb +10 -0
- data/spec/mongoid/validatable/associated_spec.rb +19 -0
- data/spec/spec_helper.rb +5 -1
- data/spec/support/crypt/models.rb +157 -0
- metadata +52 -2
|
@@ -1414,6 +1414,881 @@ describe Mongoid::Criteria::Includable do
|
|
|
1414
1414
|
# 4.4 lookup does not support the lookup pipeline as it is currently written
|
|
1415
1415
|
min_server_version '5.0'
|
|
1416
1416
|
it_behaves_like 'eager loading', :eager_load
|
|
1417
|
+
|
|
1418
|
+
context 'when the inclusion list is empty' do
|
|
1419
|
+
let!(:band) { Band.create! }
|
|
1420
|
+
|
|
1421
|
+
it 'returns the documents without eager loading' do
|
|
1422
|
+
expect(Band.eager_load([]).first).to eq(band)
|
|
1423
|
+
end
|
|
1424
|
+
end
|
|
1425
|
+
|
|
1426
|
+
context 'when the association is defined on a subclass of the queried class' do
|
|
1427
|
+
before(:all) do
|
|
1428
|
+
class Machine
|
|
1429
|
+
include Mongoid::Document
|
|
1430
|
+
end
|
|
1431
|
+
|
|
1432
|
+
class Peripheral
|
|
1433
|
+
include Mongoid::Document
|
|
1434
|
+
end
|
|
1435
|
+
|
|
1436
|
+
class Webcam < Peripheral
|
|
1437
|
+
end
|
|
1438
|
+
|
|
1439
|
+
class Mouse < Peripheral
|
|
1440
|
+
belongs_to :machine
|
|
1441
|
+
end
|
|
1442
|
+
end
|
|
1443
|
+
|
|
1444
|
+
after(:all) do
|
|
1445
|
+
Object.send(:remove_const, :Mouse)
|
|
1446
|
+
Object.send(:remove_const, :Webcam)
|
|
1447
|
+
Object.send(:remove_const, :Peripheral)
|
|
1448
|
+
Object.send(:remove_const, :Machine)
|
|
1449
|
+
end
|
|
1450
|
+
|
|
1451
|
+
let!(:machine) { Machine.create! }
|
|
1452
|
+
let!(:webcam) { Webcam.create! }
|
|
1453
|
+
let!(:mouse) { Mouse.create!(machine: machine) }
|
|
1454
|
+
|
|
1455
|
+
it 'eager-loads it through the queried superclass' do
|
|
1456
|
+
expect_query(1) do
|
|
1457
|
+
loaded = Peripheral.eager_load(:machine).detect { |doc| doc.is_a?(Mouse) }
|
|
1458
|
+
expect(loaded.machine).to eq(machine)
|
|
1459
|
+
end
|
|
1460
|
+
end
|
|
1461
|
+
end
|
|
1462
|
+
|
|
1463
|
+
context 'when the association is defined on a subclass of an associated class' do
|
|
1464
|
+
before(:all) do
|
|
1465
|
+
class Brand
|
|
1466
|
+
include Mongoid::Document
|
|
1467
|
+
end
|
|
1468
|
+
|
|
1469
|
+
class Machine
|
|
1470
|
+
include Mongoid::Document
|
|
1471
|
+
end
|
|
1472
|
+
|
|
1473
|
+
class Laptop < Machine
|
|
1474
|
+
belongs_to :brand
|
|
1475
|
+
end
|
|
1476
|
+
|
|
1477
|
+
class Peripheral
|
|
1478
|
+
include Mongoid::Document
|
|
1479
|
+
end
|
|
1480
|
+
|
|
1481
|
+
class Mouse < Peripheral
|
|
1482
|
+
belongs_to :machine
|
|
1483
|
+
end
|
|
1484
|
+
end
|
|
1485
|
+
|
|
1486
|
+
after(:all) do
|
|
1487
|
+
Object.send(:remove_const, :Mouse)
|
|
1488
|
+
Object.send(:remove_const, :Peripheral)
|
|
1489
|
+
Object.send(:remove_const, :Laptop)
|
|
1490
|
+
Object.send(:remove_const, :Machine)
|
|
1491
|
+
Object.send(:remove_const, :Brand)
|
|
1492
|
+
end
|
|
1493
|
+
|
|
1494
|
+
let!(:brand) { Brand.create! }
|
|
1495
|
+
let!(:laptop) { Laptop.create!(brand: brand) }
|
|
1496
|
+
let!(:mouse) { Mouse.create!(machine: laptop) }
|
|
1497
|
+
|
|
1498
|
+
it 'eager-loads it through the parent association' do
|
|
1499
|
+
expect_query(1) do
|
|
1500
|
+
loaded = Peripheral.eager_load(machine: :brand).first
|
|
1501
|
+
expect(loaded.machine).to eq(laptop)
|
|
1502
|
+
expect(loaded.machine.brand).to eq(brand)
|
|
1503
|
+
end
|
|
1504
|
+
end
|
|
1505
|
+
end
|
|
1506
|
+
|
|
1507
|
+
context 'when a has_many is defined only on a subclass' do
|
|
1508
|
+
before(:all) do
|
|
1509
|
+
class Gadget
|
|
1510
|
+
include Mongoid::Document
|
|
1511
|
+
end
|
|
1512
|
+
|
|
1513
|
+
class Speaker < Gadget
|
|
1514
|
+
has_many :cables
|
|
1515
|
+
end
|
|
1516
|
+
|
|
1517
|
+
class Cable
|
|
1518
|
+
include Mongoid::Document
|
|
1519
|
+
|
|
1520
|
+
belongs_to :speaker
|
|
1521
|
+
end
|
|
1522
|
+
end
|
|
1523
|
+
|
|
1524
|
+
after(:all) do
|
|
1525
|
+
Object.send(:remove_const, :Cable)
|
|
1526
|
+
Object.send(:remove_const, :Speaker)
|
|
1527
|
+
Object.send(:remove_const, :Gadget)
|
|
1528
|
+
end
|
|
1529
|
+
|
|
1530
|
+
let!(:speaker) { Speaker.create! }
|
|
1531
|
+
let!(:cable) { Cable.create!(speaker: speaker) }
|
|
1532
|
+
|
|
1533
|
+
it 'eager-loads it through the queried superclass' do
|
|
1534
|
+
expect_query(1) do
|
|
1535
|
+
loaded = Gadget.eager_load(:cables).first
|
|
1536
|
+
expect(loaded.cables).to eq([ cable ])
|
|
1537
|
+
end
|
|
1538
|
+
end
|
|
1539
|
+
end
|
|
1540
|
+
|
|
1541
|
+
context 'when a has_one is defined only on a subclass' do
|
|
1542
|
+
before(:all) do
|
|
1543
|
+
class Gadget
|
|
1544
|
+
include Mongoid::Document
|
|
1545
|
+
end
|
|
1546
|
+
|
|
1547
|
+
class Speaker < Gadget
|
|
1548
|
+
has_one :cable
|
|
1549
|
+
end
|
|
1550
|
+
|
|
1551
|
+
class Cable
|
|
1552
|
+
include Mongoid::Document
|
|
1553
|
+
|
|
1554
|
+
belongs_to :speaker
|
|
1555
|
+
end
|
|
1556
|
+
end
|
|
1557
|
+
|
|
1558
|
+
after(:all) do
|
|
1559
|
+
Object.send(:remove_const, :Cable)
|
|
1560
|
+
Object.send(:remove_const, :Speaker)
|
|
1561
|
+
Object.send(:remove_const, :Gadget)
|
|
1562
|
+
end
|
|
1563
|
+
|
|
1564
|
+
let!(:speaker) { Speaker.create! }
|
|
1565
|
+
let!(:cable) { Cable.create!(speaker: speaker) }
|
|
1566
|
+
|
|
1567
|
+
it 'eager-loads it through the queried superclass' do
|
|
1568
|
+
expect_query(1) do
|
|
1569
|
+
loaded = Gadget.eager_load(:cable).first
|
|
1570
|
+
expect(loaded.cable).to eq(cable)
|
|
1571
|
+
end
|
|
1572
|
+
end
|
|
1573
|
+
end
|
|
1574
|
+
|
|
1575
|
+
context 'when a has_and_belongs_to_many is defined only on a subclass' do
|
|
1576
|
+
before(:all) do
|
|
1577
|
+
class Cable
|
|
1578
|
+
include Mongoid::Document
|
|
1579
|
+
|
|
1580
|
+
has_and_belongs_to_many :speakers
|
|
1581
|
+
end
|
|
1582
|
+
|
|
1583
|
+
class Gadget
|
|
1584
|
+
include Mongoid::Document
|
|
1585
|
+
end
|
|
1586
|
+
|
|
1587
|
+
class Speaker < Gadget
|
|
1588
|
+
has_and_belongs_to_many :cables
|
|
1589
|
+
end
|
|
1590
|
+
end
|
|
1591
|
+
|
|
1592
|
+
after(:all) do
|
|
1593
|
+
Object.send(:remove_const, :Speaker)
|
|
1594
|
+
Object.send(:remove_const, :Gadget)
|
|
1595
|
+
Object.send(:remove_const, :Cable)
|
|
1596
|
+
end
|
|
1597
|
+
|
|
1598
|
+
let!(:cable) { Cable.create! }
|
|
1599
|
+
let!(:speaker) { Speaker.create!(cables: [ cable ]) }
|
|
1600
|
+
|
|
1601
|
+
it 'eager-loads it through the queried superclass' do
|
|
1602
|
+
expect_query(1) do
|
|
1603
|
+
loaded = Gadget.eager_load(:cables).first
|
|
1604
|
+
expect(loaded.cables).to eq([ cable ])
|
|
1605
|
+
end
|
|
1606
|
+
end
|
|
1607
|
+
end
|
|
1608
|
+
|
|
1609
|
+
context 'when a belongs_to lives inside an embedded document' do
|
|
1610
|
+
before(:all) do
|
|
1611
|
+
class Device
|
|
1612
|
+
include Mongoid::Document
|
|
1613
|
+
end
|
|
1614
|
+
|
|
1615
|
+
class Port
|
|
1616
|
+
include Mongoid::Document
|
|
1617
|
+
|
|
1618
|
+
embedded_in :computer
|
|
1619
|
+
belongs_to :device
|
|
1620
|
+
end
|
|
1621
|
+
|
|
1622
|
+
class Computer
|
|
1623
|
+
include Mongoid::Document
|
|
1624
|
+
|
|
1625
|
+
embeds_one :port
|
|
1626
|
+
end
|
|
1627
|
+
end
|
|
1628
|
+
|
|
1629
|
+
after(:all) do
|
|
1630
|
+
Object.send(:remove_const, :Computer)
|
|
1631
|
+
Object.send(:remove_const, :Port)
|
|
1632
|
+
Object.send(:remove_const, :Device)
|
|
1633
|
+
end
|
|
1634
|
+
|
|
1635
|
+
let!(:device) { Device.create! }
|
|
1636
|
+
let!(:computer) { Computer.create!(port: Port.new(device: device)) }
|
|
1637
|
+
|
|
1638
|
+
it 'eager-loads it through the embedded document' do
|
|
1639
|
+
expect_query(1) do
|
|
1640
|
+
loaded = Computer.eager_load(port: :device).first
|
|
1641
|
+
expect(loaded.port.device).to eq(device)
|
|
1642
|
+
end
|
|
1643
|
+
end
|
|
1644
|
+
|
|
1645
|
+
it 'leaves the embedded document absent instead of synthesizing it' do
|
|
1646
|
+
without_port = Computer.create!
|
|
1647
|
+
loaded = expect_query(1) do
|
|
1648
|
+
Computer.eager_load(port: :device).to_a.index_by(&:id)
|
|
1649
|
+
end
|
|
1650
|
+
expect_no_queries do
|
|
1651
|
+
expect(loaded[without_port.id].port).to be_nil
|
|
1652
|
+
end
|
|
1653
|
+
end
|
|
1654
|
+
end
|
|
1655
|
+
|
|
1656
|
+
context 'when two embeds_one associations of the same class are eager-loaded' do
|
|
1657
|
+
before(:all) do
|
|
1658
|
+
class Device
|
|
1659
|
+
include Mongoid::Document
|
|
1660
|
+
end
|
|
1661
|
+
|
|
1662
|
+
class Port
|
|
1663
|
+
include Mongoid::Document
|
|
1664
|
+
|
|
1665
|
+
embedded_in :computer
|
|
1666
|
+
belongs_to :device
|
|
1667
|
+
end
|
|
1668
|
+
|
|
1669
|
+
class Computer
|
|
1670
|
+
include Mongoid::Document
|
|
1671
|
+
|
|
1672
|
+
embeds_one :left_port, class_name: 'Port'
|
|
1673
|
+
embeds_one :right_port, class_name: 'Port'
|
|
1674
|
+
end
|
|
1675
|
+
end
|
|
1676
|
+
|
|
1677
|
+
after(:all) do
|
|
1678
|
+
Object.send(:remove_const, :Computer)
|
|
1679
|
+
Object.send(:remove_const, :Port)
|
|
1680
|
+
Object.send(:remove_const, :Device)
|
|
1681
|
+
end
|
|
1682
|
+
|
|
1683
|
+
let!(:device1) { Device.create! }
|
|
1684
|
+
let!(:device2) { Device.create! }
|
|
1685
|
+
let!(:computer) do
|
|
1686
|
+
Computer.create!(
|
|
1687
|
+
left_port: Port.new(device: device1),
|
|
1688
|
+
right_port: Port.new(device: device2)
|
|
1689
|
+
)
|
|
1690
|
+
end
|
|
1691
|
+
|
|
1692
|
+
it 'eager-loads the belongs_to in both embedded documents' do
|
|
1693
|
+
expect_query(1) do
|
|
1694
|
+
loaded = Computer.eager_load(left_port: :device, right_port: :device).first
|
|
1695
|
+
expect(loaded.left_port.device).to eq(device1)
|
|
1696
|
+
expect(loaded.right_port.device).to eq(device2)
|
|
1697
|
+
end
|
|
1698
|
+
end
|
|
1699
|
+
end
|
|
1700
|
+
|
|
1701
|
+
context 'when a belongs_to lives inside a doubly embedded document' do
|
|
1702
|
+
before(:all) do
|
|
1703
|
+
class Device
|
|
1704
|
+
include Mongoid::Document
|
|
1705
|
+
end
|
|
1706
|
+
|
|
1707
|
+
class Port
|
|
1708
|
+
include Mongoid::Document
|
|
1709
|
+
|
|
1710
|
+
embedded_in :panel
|
|
1711
|
+
belongs_to :device
|
|
1712
|
+
end
|
|
1713
|
+
|
|
1714
|
+
class Panel
|
|
1715
|
+
include Mongoid::Document
|
|
1716
|
+
|
|
1717
|
+
embedded_in :computer
|
|
1718
|
+
embeds_one :port
|
|
1719
|
+
end
|
|
1720
|
+
|
|
1721
|
+
class Computer
|
|
1722
|
+
include Mongoid::Document
|
|
1723
|
+
|
|
1724
|
+
embeds_one :panel
|
|
1725
|
+
end
|
|
1726
|
+
end
|
|
1727
|
+
|
|
1728
|
+
after(:all) do
|
|
1729
|
+
Object.send(:remove_const, :Computer)
|
|
1730
|
+
Object.send(:remove_const, :Panel)
|
|
1731
|
+
Object.send(:remove_const, :Port)
|
|
1732
|
+
Object.send(:remove_const, :Device)
|
|
1733
|
+
end
|
|
1734
|
+
|
|
1735
|
+
let!(:device) { Device.create! }
|
|
1736
|
+
let!(:computer) { Computer.create!(panel: Panel.new(port: Port.new(device: device))) }
|
|
1737
|
+
|
|
1738
|
+
it 'eager-loads it through both embedded documents' do
|
|
1739
|
+
expect_query(1) do
|
|
1740
|
+
loaded = Computer.eager_load(panel: { port: :device }).first
|
|
1741
|
+
expect(loaded.panel.port.device).to eq(device)
|
|
1742
|
+
end
|
|
1743
|
+
end
|
|
1744
|
+
end
|
|
1745
|
+
|
|
1746
|
+
context 'when a belongs_to is defined only on a subclass of an embedded document' do
|
|
1747
|
+
before(:all) do
|
|
1748
|
+
class Device
|
|
1749
|
+
include Mongoid::Document
|
|
1750
|
+
end
|
|
1751
|
+
|
|
1752
|
+
class Port
|
|
1753
|
+
include Mongoid::Document
|
|
1754
|
+
|
|
1755
|
+
embedded_in :computer
|
|
1756
|
+
end
|
|
1757
|
+
|
|
1758
|
+
class UsbPort < Port
|
|
1759
|
+
belongs_to :device
|
|
1760
|
+
end
|
|
1761
|
+
|
|
1762
|
+
class Computer
|
|
1763
|
+
include Mongoid::Document
|
|
1764
|
+
|
|
1765
|
+
embeds_one :port
|
|
1766
|
+
end
|
|
1767
|
+
end
|
|
1768
|
+
|
|
1769
|
+
after(:all) do
|
|
1770
|
+
Object.send(:remove_const, :Computer)
|
|
1771
|
+
Object.send(:remove_const, :UsbPort)
|
|
1772
|
+
Object.send(:remove_const, :Port)
|
|
1773
|
+
Object.send(:remove_const, :Device)
|
|
1774
|
+
end
|
|
1775
|
+
|
|
1776
|
+
let!(:device) { Device.create! }
|
|
1777
|
+
let!(:computer) { Computer.create!(port: UsbPort.new(device: device)) }
|
|
1778
|
+
|
|
1779
|
+
it 'eager-loads it through the embedded subclass' do
|
|
1780
|
+
expect_query(1) do
|
|
1781
|
+
loaded = Computer.eager_load(port: :device).first
|
|
1782
|
+
expect(loaded.port.device).to eq(device)
|
|
1783
|
+
end
|
|
1784
|
+
end
|
|
1785
|
+
end
|
|
1786
|
+
|
|
1787
|
+
context 'when a belongs_to lives inside an embeds_many' do
|
|
1788
|
+
before(:all) do
|
|
1789
|
+
class Device
|
|
1790
|
+
include Mongoid::Document
|
|
1791
|
+
end
|
|
1792
|
+
|
|
1793
|
+
class Port
|
|
1794
|
+
include Mongoid::Document
|
|
1795
|
+
|
|
1796
|
+
embedded_in :computer
|
|
1797
|
+
belongs_to :device
|
|
1798
|
+
end
|
|
1799
|
+
|
|
1800
|
+
class Computer
|
|
1801
|
+
include Mongoid::Document
|
|
1802
|
+
|
|
1803
|
+
embeds_many :ports
|
|
1804
|
+
end
|
|
1805
|
+
end
|
|
1806
|
+
|
|
1807
|
+
after(:all) do
|
|
1808
|
+
Object.send(:remove_const, :Computer)
|
|
1809
|
+
Object.send(:remove_const, :Port)
|
|
1810
|
+
Object.send(:remove_const, :Device)
|
|
1811
|
+
end
|
|
1812
|
+
|
|
1813
|
+
let!(:device1) { Device.create! }
|
|
1814
|
+
let!(:device2) { Device.create! }
|
|
1815
|
+
let!(:computer) { Computer.create!(ports: [ Port.new(device: device1), Port.new(device: device2) ]) }
|
|
1816
|
+
|
|
1817
|
+
it 'eager-loads each embedded belongs_to without extra queries' do
|
|
1818
|
+
expect_query(1) do
|
|
1819
|
+
loaded = Computer.eager_load(ports: :device).first
|
|
1820
|
+
expect(loaded.ports.map(&:device)).to eq([ device1, device2 ])
|
|
1821
|
+
end
|
|
1822
|
+
end
|
|
1823
|
+
end
|
|
1824
|
+
|
|
1825
|
+
context 'when a has_and_belongs_to_many lives inside an embedded document' do
|
|
1826
|
+
before(:all) do
|
|
1827
|
+
class Device
|
|
1828
|
+
include Mongoid::Document
|
|
1829
|
+
end
|
|
1830
|
+
|
|
1831
|
+
class Port
|
|
1832
|
+
include Mongoid::Document
|
|
1833
|
+
|
|
1834
|
+
embedded_in :computer
|
|
1835
|
+
has_and_belongs_to_many :devices
|
|
1836
|
+
end
|
|
1837
|
+
|
|
1838
|
+
class Computer
|
|
1839
|
+
include Mongoid::Document
|
|
1840
|
+
|
|
1841
|
+
embeds_one :port
|
|
1842
|
+
end
|
|
1843
|
+
end
|
|
1844
|
+
|
|
1845
|
+
after(:all) do
|
|
1846
|
+
Object.send(:remove_const, :Computer)
|
|
1847
|
+
Object.send(:remove_const, :Port)
|
|
1848
|
+
Object.send(:remove_const, :Device)
|
|
1849
|
+
end
|
|
1850
|
+
|
|
1851
|
+
let!(:device1) { Device.create! }
|
|
1852
|
+
let!(:device2) { Device.create! }
|
|
1853
|
+
let!(:computer) { Computer.create!(port: Port.new(devices: [ device1, device2 ])) }
|
|
1854
|
+
|
|
1855
|
+
it 'eager-loads the devices referenced by the embedded port' do
|
|
1856
|
+
expect_query(1) do
|
|
1857
|
+
loaded = Computer.eager_load(port: :devices).first
|
|
1858
|
+
expect(loaded.port.devices).to eq([ device1, device2 ])
|
|
1859
|
+
end
|
|
1860
|
+
end
|
|
1861
|
+
end
|
|
1862
|
+
|
|
1863
|
+
context 'when an embedded belongs_to targets a superclass of the queried subclass' do
|
|
1864
|
+
before(:all) do
|
|
1865
|
+
class Device
|
|
1866
|
+
include Mongoid::Document
|
|
1867
|
+
end
|
|
1868
|
+
|
|
1869
|
+
class Computer < Device
|
|
1870
|
+
embeds_one :port
|
|
1871
|
+
end
|
|
1872
|
+
|
|
1873
|
+
class Port
|
|
1874
|
+
include Mongoid::Document
|
|
1875
|
+
|
|
1876
|
+
embedded_in :computer
|
|
1877
|
+
belongs_to :device
|
|
1878
|
+
end
|
|
1879
|
+
end
|
|
1880
|
+
|
|
1881
|
+
after(:all) do
|
|
1882
|
+
Object.send(:remove_const, :Port)
|
|
1883
|
+
Object.send(:remove_const, :Computer)
|
|
1884
|
+
Object.send(:remove_const, :Device)
|
|
1885
|
+
end
|
|
1886
|
+
|
|
1887
|
+
let!(:device) { Device.create! }
|
|
1888
|
+
let!(:computer) { Computer.create!(port: Port.new(device: device)) }
|
|
1889
|
+
|
|
1890
|
+
it 'eager-loads the embedded belongs_to through the queried subclass' do
|
|
1891
|
+
expect_query(1) do
|
|
1892
|
+
loaded = Computer.eager_load(port: :device).first
|
|
1893
|
+
expect(loaded.port.device).to eq(device)
|
|
1894
|
+
end
|
|
1895
|
+
end
|
|
1896
|
+
end
|
|
1897
|
+
|
|
1898
|
+
context 'when an embedded association is nested under a referenced one' do
|
|
1899
|
+
before(:all) do
|
|
1900
|
+
class Device
|
|
1901
|
+
include Mongoid::Document
|
|
1902
|
+
end
|
|
1903
|
+
|
|
1904
|
+
class Port
|
|
1905
|
+
include Mongoid::Document
|
|
1906
|
+
|
|
1907
|
+
embedded_in :computer
|
|
1908
|
+
belongs_to :device
|
|
1909
|
+
end
|
|
1910
|
+
|
|
1911
|
+
class Computer
|
|
1912
|
+
include Mongoid::Document
|
|
1913
|
+
|
|
1914
|
+
embeds_one :port
|
|
1915
|
+
end
|
|
1916
|
+
|
|
1917
|
+
class Desk
|
|
1918
|
+
include Mongoid::Document
|
|
1919
|
+
|
|
1920
|
+
belongs_to :computer
|
|
1921
|
+
end
|
|
1922
|
+
end
|
|
1923
|
+
|
|
1924
|
+
after(:all) do
|
|
1925
|
+
Object.send(:remove_const, :Desk)
|
|
1926
|
+
Object.send(:remove_const, :Computer)
|
|
1927
|
+
Object.send(:remove_const, :Port)
|
|
1928
|
+
Object.send(:remove_const, :Device)
|
|
1929
|
+
end
|
|
1930
|
+
|
|
1931
|
+
let!(:device) { Device.create! }
|
|
1932
|
+
let!(:computer) { Computer.create!(port: Port.new(device: device)) }
|
|
1933
|
+
let!(:desk) { Desk.create!(computer: computer) }
|
|
1934
|
+
|
|
1935
|
+
it 'eager-loads the embedded association together with its referenced child' do
|
|
1936
|
+
expect_query(1) do
|
|
1937
|
+
loaded = Desk.eager_load(computer: { port: :device }).first
|
|
1938
|
+
expect(loaded.computer.port.device).to eq(device)
|
|
1939
|
+
end
|
|
1940
|
+
end
|
|
1941
|
+
end
|
|
1942
|
+
|
|
1943
|
+
context 'when an embedded association is nested two levels under a referenced one' do
|
|
1944
|
+
before(:all) do
|
|
1945
|
+
class Device
|
|
1946
|
+
include Mongoid::Document
|
|
1947
|
+
end
|
|
1948
|
+
|
|
1949
|
+
class Pin
|
|
1950
|
+
include Mongoid::Document
|
|
1951
|
+
|
|
1952
|
+
embedded_in :port
|
|
1953
|
+
belongs_to :device
|
|
1954
|
+
end
|
|
1955
|
+
|
|
1956
|
+
class Port
|
|
1957
|
+
include Mongoid::Document
|
|
1958
|
+
|
|
1959
|
+
embedded_in :computer
|
|
1960
|
+
embeds_one :pin
|
|
1961
|
+
end
|
|
1962
|
+
|
|
1963
|
+
class Computer
|
|
1964
|
+
include Mongoid::Document
|
|
1965
|
+
|
|
1966
|
+
embeds_one :port
|
|
1967
|
+
end
|
|
1968
|
+
|
|
1969
|
+
class Desk
|
|
1970
|
+
include Mongoid::Document
|
|
1971
|
+
|
|
1972
|
+
belongs_to :computer
|
|
1973
|
+
end
|
|
1974
|
+
end
|
|
1975
|
+
|
|
1976
|
+
after(:all) do
|
|
1977
|
+
Object.send(:remove_const, :Desk)
|
|
1978
|
+
Object.send(:remove_const, :Computer)
|
|
1979
|
+
Object.send(:remove_const, :Port)
|
|
1980
|
+
Object.send(:remove_const, :Pin)
|
|
1981
|
+
Object.send(:remove_const, :Device)
|
|
1982
|
+
end
|
|
1983
|
+
|
|
1984
|
+
let!(:device) { Device.create! }
|
|
1985
|
+
let!(:computer) { Computer.create!(port: Port.new(pin: Pin.new(device: device))) }
|
|
1986
|
+
let!(:desk) { Desk.create!(computer: computer) }
|
|
1987
|
+
|
|
1988
|
+
it 'eager-loads the doubly embedded association together with its referenced child' do
|
|
1989
|
+
expect_query(1) do
|
|
1990
|
+
loaded = Desk.eager_load(computer: { port: { pin: :device } }).first
|
|
1991
|
+
expect(loaded.computer.port.pin.device).to eq(device)
|
|
1992
|
+
end
|
|
1993
|
+
end
|
|
1994
|
+
end
|
|
1995
|
+
|
|
1996
|
+
context 'when an embeds_many is nested inside another embeds_many under a referenced one' do
|
|
1997
|
+
before(:all) do
|
|
1998
|
+
class Device
|
|
1999
|
+
include Mongoid::Document
|
|
2000
|
+
end
|
|
2001
|
+
|
|
2002
|
+
class Port
|
|
2003
|
+
include Mongoid::Document
|
|
2004
|
+
|
|
2005
|
+
embedded_in :card
|
|
2006
|
+
belongs_to :device
|
|
2007
|
+
end
|
|
2008
|
+
|
|
2009
|
+
class Card
|
|
2010
|
+
include Mongoid::Document
|
|
2011
|
+
|
|
2012
|
+
embedded_in :computer
|
|
2013
|
+
embeds_many :ports
|
|
2014
|
+
end
|
|
2015
|
+
|
|
2016
|
+
class Computer
|
|
2017
|
+
include Mongoid::Document
|
|
2018
|
+
|
|
2019
|
+
embeds_many :cards
|
|
2020
|
+
end
|
|
2021
|
+
|
|
2022
|
+
class Desk
|
|
2023
|
+
include Mongoid::Document
|
|
2024
|
+
|
|
2025
|
+
belongs_to :computer
|
|
2026
|
+
end
|
|
2027
|
+
end
|
|
2028
|
+
|
|
2029
|
+
after(:all) do
|
|
2030
|
+
Object.send(:remove_const, :Desk)
|
|
2031
|
+
Object.send(:remove_const, :Computer)
|
|
2032
|
+
Object.send(:remove_const, :Card)
|
|
2033
|
+
Object.send(:remove_const, :Port)
|
|
2034
|
+
Object.send(:remove_const, :Device)
|
|
2035
|
+
end
|
|
2036
|
+
|
|
2037
|
+
let!(:devices) { Array.new(4) { Device.create! } }
|
|
2038
|
+
let!(:computer) do
|
|
2039
|
+
Computer.create!(
|
|
2040
|
+
cards: [
|
|
2041
|
+
Card.new(ports: [ Port.new(device: devices[0]), Port.new(device: devices[1]) ]),
|
|
2042
|
+
Card.new(ports: [ Port.new(device: devices[2]), Port.new(device: devices[3]) ])
|
|
2043
|
+
]
|
|
2044
|
+
)
|
|
2045
|
+
end
|
|
2046
|
+
let!(:desk) { Desk.create!(computer: computer) }
|
|
2047
|
+
|
|
2048
|
+
it 'eager-loads each deeply embedded belongs_to correlated to its own element' do
|
|
2049
|
+
expect_query(1) do
|
|
2050
|
+
loaded = Desk.eager_load(computer: { cards: { ports: :device } }).first
|
|
2051
|
+
got = loaded.computer.cards.flat_map { |card| card.ports.map(&:device) }
|
|
2052
|
+
expect(got).to eq(devices)
|
|
2053
|
+
end
|
|
2054
|
+
end
|
|
2055
|
+
end
|
|
2056
|
+
|
|
2057
|
+
context 'when a polymorphic belongs_to is eager-loaded' do
|
|
2058
|
+
before(:all) do
|
|
2059
|
+
class Printer
|
|
2060
|
+
include Mongoid::Document
|
|
2061
|
+
end
|
|
2062
|
+
|
|
2063
|
+
class Scanner
|
|
2064
|
+
include Mongoid::Document
|
|
2065
|
+
end
|
|
2066
|
+
|
|
2067
|
+
class Cartridge
|
|
2068
|
+
include Mongoid::Document
|
|
2069
|
+
|
|
2070
|
+
belongs_to :device, polymorphic: true
|
|
2071
|
+
end
|
|
2072
|
+
end
|
|
2073
|
+
|
|
2074
|
+
after(:all) do
|
|
2075
|
+
Object.send(:remove_const, :Cartridge)
|
|
2076
|
+
Object.send(:remove_const, :Scanner)
|
|
2077
|
+
Object.send(:remove_const, :Printer)
|
|
2078
|
+
end
|
|
2079
|
+
|
|
2080
|
+
let!(:printer) { Printer.create! }
|
|
2081
|
+
let!(:scanner) { Scanner.create! }
|
|
2082
|
+
let!(:printer_cartridge) { Cartridge.create!(device: printer) }
|
|
2083
|
+
let!(:scanner_cartridge) { Cartridge.create!(device: scanner) }
|
|
2084
|
+
|
|
2085
|
+
it 'eager-loads polymorphic targets of different types in a single extra query' do
|
|
2086
|
+
expect_query(2) do
|
|
2087
|
+
loaded = Cartridge.eager_load(:device).to_a.index_by(&:id)
|
|
2088
|
+
expect(loaded[printer_cartridge.id].device).to eq(printer)
|
|
2089
|
+
expect(loaded[scanner_cartridge.id].device).to eq(scanner)
|
|
2090
|
+
end
|
|
2091
|
+
end
|
|
2092
|
+
end
|
|
2093
|
+
|
|
2094
|
+
context 'when a polymorphic target is stored in another database' do
|
|
2095
|
+
before(:all) do
|
|
2096
|
+
class LocalDevice
|
|
2097
|
+
include Mongoid::Document
|
|
2098
|
+
end
|
|
2099
|
+
|
|
2100
|
+
class RemoteDevice
|
|
2101
|
+
include Mongoid::Document
|
|
2102
|
+
|
|
2103
|
+
store_in database: 'secondary'
|
|
2104
|
+
end
|
|
2105
|
+
|
|
2106
|
+
class Accessory
|
|
2107
|
+
include Mongoid::Document
|
|
2108
|
+
|
|
2109
|
+
belongs_to :device, polymorphic: true
|
|
2110
|
+
end
|
|
2111
|
+
end
|
|
2112
|
+
|
|
2113
|
+
after(:all) do
|
|
2114
|
+
Object.send(:remove_const, :Accessory)
|
|
2115
|
+
Object.send(:remove_const, :RemoteDevice)
|
|
2116
|
+
Object.send(:remove_const, :LocalDevice)
|
|
2117
|
+
end
|
|
2118
|
+
|
|
2119
|
+
# RemoteDevice lives in its own database, which the global cleanup hook
|
|
2120
|
+
# (default database only) does not touch, so drop it here.
|
|
2121
|
+
after { RemoteDevice.collection.drop }
|
|
2122
|
+
|
|
2123
|
+
let!(:local_device) { LocalDevice.create! }
|
|
2124
|
+
let!(:remote_device) { RemoteDevice.create! }
|
|
2125
|
+
let!(:local_accessory) { Accessory.create!(device: local_device) }
|
|
2126
|
+
let!(:remote_accessory) { Accessory.create!(device: remote_device) }
|
|
2127
|
+
|
|
2128
|
+
it 'eager-loads the target stored in the other database' do
|
|
2129
|
+
# One query materializes the roots, one $facet fetches the same-database
|
|
2130
|
+
# target, and one direct query fetches the target in the other database.
|
|
2131
|
+
loaded = expect_query(3) do
|
|
2132
|
+
Accessory.eager_load(:device).to_a.index_by(&:id)
|
|
2133
|
+
end
|
|
2134
|
+
|
|
2135
|
+
expect_no_queries do
|
|
2136
|
+
expect(loaded[local_accessory.id].device).to eq(local_device)
|
|
2137
|
+
expect(loaded[remote_accessory.id].device).to eq(remote_device)
|
|
2138
|
+
end
|
|
2139
|
+
end
|
|
2140
|
+
end
|
|
2141
|
+
|
|
2142
|
+
context 'when a non-polymorphic target is stored in another database' do
|
|
2143
|
+
before(:all) do
|
|
2144
|
+
class RemoteServer
|
|
2145
|
+
include Mongoid::Document
|
|
2146
|
+
|
|
2147
|
+
store_in database: 'secondary'
|
|
2148
|
+
end
|
|
2149
|
+
|
|
2150
|
+
class Workstation
|
|
2151
|
+
include Mongoid::Document
|
|
2152
|
+
|
|
2153
|
+
belongs_to :server, class_name: 'RemoteServer', optional: true
|
|
2154
|
+
end
|
|
2155
|
+
end
|
|
2156
|
+
|
|
2157
|
+
after(:all) do
|
|
2158
|
+
Object.send(:remove_const, :Workstation)
|
|
2159
|
+
Object.send(:remove_const, :RemoteServer)
|
|
2160
|
+
end
|
|
2161
|
+
|
|
2162
|
+
# RemoteServer lives in its own database, which the global cleanup hook
|
|
2163
|
+
# (default database only) does not touch, so drop it here.
|
|
2164
|
+
after { RemoteServer.collection.drop }
|
|
2165
|
+
|
|
2166
|
+
let!(:server) { RemoteServer.create! }
|
|
2167
|
+
let!(:workstation) { Workstation.create!(server: server) }
|
|
2168
|
+
|
|
2169
|
+
it 'eager-loads the target stored in the other database' do
|
|
2170
|
+
# A $lookup cannot reach another database, so this falls back to
|
|
2171
|
+
# separate-query loading: one query materializes the roots and one fetches
|
|
2172
|
+
# the targets, instead of silently returning nothing.
|
|
2173
|
+
loaded = expect_query(2) do
|
|
2174
|
+
Workstation.eager_load(:server).to_a
|
|
2175
|
+
end
|
|
2176
|
+
|
|
2177
|
+
expect_no_queries do
|
|
2178
|
+
expect(loaded.first.server).to eq(server)
|
|
2179
|
+
end
|
|
2180
|
+
end
|
|
2181
|
+
end
|
|
2182
|
+
|
|
2183
|
+
context 'when a has_many of the same name is defined on more than one subclass' do
|
|
2184
|
+
before(:all) do
|
|
2185
|
+
class Supplier
|
|
2186
|
+
include Mongoid::Document
|
|
2187
|
+
end
|
|
2188
|
+
|
|
2189
|
+
class Cog
|
|
2190
|
+
include Mongoid::Document
|
|
2191
|
+
|
|
2192
|
+
belongs_to :machine, optional: true
|
|
2193
|
+
belongs_to :supplier, optional: true
|
|
2194
|
+
end
|
|
2195
|
+
|
|
2196
|
+
class Belt
|
|
2197
|
+
include Mongoid::Document
|
|
2198
|
+
|
|
2199
|
+
belongs_to :machine, optional: true
|
|
2200
|
+
belongs_to :supplier, optional: true
|
|
2201
|
+
end
|
|
2202
|
+
|
|
2203
|
+
class Machine
|
|
2204
|
+
include Mongoid::Document
|
|
2205
|
+
end
|
|
2206
|
+
|
|
2207
|
+
class Lathe < Machine
|
|
2208
|
+
has_many :widgets, class_name: 'Cog', inverse_of: :machine
|
|
2209
|
+
end
|
|
2210
|
+
|
|
2211
|
+
class Press < Machine
|
|
2212
|
+
has_many :widgets, class_name: 'Belt', inverse_of: :machine
|
|
2213
|
+
end
|
|
2214
|
+
end
|
|
2215
|
+
|
|
2216
|
+
after(:all) do
|
|
2217
|
+
Object.send(:remove_const, :Press)
|
|
2218
|
+
Object.send(:remove_const, :Lathe)
|
|
2219
|
+
Object.send(:remove_const, :Machine)
|
|
2220
|
+
Object.send(:remove_const, :Belt)
|
|
2221
|
+
Object.send(:remove_const, :Cog)
|
|
2222
|
+
Object.send(:remove_const, :Supplier)
|
|
2223
|
+
end
|
|
2224
|
+
|
|
2225
|
+
let!(:cog_supplier) { Supplier.create! }
|
|
2226
|
+
let!(:belt_supplier) { Supplier.create! }
|
|
2227
|
+
let!(:lathe) { Lathe.create! }
|
|
2228
|
+
let!(:press) { Press.create! }
|
|
2229
|
+
let!(:cog) { Cog.create!(machine: lathe, supplier: cog_supplier) }
|
|
2230
|
+
let!(:belt) { Belt.create!(machine: press, supplier: belt_supplier) }
|
|
2231
|
+
|
|
2232
|
+
it 'loads each subclass association without one overwriting the other' do
|
|
2233
|
+
loaded = expect_query(1) do
|
|
2234
|
+
Machine.eager_load(:widgets).to_a.index_by(&:id)
|
|
2235
|
+
end
|
|
2236
|
+
expect_no_queries do
|
|
2237
|
+
expect(loaded[lathe.id].widgets).to eq([ cog ])
|
|
2238
|
+
expect(loaded[press.id].widgets).to eq([ belt ])
|
|
2239
|
+
end
|
|
2240
|
+
end
|
|
2241
|
+
|
|
2242
|
+
it 'eager-loads inclusions nested under each subclass association' do
|
|
2243
|
+
loaded = expect_query(1) do
|
|
2244
|
+
Machine.eager_load(widgets: :supplier).to_a.index_by(&:id)
|
|
2245
|
+
end
|
|
2246
|
+
expect_no_queries do
|
|
2247
|
+
expect(loaded[lathe.id].widgets.first.supplier).to eq(cog_supplier)
|
|
2248
|
+
expect(loaded[press.id].widgets.first.supplier).to eq(belt_supplier)
|
|
2249
|
+
end
|
|
2250
|
+
end
|
|
2251
|
+
end
|
|
2252
|
+
|
|
2253
|
+
context 'when a has_many targets a class sharing its collection with sibling subclasses' do
|
|
2254
|
+
before(:all) do
|
|
2255
|
+
class Part
|
|
2256
|
+
include Mongoid::Document
|
|
2257
|
+
end
|
|
2258
|
+
|
|
2259
|
+
class Chip < Part
|
|
2260
|
+
belongs_to :board, class_name: 'Board', optional: true
|
|
2261
|
+
end
|
|
2262
|
+
|
|
2263
|
+
class Cable < Part
|
|
2264
|
+
belongs_to :board, class_name: 'Board', optional: true
|
|
2265
|
+
end
|
|
2266
|
+
|
|
2267
|
+
class Board
|
|
2268
|
+
include Mongoid::Document
|
|
2269
|
+
|
|
2270
|
+
has_many :chips, class_name: 'Chip', inverse_of: :board
|
|
2271
|
+
end
|
|
2272
|
+
end
|
|
2273
|
+
|
|
2274
|
+
after(:all) do
|
|
2275
|
+
Object.send(:remove_const, :Board)
|
|
2276
|
+
Object.send(:remove_const, :Cable)
|
|
2277
|
+
Object.send(:remove_const, :Chip)
|
|
2278
|
+
Object.send(:remove_const, :Part)
|
|
2279
|
+
end
|
|
2280
|
+
|
|
2281
|
+
let!(:board) { Board.create! }
|
|
2282
|
+
let!(:chip) { Chip.create!(board: board) }
|
|
2283
|
+
let!(:cable) { Cable.create!(board: board) }
|
|
2284
|
+
|
|
2285
|
+
it 'eager-loads only the chips, not the sibling subclass' do
|
|
2286
|
+
expect_query(1) do
|
|
2287
|
+
loaded = Board.eager_load(:chips).first
|
|
2288
|
+
expect(loaded.chips.to_a).to eq([ chip ])
|
|
2289
|
+
end
|
|
2290
|
+
end
|
|
2291
|
+
end
|
|
1417
2292
|
end
|
|
1418
2293
|
|
|
1419
2294
|
describe '#inclusions' do
|