diff options
| author | Mike Bayer <mike_mp@zzzcomputing.com> | 2014-05-25 13:45:32 -0400 |
|---|---|---|
| committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2014-05-25 13:45:32 -0400 |
| commit | 95b10c4e8e59cf2509ba5d90a03341d74f93d164 (patch) | |
| tree | bd2723a3f02502ffebb35f538f0ac8477aec3a12 | |
| parent | e6cbd88fe17a8ce63078b00293fbe3da2ddf9ea4 (diff) | |
| download | sqlalchemy-95b10c4e8e59cf2509ba5d90a03341d74f93d164.tar.gz | |
- Fixed bug in subquery eager loading where a long chain of
eager loads across a polymorphic-subclass boundary in conjunction
with polymorphic loading would fail to locate the subclass-link in the
chain, erroring out with a missing property name on an
:class:`.AliasedClass`. fixes #3055
| -rw-r--r-- | doc/build/changelog/changelog_08.rst | 11 | ||||
| -rw-r--r-- | lib/sqlalchemy/orm/strategies.py | 2 | ||||
| -rw-r--r-- | test/orm/inheritance/_poly_fixtures.py | 2 | ||||
| -rw-r--r-- | test/orm/test_subquery_relations.py | 111 |
4 files changed, 124 insertions, 2 deletions
diff --git a/doc/build/changelog/changelog_08.rst b/doc/build/changelog/changelog_08.rst index 61ef96aff..c3c0900a1 100644 --- a/doc/build/changelog/changelog_08.rst +++ b/doc/build/changelog/changelog_08.rst @@ -12,6 +12,17 @@ :version: 0.8.7 .. change:: + :tags: bug, orm + :versions: 0.9.5, 1.0.0 + :tickets: 3055 + + Fixed bug in subquery eager loading where a long chain of + eager loads across a polymorphic-subclass boundary in conjunction + with polymorphic loading would fail to locate the subclass-link in the + chain, erroring out with a missing property name on an + :class:`.AliasedClass`. + + .. change:: :tags: bug, ext :versions: 0.9.5 :tickets: 3051 diff --git a/lib/sqlalchemy/orm/strategies.py b/lib/sqlalchemy/orm/strategies.py index 3ebadd62b..c8946a0c0 100644 --- a/lib/sqlalchemy/orm/strategies.py +++ b/lib/sqlalchemy/orm/strategies.py @@ -885,7 +885,7 @@ class SubqueryLoader(AbstractRelationshipLoader): attr = getattr(parent_alias, key).\ of_type(effective_entity) else: - attr = key + attr = getattr(mapper.entity, key) if second_to_last: q = q.join(parent_alias, attr, from_joinpoint=True) diff --git a/test/orm/inheritance/_poly_fixtures.py b/test/orm/inheritance/_poly_fixtures.py index 1370c4cf8..689d19d33 100644 --- a/test/orm/inheritance/_poly_fixtures.py +++ b/test/orm/inheritance/_poly_fixtures.py @@ -23,6 +23,8 @@ class Boss(Manager): pass class Machine(fixtures.ComparableEntity): pass +class MachineType(fixtures.ComparableEntity): + pass class Paperwork(fixtures.ComparableEntity): pass diff --git a/test/orm/test_subquery_relations.py b/test/orm/test_subquery_relations.py index 4958bdfd5..03498d7ea 100644 --- a/test/orm/test_subquery_relations.py +++ b/test/orm/test_subquery_relations.py @@ -976,7 +976,8 @@ class OrderBySecondaryTest(fixtures.MappedTest): self.assert_sql_count(testing.db, go, 2) -from .inheritance._poly_fixtures import _Polymorphic, Person, Engineer, Paperwork +from .inheritance._poly_fixtures import _Polymorphic, Person, Engineer, \ + Paperwork, Machine, MachineType, Company class BaseRelationFromJoinedSubclassTest(_Polymorphic): @classmethod @@ -1132,7 +1133,115 @@ class BaseRelationFromJoinedSubclassTest(_Polymorphic): ) ) +class SubRelationFromJoinedSubclassMultiLevelTest(_Polymorphic): + @classmethod + def define_tables(cls, metadata): + Table('companies', metadata, + Column('company_id', Integer, + primary_key=True, + test_needs_autoincrement=True), + Column('name', String(50))) + + Table('people', metadata, + Column('person_id', Integer, + primary_key=True, + test_needs_autoincrement=True), + Column('company_id', ForeignKey('companies.company_id')), + Column('name', String(50)), + Column('type', String(30))) + + Table('engineers', metadata, + Column('engineer_id', ForeignKey('people.person_id'), + primary_key=True), + Column('primary_language', String(50))) + + Table('machines', metadata, + Column('machine_id', + Integer, primary_key=True, + test_needs_autoincrement=True), + Column('name', String(50)), + Column('engineer_id', ForeignKey('engineers.engineer_id')), + Column('machine_type_id', + ForeignKey('machine_type.machine_type_id'))) + + Table('machine_type', metadata, + Column('machine_type_id', + Integer, primary_key=True, + test_needs_autoincrement=True), + Column('name', String(50))) + + @classmethod + def setup_mappers(cls): + companies = cls.tables.companies + people = cls.tables.people + engineers = cls.tables.engineers + machines = cls.tables.machines + machine_type = cls.tables.machine_type + + mapper(Company, companies, properties={ + 'employees': relationship(Person, order_by=people.c.person_id) + }) + mapper(Person, people, + polymorphic_on=people.c.type, + polymorphic_identity='person', + with_polymorphic='*') + + mapper(Engineer, engineers, + inherits=Person, + polymorphic_identity='engineer', properties={ + 'machines': relationship(Machine, + order_by=machines.c.machine_id) + }) + + mapper(Machine, machines, properties={ + 'type': relationship(MachineType) + }) + mapper(MachineType, machine_type) + + + @classmethod + def insert_data(cls): + c1 = cls._fixture() + sess = create_session() + sess.add(c1) + sess.flush() + + @classmethod + def _fixture(cls): + mt1 = MachineType(name='mt1') + mt2 = MachineType(name='mt2') + return Company( + employees=[ + Engineer( + name='e1', + machines=[ + Machine(name='m1', type=mt1), + Machine(name='m2', type=mt2) + ] + ), + Engineer( + name='e2', + machines=[ + Machine(name='m3', type=mt1), + Machine(name='m4', type=mt1) + ] + ) + ]) + def test_chained_subq_subclass(self): + s = Session() + q = s.query(Company).options( + subqueryload(Company.employees.of_type(Engineer)). + subqueryload(Engineer.machines). + subqueryload(Machine.type) + ) + + def go(): + eq_( + q.all(), + [self._fixture()] + ) + self.assert_sql_count(testing.db, go, 4) class SelfReferentialTest(fixtures.MappedTest): |
