summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2019-01-26 19:49:44 -0500
committerMike Bayer <mike_mp@zzzcomputing.com>2019-02-04 10:37:45 -0500
commit95c371f1d3007071a32fad1d67329e6f9d56931b (patch)
tree8f8d1ef868dbf1b623bbd1d4ad9f25db5d65a8c4 /test
parent7e48d8b2a70b399ffa6ec874f824d6cee82980a0 (diff)
downloadsqlalchemy-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.py11
-rw-r--r--test/orm/inheritance/test_relationship.py4
-rw-r--r--test/orm/test_deferred.py71
-rw-r--r--test/orm/test_options.py80
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(