]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
Alias the onclause if ORM join is to same polymorphic selectable
authorMike Bayer <mike_mp@zzzcomputing.com>
Mon, 27 Apr 2020 20:51:43 +0000 (16:51 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Mon, 27 Apr 2020 22:39:11 +0000 (18:39 -0400)
Fixed bug where using :func:`.with_polymorphic` as the target of a join via
:meth:`.RelationshipComparator.of_type` on a mapper that already has a
subquery-based with_polymorphic setting that's equivalent to the one
requested would not correctly alias the ON clause in the join.

Fixes: #5288
Change-Id: I0212a990ee67a344c87fe21833bf47fdb72ca0cc
(cherry picked from commit 483a644959f396e3abdcb8f0f373936569958970)

doc/build/changelog/unreleased_13/5288.rst [new file with mode: 0644]
lib/sqlalchemy/orm/query.py
lib/sqlalchemy/orm/relationships.py
test/orm/inheritance/_poly_fixtures.py
test/orm/inheritance/test_polymorphic_rel.py

diff --git a/doc/build/changelog/unreleased_13/5288.rst b/doc/build/changelog/unreleased_13/5288.rst
new file mode 100644 (file)
index 0000000..d5fbdf5
--- /dev/null
@@ -0,0 +1,8 @@
+.. change::
+    :tags: bug, orm
+    :tickets: 5288
+
+    Fixed bug where using :func:`.with_polymorphic` as the target of a join via
+    :meth:`.RelationshipComparator.of_type` on a mapper that already has a
+    subquery-based with_polymorphic setting that's equivalent to the one
+    requested would not correctly alias the ON clause in the join.
index 1bcf4984215ddd1902ae60e7311e2cd1154d2f4c..2cf82c7d49ea9f53cc7210f6327c13ec58916257 100644 (file)
@@ -2849,7 +2849,6 @@ class Query(object):
             elif prop:
                 # joining to selectable with a mapper property given
                 # as the ON clause
-
                 if not right_selectable.is_derived_from(
                     right_mapper.persist_selectable
                 ):
index daa85c5661787500835046df7d1bbc882f4577f3..209308e4dbf67750e5a74221cdb27cc28d46158f 100644 (file)
@@ -2361,7 +2361,10 @@ class RelationshipProperty(StrategizedProperty):
             if self._is_self_referential and source_selectable is None:
                 dest_selectable = dest_selectable.alias()
                 aliased = True
-        elif dest_selectable is not self.mapper._with_polymorphic_selectable:
+        elif (
+            dest_selectable is not self.mapper._with_polymorphic_selectable
+            or self.mapper.with_polymorphic
+        ):
             aliased = True
 
         dest_mapper = of_type_mapper or self.mapper
index 4756ae78adcf7d24cbb45ec0be64362ab94d22ba..24a600fa502b51818bacaeca2650e75e1f492772 100644 (file)
@@ -150,6 +150,16 @@ class _PolymorphicFixtureBase(fixtures.MappedTest, AssertsCompiledSQL):
             Column("person_id", Integer, ForeignKey("people.person_id")),
         )
 
+    @classmethod
+    def setup_classes(cls):
+        cls.classes["Engineer"] = Engineer
+        cls.classes["Person"] = Person
+        cls.classes["Manager"] = Manager
+        cls.classes["Machine"] = Machine
+        cls.classes["Boss"] = Boss
+        cls.classes["Company"] = Company
+        cls.classes["Paperwork"] = Paperwork
+
     @classmethod
     def insert_data(cls, connection):
 
index 880cc5f913d42cbb93f436c0f08d76d1ac5539e1..ad9b57015081548e356ee4ee83b0741ad8df6ef0 100644 (file)
@@ -1349,6 +1349,55 @@ class _PolymorphicTestBase(object):
             expected,
         )
 
+    def _join_to_poly_wp_one(self, sess):
+        wp = with_polymorphic(self.classes.Person, "*")
+        return (
+            sess.query(wp.name, self.classes.Company.name)
+            .join(self.classes.Company.employees.of_type(wp))
+            .order_by(wp.person_id)
+        )
+
+    def _join_to_poly_wp_two(self, sess):
+        wp = with_polymorphic(self.classes.Person, "*", aliased=True)
+        return (
+            sess.query(wp.name, self.classes.Company.name)
+            .join(self.classes.Company.employees.of_type(wp))
+            .order_by(wp.person_id)
+        )
+
+    def _join_to_poly_wp_three(self, sess):
+        wp = with_polymorphic(
+            self.classes.Person, "*", aliased=True, flat=True
+        )
+        return (
+            sess.query(wp.name, self.classes.Company.name)
+            .join(self.classes.Company.employees.of_type(wp))
+            .order_by(wp.person_id)
+        )
+
+    @testing.combinations(
+        lambda self, sess: (
+            sess.query(self.classes.Person.name, self.classes.Company.name)
+            .join(self.classes.Company.employees)
+            .order_by(self.classes.Person.person_id)
+        ),
+        _join_to_poly_wp_one,
+        _join_to_poly_wp_two,
+        _join_to_poly_wp_three,
+    )
+    def test_mixed_entities_join_to_poly(self, q):
+        sess = create_session()
+        expected = [
+            ("dilbert", "MegaCorp, Inc."),
+            ("wally", "MegaCorp, Inc."),
+            ("pointy haired boss", "MegaCorp, Inc."),
+            ("dogbert", "MegaCorp, Inc."),
+            ("vlad", "Elbonia, Inc."),
+        ]
+        eq_(
+            q(self, sess).all(), expected,
+        )
+
     def test_mixed_entities_two(self):
         sess = create_session()
         expected = [