]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
allow aliased() to receive any FromClause
authorMike Bayer <mike_mp@zzzcomputing.com>
Tue, 4 Jul 2023 18:13:31 +0000 (14:13 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Tue, 4 Jul 2023 22:41:21 +0000 (18:41 -0400)
Fixed some of the typing within the :func:`_orm.aliased` construct to
correctly accept a :class:`.Table` object that's been aliased with
:meth:`.Table.alias`, as well as general support for :class:`.FromClause`
objects to be passed as the "selectable" argument, since this is all
supported.

Change-Id: I6dfd5c93dc2b2f23895fbd8982633f2ed13b5a52
References: #10061

doc/build/changelog/unreleased_20/10061.rst [new file with mode: 0644]
lib/sqlalchemy/orm/_orm_constructors.py
lib/sqlalchemy/orm/util.py
test/orm/test_core_compilation.py
test/typing/plain_files/orm/typed_queries.py

diff --git a/doc/build/changelog/unreleased_20/10061.rst b/doc/build/changelog/unreleased_20/10061.rst
new file mode 100644 (file)
index 0000000..a8cbaec
--- /dev/null
@@ -0,0 +1,9 @@
+.. change::
+    :tags: bug, typing
+    :tickets: 10061
+
+    Fixed some of the typing within the :func:`_orm.aliased` construct to
+    correctly accept a :class:`.Table` object that's been aliased with
+    :meth:`.Table.alias`, as well as general support for :class:`.FromClause`
+    objects to be passed as the "selectable" argument, since this is all
+    supported.
index b5586350d0ec0f97e2173b570925eae47b75d397..9e41874dc1acdc67a86c0790426e963724a565cb 100644 (file)
@@ -2182,7 +2182,7 @@ AliasedType = Annotated[Type[_O], "aliased"]
 @overload
 def aliased(
     element: Type[_O],
-    alias: Optional[Union[Alias, Subquery]] = None,
+    alias: Optional[FromClause] = None,
     name: Optional[str] = None,
     flat: bool = False,
     adapt_on_names: bool = False,
@@ -2193,7 +2193,7 @@ def aliased(
 @overload
 def aliased(
     element: Union[AliasedClass[_O], Mapper[_O], AliasedInsp[_O]],
-    alias: Optional[Union[Alias, Subquery]] = None,
+    alias: Optional[FromClause] = None,
     name: Optional[str] = None,
     flat: bool = False,
     adapt_on_names: bool = False,
@@ -2204,7 +2204,7 @@ def aliased(
 @overload
 def aliased(
     element: FromClause,
-    alias: Optional[Union[Alias, Subquery]] = None,
+    alias: None = None,
     name: Optional[str] = None,
     flat: bool = False,
     adapt_on_names: bool = False,
@@ -2214,7 +2214,7 @@ def aliased(
 
 def aliased(
     element: Union[_EntityType[_O], FromClause],
-    alias: Optional[Union[Alias, Subquery]] = None,
+    alias: Optional[FromClause] = None,
     name: Optional[str] = None,
     flat: bool = False,
     adapt_on_names: bool = False,
index f50dba52bc0539170e3ec24756732485cd703655..4371e6116f8fa9df0541fbed0e4679aaddc07551 100644 (file)
@@ -114,10 +114,8 @@ if typing.TYPE_CHECKING:
     from ..sql.base import ReadOnlyColumnCollection
     from ..sql.elements import BindParameter
     from ..sql.selectable import _ColumnsClauseElement
-    from ..sql.selectable import Alias
     from ..sql.selectable import Select
     from ..sql.selectable import Selectable
-    from ..sql.selectable import Subquery
     from ..sql.visitors import anon_map
     from ..util.typing import _AnnotationScanType
     from ..util.typing import ArgsTypeProcotol
@@ -1024,7 +1022,7 @@ class AliasedInsp(
     def _alias_factory(
         cls,
         element: Union[_EntityType[_O], FromClause],
-        alias: Optional[Union[Alias, Subquery]] = None,
+        alias: Optional[FromClause] = None,
         name: Optional[str] = None,
         flat: bool = False,
         adapt_on_names: bool = False,
index f66fc7a48e7e0bff85e0037ada892e6885d0aa88..fe47bcd856902debecaeba76a2a0c9e34748de2f 100644 (file)
@@ -2477,6 +2477,46 @@ class RelNaturalAliasedJoinsDisamTest(
     )
 
 
+class JoinedInhTest(
+    InheritedTest, _poly_fixtures._Polymorphic, AssertsCompiledSQL
+):
+    __dialect__ = "default"
+
+    def test_load_only_on_sub_table(self):
+        Company = self.classes.Company
+        Engineer = self.classes.Engineer
+
+        e1 = aliased(Engineer, inspect(Engineer).local_table)
+
+        q = select(Company.name, e1.primary_language).join(
+            Company.employees.of_type(e1)
+        )
+
+        self.assert_compile(
+            q,
+            "SELECT companies.name, engineers.primary_language "
+            "FROM companies JOIN engineers "
+            "ON companies.company_id = people.company_id",
+        )
+
+    def test_load_only_on_sub_table_aliased(self):
+        Company = self.classes.Company
+        Engineer = self.classes.Engineer
+
+        e1 = aliased(Engineer, inspect(Engineer).local_table.alias())
+
+        q = select(Company.name, e1.primary_language).join(
+            Company.employees.of_type(e1)
+        )
+
+        self.assert_compile(
+            q,
+            "SELECT companies.name, engineers_1.primary_language "
+            "FROM companies JOIN engineers AS engineers_1 "
+            "ON companies.company_id = people.company_id",
+        )
+
+
 class RawSelectTest(QueryTest, AssertsCompiledSQL):
     """older tests from test_query.   Here, they are converted to use
     future selects with ORM compilation.
index 8030fcff84e522836b9fcaf92519e6e8f4e2e122..c3468d95280bc45cc4ecbd9729923213b20ded28 100644 (file)
@@ -9,6 +9,7 @@ from sqlalchemy import delete
 from sqlalchemy import func
 from sqlalchemy import insert
 from sqlalchemy import Integer
+from sqlalchemy import join
 from sqlalchemy import MetaData
 from sqlalchemy import Select
 from sqlalchemy import select
@@ -480,3 +481,25 @@ def t_from_statement() -> None:
     reveal_type(ts2)
 
     select(User).from_statement(ts2)
+
+
+def t_aliased_fromclause() -> None:
+    a1 = aliased(User, user_table)
+
+    a2 = aliased(User, user_table.alias())
+
+    a3 = aliased(User, join(user_table, user_table.alias()))
+
+    a4 = aliased(user_table)
+
+    # EXPECTED_TYPE: Type[User]
+    reveal_type(a1)
+
+    # EXPECTED_TYPE: Type[User]
+    reveal_type(a2)
+
+    # EXPECTED_TYPE: Type[User]
+    reveal_type(a3)
+
+    # EXPECTED_TYPE: FromClause
+    reveal_type(a4)