diff options
| author | Mike Bayer <mike_mp@zzzcomputing.com> | 2019-01-26 19:49:44 -0500 |
|---|---|---|
| committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2019-02-04 10:37:45 -0500 |
| commit | 95c371f1d3007071a32fad1d67329e6f9d56931b (patch) | |
| tree | 8f8d1ef868dbf1b623bbd1d4ad9f25db5d65a8c4 /test | |
| parent | 7e48d8b2a70b399ffa6ec874f824d6cee82980a0 (diff) | |
| download | sqlalchemy-95c371f1d3007071a32fad1d67329e6f9d56931b.tar.gz | |
Improve support for with_polymorphic in mapper options
Improved the behavior of :func:`.orm.with_polymorphic` in conjunction with
loader options, in particular wildcard operations as well as
:func:`.orm.load_only`. The polymorphic object will be more accurately
targeted so that column-level options on the entity will correctly take
effect.The issue is a continuation of the same kinds of things fixed in
:ticket:`4468`.
The path logic when using chained mapper options is improved
to be more accurate in terms of the entities being linked
in the path; when using :func:`.with_polymorphic`, mapper
options against this entity need to specify attributes
in terms of the with_polymorphic() object and not against the
base mappings. New error conditions are raised which were previously
more than likely silenty failures.
Fixes: #4469
Change-Id: Ie8d802879663b4ff6f6ac1438c885c06d78ae2a0
Diffstat (limited to 'test')
| -rw-r--r-- | test/aaa_profiling/test_memusage.py | 11 | ||||
| -rw-r--r-- | test/orm/inheritance/test_relationship.py | 4 | ||||
| -rw-r--r-- | test/orm/test_deferred.py | 71 | ||||
| -rw-r--r-- | test/orm/test_options.py | 80 |
4 files changed, 162 insertions, 4 deletions
diff --git a/test/aaa_profiling/test_memusage.py b/test/aaa_profiling/test_memusage.py index 36f28c063..8e7bd57bb 100644 --- a/test/aaa_profiling/test_memusage.py +++ b/test/aaa_profiling/test_memusage.py @@ -738,12 +738,19 @@ class MemUsageWBackendTest(EnsureZeroed): Column("foo", Integer), Column("bar", Integer), ) - m1 = mapper(A, a) + b = Table( + "b", + metadata, + Column("id", Integer, primary_key=True), + Column("a_id", ForeignKey("a.id")), + ) + m1 = mapper(A, a, properties={"bs": relationship(B)}) + m2 = mapper(B, b) @profile_memory() def go(): ma = sa.inspect(aliased(A)) - m1._path_registry[m1.attrs.foo][ma][m1.attrs.bar] + m1._path_registry[m1.attrs.bs][ma][m1.attrs.bar] go() clear_mappers() diff --git a/test/orm/inheritance/test_relationship.py b/test/orm/inheritance/test_relationship.py index 9db2a5163..11f945fcd 100644 --- a/test/orm/inheritance/test_relationship.py +++ b/test/orm/inheritance/test_relationship.py @@ -1971,7 +1971,7 @@ class JoinedloadOverWPolyAliased( q = session.query(poly).options( joinedload(poly.Sub1.links) .joinedload(Link.child.of_type(Sub1)) - .joinedload(poly.Sub1.links) + .joinedload(Sub1.links) ) self.assert_compile( q, @@ -1999,7 +1999,7 @@ class JoinedloadOverWPolyAliased( q = session.query(poly).options( joinedload(poly.Sub1.links, innerjoin=True) .joinedload(Link.child.of_type(Sub1), innerjoin=True) - .joinedload(poly.Sub1.links, innerjoin=True) + .joinedload(Sub1.links, innerjoin=True) ) self.assert_compile( q, diff --git a/test/orm/test_deferred.py b/test/orm/test_deferred.py index d9ac6b0ff..6b9c1c918 100644 --- a/test/orm/test_deferred.py +++ b/test/orm/test_deferred.py @@ -1554,6 +1554,77 @@ class InheritanceTest(_Polymorphic): "ORDER BY people.person_id", ) + def test_load_only_from_with_polymorphic(self): + s = Session() + + wp = with_polymorphic(Person, [Manager], flat=True) + + assert_raises_message( + sa.exc.ArgumentError, + 'Mapped attribute "Manager.status" does not apply to any of the ' + "root entities in this query, e.g. " + r"with_polymorphic\(Person, \[Manager\]\).", + s.query(wp).options, + load_only(Manager.status), + ) + + q = s.query(wp).options(load_only(wp.Manager.status)) + self.assert_compile( + q, + "SELECT people_1.person_id AS people_1_person_id, " + "people_1.type AS people_1_type, " + "managers_1.person_id AS managers_1_person_id, " + "managers_1.status AS managers_1_status " + "FROM people AS people_1 " + "LEFT OUTER JOIN managers AS managers_1 " + "ON people_1.person_id = managers_1.person_id", + ) + + def test_load_only_of_type_with_polymorphic(self): + s = Session() + + wp = with_polymorphic(Person, [Manager], flat=True) + + # needs to be explicit, we don't currently dig onto all the + # sub-entities in the wp + assert_raises_message( + sa.exc.ArgumentError, + r'Can\'t find property named "status" on ' + r"with_polymorphic\(Person, \[Manager\]\) in this Query.", + s.query(Company).options, + joinedload(Company.employees.of_type(wp)).load_only("status"), + ) + + assert_raises_message( + sa.exc.ArgumentError, + 'Attribute "Manager.status" does not link from element ' + r'"with_polymorphic\(Person, \[Manager\]\)"', + s.query(Company).options, + joinedload(Company.employees.of_type(wp)).load_only( + Manager.status + ), + ) + + self.assert_compile( + s.query(Company).options( + joinedload(Company.employees.of_type(wp)).load_only( + wp.Manager.status + ) + ), + # should at least not have manager_name in it + "SELECT companies.company_id AS companies_company_id, " + "companies.name AS companies_name, " + "people_1.person_id AS people_1_person_id, " + "people_1.type AS people_1_type, " + "managers_1.person_id AS managers_1_person_id, " + "managers_1.status AS managers_1_status " + "FROM companies LEFT OUTER JOIN " + "(people AS people_1 LEFT OUTER JOIN managers AS managers_1 " + "ON people_1.person_id = managers_1.person_id) " + "ON companies.company_id = people_1.company_id " + "ORDER BY people_1.person_id", + ) + class WithExpressionTest(fixtures.DeclarativeMappedTest): @classmethod diff --git a/test/orm/test_options.py b/test/orm/test_options.py index b4953cd3b..e382a8097 100644 --- a/test/orm/test_options.py +++ b/test/orm/test_options.py @@ -21,10 +21,16 @@ from sqlalchemy.orm import Session from sqlalchemy.orm import strategy_options from sqlalchemy.orm import subqueryload from sqlalchemy.orm import util as orm_util +from sqlalchemy.orm import with_polymorphic from sqlalchemy.testing import fixtures from sqlalchemy.testing.assertions import assert_raises_message from sqlalchemy.testing.assertions import eq_ from test.orm import _fixtures +from .inheritance._poly_fixtures import _Polymorphic +from .inheritance._poly_fixtures import Company +from .inheritance._poly_fixtures import Engineer +from .inheritance._poly_fixtures import Manager +from .inheritance._poly_fixtures import Person class QueryTest(_fixtures.FixtureTest): @@ -1239,6 +1245,80 @@ class OptionsNoPropTest(_fixtures.FixtureTest): ) +class OptionsNoPropTestInh(_Polymorphic): + def test_missing_attr_wpoly_subclasss(self): + s = Session() + + wp = with_polymorphic(Person, [Manager], flat=True) + + assert_raises_message( + sa.exc.ArgumentError, + r'Mapped attribute "Manager.status" does not apply to any of ' + r"the root entities in this query, e.g. " + r"with_polymorphic\(Person, \[Manager\]\).", + s.query(wp).options, + load_only(Manager.status), + ) + + def test_missing_attr_of_type_subclass(self): + s = Session() + + assert_raises_message( + sa.exc.ArgumentError, + r'Attribute "Manager.manager_name" does not link from element ' + r'"with_polymorphic\(Person, \[Engineer\]\)"', + s.query(Company).options, + joinedload(Company.employees.of_type(Engineer)).load_only( + Manager.manager_name + ), + ) + + def test_missing_attr_of_type_subclass_name_matches(self): + s = Session() + + # the name "status" is present on Engineer also, make sure + # that doesn't get mixed up here + assert_raises_message( + sa.exc.ArgumentError, + r'Attribute "Manager.status" does not link from element ' + r'"with_polymorphic\(Person, \[Engineer\]\)"', + s.query(Company).options, + joinedload(Company.employees.of_type(Engineer)).load_only( + Manager.status + ), + ) + + def test_missing_str_attr_of_type_subclass(self): + s = Session() + + wp = with_polymorphic(Person, [Manager], flat=True) + + assert_raises_message( + sa.exc.ArgumentError, + r'Can\'t find property named "manager_name" on ' + "mapped class Engineer->engineers in this Query.", + s.query(Company).options, + joinedload(Company.employees.of_type(Engineer)).load_only( + "manager_name" + ), + ) + + def test_missing_attr_of_type_wpoly_subclass(self): + s = Session() + + wp = with_polymorphic(Person, [Manager], flat=True) + + assert_raises_message( + sa.exc.ArgumentError, + r'Attribute "Manager.manager_name" does not link from ' + r'element "with_polymorphic\(Person, \[Manager\]\)"', + s.query(Company).options, + joinedload(Company.employees.of_type(wp)).load_only( + Manager.manager_name + ), + ) + + class PickleTest(PathTest, QueryTest): def _option_fixture(self, *arg): return strategy_options._UnboundLoad._from_keys( |
