]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
Ensure loader criteria used for ORM join with expression condition
authorMike Bayer <mike_mp@zzzcomputing.com>
Tue, 19 Sep 2023 12:58:52 +0000 (08:58 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Tue, 27 Feb 2024 13:22:57 +0000 (08:22 -0500)
Fixed bug where ORM :func:`_orm.with_loader_criteria` would not apply
itself to a :meth:`_sql.Select.join` where the ON clause were given as a
plain SQL comparison, rather than as a relationship target or similar.

Fixes: #10365
Change-Id: Ie6d08fb01a3079b7c3ccd3a8241031d46a56e19d
(cherry picked from commit f8086a809bba358790cff032d745814b186ab8cb)

doc/build/changelog/unreleased_14/10365.rst [new file with mode: 0644]
lib/sqlalchemy/orm/util.py
setup.cfg
test/orm/test_relationship_criteria.py

diff --git a/doc/build/changelog/unreleased_14/10365.rst b/doc/build/changelog/unreleased_14/10365.rst
new file mode 100644 (file)
index 0000000..5eb4f44
--- /dev/null
@@ -0,0 +1,9 @@
+.. change::
+    :tags: bug, orm
+    :tickets: 10365
+
+    Fixed bug where ORM :func:`_orm.with_loader_criteria` would not apply
+    itself to a :meth:`_sql.Select.join` where the ON clause were given as a
+    plain SQL comparison, rather than as a relationship target or similar.
+
+    This is a backport of the same issue fixed in version 2.0 for 2.0.22.
index a296fc0c17d8384ab5efe45712085dcdce42d3f8..28bf5b76c8daaf34eeaa2723110155e8a192e0c7 100644 (file)
@@ -1737,9 +1737,8 @@ class _ORMJoin(expression.Join):
         else:
             prop = None
 
+        left_selectable = left_info.selectable
         if prop:
-            left_selectable = left_info.selectable
-
             if sql_util.clause_is_present(on_selectable, left_selectable):
                 adapt_from = on_selectable
             else:
@@ -1774,25 +1773,25 @@ class _ORMJoin(expression.Join):
 
             self._target_adapter = target_adapter
 
-            # we don't use the normal coercions logic for _ORMJoin
-            # (probably should), so do some gymnastics to get the entity.
-            # logic here is for #8721, which was a major bug in 1.4
-            # for almost two years, not reported/fixed until 1.4.43 (!)
-            if left_info.is_selectable:
-                parententity = left_selectable._annotations.get(
-                    "parententity", None
-                )
-            elif left_info.is_mapper or left_info.is_aliased_class:
-                parententity = left_info
-            else:
-                parententity = None
+        # we don't use the normal coercions logic for _ORMJoin
+        # (probably should), so do some gymnastics to get the entity.
+        # logic here is for #8721, which was a major bug in 1.4
+        # for almost two years, not reported/fixed until 1.4.43 (!)
+        if left_info.is_selectable:
+            parententity = left_selectable._annotations.get(
+                "parententity", None
+            )
+        elif left_info.is_mapper or left_info.is_aliased_class:
+            parententity = left_info
+        else:
+            parententity = None
 
-            if parententity is not None:
-                self._annotations = self._annotations.union(
-                    {"parententity": parententity}
-                )
+        if parententity is not None:
+            self._annotations = self._annotations.union(
+                {"parententity": parententity}
+            )
 
-        augment_onclause = onclause is None and _extra_criteria
+        augment_onclause = bool(_extra_criteria) and not prop
         expression.Join.__init__(self, left, right, onclause, isouter, full)
 
         if augment_onclause:
index 852089a99bb37afcbb51d11ded8448773e6cecbd..c11b40cbbf2fd69e891d945a7d531d0c71789b91 100644 (file)
--- a/setup.cfg
+++ b/setup.cfg
@@ -114,6 +114,8 @@ ignore =
     N801,N802,N806,
     RST304,RST303,RST299,RST399,
     W503,W504
+    U100
+    IS001
 exclude = .venv,.git,.tox,dist,doc,*egg,build
 import-order-style = google
 application-import-names = sqlalchemy,test
index d93f1fc8f30cf42bff7a5788b7544b2cef6518d4..82ad752c44dfacf68633ec2830fa8133a8b72233 100644 (file)
@@ -306,6 +306,13 @@ class LoaderCriteriaTest(_Fixtures, testing.AssertsCompiledSQL):
             .join(User.addresses)
             .options(with_loader_criteria(User, User.name != "name")),
         ),
+        (
+            # issue #10365
+            lambda User, Address: select(Address)
+            .select_from(User)
+            .join(Address, User.id == Address.user_id)
+            .options(with_loader_criteria(User, User.name != "name")),
+        ),
         (
             lambda User, Address: select(Address)
             .select_from(orm_join(User, Address, User.addresses))
@@ -354,6 +361,13 @@ class LoaderCriteriaTest(_Fixtures, testing.AssertsCompiledSQL):
             .join(User.addresses)
             .options(with_loader_criteria(User, User.name != "name")),
         ),
+        (
+            # issue #10365 - this seems to have already worked
+            lambda User, Address: select(Address.id, User.id)
+            .select_from(User)
+            .join(Address, User.id == Address.user_id)
+            .options(with_loader_criteria(User, User.name != "name")),
+        ),
         (
             lambda User, Address: select(Address.id, User.id)
             .select_from(orm_join(User, Address, User.addresses))
@@ -403,6 +417,15 @@ class LoaderCriteriaTest(_Fixtures, testing.AssertsCompiledSQL):
                 with_loader_criteria(Address, Address.email_address != "email")
             ),
         ),
+        (
+            # issue #10365
+            lambda User, Address: select(Address)
+            .select_from(User)
+            .join(Address, User.id == Address.user_id)
+            .options(
+                with_loader_criteria(Address, Address.email_address != "email")
+            ),
+        ),
         (
             # for orm_join(), this is set up before we have the context
             # available that allows with_loader_criteria to be set up