]> 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, 19 Sep 2023 13:27:54 +0000 (09:27 -0400)
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

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

diff --git a/doc/build/changelog/unreleased_20/10365.rst b/doc/build/changelog/unreleased_20/10365.rst
new file mode 100644 (file)
index 0000000..87791d7
--- /dev/null
@@ -0,0 +1,7 @@
+.. 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.
index f22a7988032858b62d4ad7d7e9242b3ee87b511f..a838d8d08eb89a9d535de202390f3deff0c4eddc 100644 (file)
@@ -1828,8 +1828,8 @@ class _ORMJoin(expression.Join):
             prop = None
             on_selectable = None
 
+        left_selectable = left_info.selectable
         if prop:
-            left_selectable = left_info.selectable
             adapt_from: Optional[FromClause]
             if sql_util.clause_is_present(on_selectable, left_selectable):
                 adapt_from = on_selectable
@@ -1866,25 +1866,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 is_selectable(left_info):
-                parententity = left_selectable._annotations.get(
-                    "parententity", None
-                )
-            elif insp_is_mapper(left_info) or insp_is_aliased_class(left_info):
-                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 is_selectable(left_info):
+            parententity = left_selectable._annotations.get(
+                "parententity", None
+            )
+        elif insp_is_mapper(left_info) or insp_is_aliased_class(left_info):
+            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)
 
         assert self.onclause is not None
index e67f9a01d5ce20066b2cb3ed8c4492f9af95bf26..aebdf6922aead949cb9f643e1b2944c6d7dd6b02 100644 (file)
@@ -314,6 +314,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))
@@ -362,6 +369,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))
@@ -411,6 +425,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