]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
Ensure of_type subclass taken into account with wildcards
authorMike Bayer <mike_mp@zzzcomputing.com>
Sat, 26 Jan 2019 19:53:45 +0000 (14:53 -0500)
committerMike Bayer <mike_mp@zzzcomputing.com>
Sat, 26 Jan 2019 20:04:07 +0000 (15:04 -0500)
Fixed a regression in 1.2 where a wildcard/load_only loader option would
not work correctly against a loader path where of_type() were used to limit
to a particular subclass.  The fix only works for of_type() of a simple
subclass so far, not a with_polymorphic entity which will be addressed in a
separate issue; it is unlikely this latter case was working previously.

Since we ensure that the entity is broken out into its superclasses
when a wilcard is encountered, we can limit the entity path to the
specific entity given in this case.

Within this issue some additional issues with with_polymorphic()
loaders were found which will be addressed in #4469.

Fixes: #4468
Change-Id: Ie91ec27b49104e019636f870776e294321586a9e

doc/build/changelog/unreleased_12/4468.rst [new file with mode: 0644]
lib/sqlalchemy/orm/strategy_options.py
test/orm/test_deferred.py

diff --git a/doc/build/changelog/unreleased_12/4468.rst b/doc/build/changelog/unreleased_12/4468.rst
new file mode 100644 (file)
index 0000000..0106d2f
--- /dev/null
@@ -0,0 +1,10 @@
+.. change::
+   :tags: bug, orm
+   :tickets: 4468
+
+    Fixed a regression in 1.2 where a wildcard/load_only loader option would
+    not work correctly against a loader path where of_type() were used to limit
+    to a particular subclass.  The fix only works for of_type() of a simple
+    subclass so far, not a with_polymorphic entity which will be addressed in a
+    separate issue; it is unlikely this latter case was working previously.
+
index 19c81860e80f9bf5aa9388b7b51cceec5ef90a5f..ee3b83caa01808aa7fbbaa4fea045b78cdf50b08 100644 (file)
@@ -203,6 +203,13 @@ class Load(Generative, MapperOption):
                     self.propagate_to_loaders = False
                 if wildcard_key:
                     attr = "%s:%s" % (wildcard_key, attr)
+
+                # TODO: AliasedInsp inside the path for of_type is not
+                # working for a with_polymorphic entity because the
+                # relationship loaders don't render the with_poly into the
+                # path.  See #4469 which will try to improve this
+                if existing_of_type and not existing_of_type.is_aliased_class:
+                    path = path.parent[existing_of_type]
                 path = path.token(attr)
                 self.path = path
                 return path
@@ -706,7 +713,6 @@ class _UnboundLoad(Load):
 
         if not loader.is_class_strategy:
             for idx, token in enumerate(start_path):
-
                 if not loader._generate_path(
                     loader.path,
                     token,
index 551952cfe1c3a47a661163b75b85d379527494c6..d9ac6b0ff571ca7beb27844b3d451832e7d207ef 100644 (file)
@@ -1472,6 +1472,54 @@ class InheritanceTest(_Polymorphic):
         # note this doesn't apply to "bound" loaders since they don't seem
         # to have this ".*" featue.
 
+    def test_load_only_subclass_of_type(self):
+        s = Session()
+        q = s.query(Company).options(
+            joinedload(Company.employees.of_type(Manager)).load_only("status")
+        )
+        self.assert_compile(
+            q,
+            "SELECT companies.company_id AS companies_company_id, "
+            "companies.name AS companies_name, "
+            "anon_1.people_person_id AS anon_1_people_person_id, "
+            "anon_1.people_type AS anon_1_people_type, "
+            "anon_1.managers_person_id AS anon_1_managers_person_id, "
+            "anon_1.managers_status AS anon_1_managers_status "
+            "FROM companies LEFT OUTER JOIN "
+            "(SELECT people.person_id AS people_person_id, "
+            "people.company_id AS people_company_id, "
+            "people.name AS people_name, people.type AS people_type, "
+            "managers.person_id AS managers_person_id, "
+            "managers.status AS managers_status, "
+            "managers.manager_name AS managers_manager_name "
+            "FROM people LEFT OUTER JOIN managers "
+            "ON people.person_id = managers.person_id) AS anon_1 "
+            "ON companies.company_id = anon_1.people_company_id "
+            "ORDER BY anon_1.people_person_id",
+        )
+
+    def test_wildcard_subclass_of_type(self):
+        s = Session()
+        q = s.query(Company).options(
+            joinedload(Company.employees.of_type(Manager)).defer("*")
+        )
+        self.assert_compile(
+            q,
+            "SELECT companies.company_id AS companies_company_id, "
+            "companies.name AS companies_name "
+            "FROM companies LEFT OUTER JOIN "
+            "(SELECT people.person_id AS people_person_id, "
+            "people.company_id AS people_company_id, "
+            "people.name AS people_name, people.type AS people_type, "
+            "managers.person_id AS managers_person_id, "
+            "managers.status AS managers_status, "
+            "managers.manager_name AS managers_manager_name "
+            "FROM people LEFT OUTER JOIN managers "
+            "ON people.person_id = managers.person_id) AS anon_1 "
+            "ON companies.company_id = anon_1.people_company_id "
+            "ORDER BY anon_1.people_person_id",
+        )
+
     def test_defer_super_name_on_subclass(self):
         s = Session()
         q = s.query(Manager).order_by(Person.person_id).options(defer("name"))