from ..util.typing import Unpack
if typing.TYPE_CHECKING:
+ from typing import Type
+
+ from .. import inspection
+ from ..sql import roles
+ from ..sql._typing import _HasClauseElement
from ..sql.elements import SQLCoreOperations
from ..sql.type_api import _ResultProcessorType
-_KeyType = Union[str, "SQLCoreOperations[Any]"]
+_KeyType = Union[
+ str,
+ "SQLCoreOperations[Any]",
+ "roles.TypedColumnsClauseRole[Any]",
+ "roles.ColumnsClauseRole",
+ "Type[Any]",
+ "inspection.Inspectable[_HasClauseElement[Any]]",
+]
_KeyIndexType = Union[_KeyType, int]
# is overridden in cursor using _CursorKeyMapRecType
def test_bundles() -> None:
b1 = orm.Bundle("b1", A.id, A.data)
orm.Bundle("b2", A.id, A.data, b1)
+
+
+def test_row_mapping_with_orm_entities() -> None:
+ """Test row._mapping access with ORM entities and aliased entities."""
+ from sqlalchemy import create_engine
+
+ engine = create_engine("sqlite://")
+
+ # Test with regular mapped class
+ stmt1 = select(A, B)
+ with orm.Session(engine) as session:
+ for row in session.execute(stmt1):
+ _ = row._mapping[A]
+ _ = row._mapping[B]
+
+ # Test with aliased class
+ a_alias = aliased(A)
+ b_alias = aliased(B)
+ stmt2 = select(a_alias, b_alias)
+ with orm.Session(engine) as session:
+ for row in session.execute(stmt2):
+ _ = row._mapping[a_alias]
+ _ = row._mapping[b_alias]
--- /dev/null
+from typing import assert_type
+from typing import TYPE_CHECKING
+
+from sqlalchemy import create_engine
+from sqlalchemy import ForeignKey
+from sqlalchemy import select
+from sqlalchemy.orm import DeclarativeBase
+from sqlalchemy.orm import Mapped
+from sqlalchemy.orm import mapped_column
+from sqlalchemy.orm import Session
+from sqlalchemy.orm import with_polymorphic
+from sqlalchemy.orm.util import AliasedClass
+
+
+class Base(DeclarativeBase):
+ pass
+
+
+class Company(Base):
+ __tablename__ = "company"
+ company_id: Mapped[int] = mapped_column(primary_key=True)
+ name: Mapped[str]
+
+
+class Employee(Base):
+ __tablename__ = "employee"
+ __mapper_args__ = {
+ "polymorphic_on": "type",
+ "polymorphic_identity": "employee",
+ }
+ employee_id: Mapped[int] = mapped_column(primary_key=True)
+ company_id: Mapped[int] = mapped_column(ForeignKey("company.company_id"))
+ name: Mapped[str]
+ type: Mapped[str]
+
+
+class Manager(Employee):
+ __tablename__ = "manager"
+ __mapper_args__ = {
+ "polymorphic_identity": "manager",
+ }
+ employee_id: Mapped[int] = mapped_column(
+ ForeignKey("employee.employee_id"), primary_key=True
+ )
+ manager_data: Mapped[str]
+
+
+class Engineer(Employee):
+ __tablename__ = "engineer"
+ __mapper_args__ = {
+ "polymorphic_identity": "engineer",
+ }
+ employee_id: Mapped[int] = mapped_column(
+ ForeignKey("employee.employee_id"), primary_key=True
+ )
+ engineer_info: Mapped[str]
+
+
+engine = create_engine("sqlite://")
+
+
+def test_with_polymorphic_aliased_in_join() -> None:
+ """Test that with_polymorphic with aliased=True can be used in join().
+
+ Relates to discussion #13075.
+ """
+ manager_employee = with_polymorphic(
+ Employee, [Manager], aliased=True, flat=True
+ )
+ engineer_employee = with_polymorphic(
+ Employee, [Engineer], aliased=True, flat=True
+ )
+
+ if TYPE_CHECKING:
+ assert_type(manager_employee, AliasedClass[Employee])
+ assert_type(engineer_employee, AliasedClass[Employee])
+
+ # Should not produce a type error
+ stmt = select(manager_employee, engineer_employee).join(
+ engineer_employee,
+ engineer_employee.company_id == manager_employee.company_id,
+ )
+
+ with Session(engine) as session:
+ session.execute(stmt)
+
+
+def test_with_polymorphic_aliased_in_row_mapping() -> None:
+ """Test that with_polymorphic result can be used as key in row._mapping.
+
+ Relates to discussion #13075.
+ """
+ manager_employee = with_polymorphic(
+ Employee, [Manager], aliased=True, flat=True
+ )
+ engineer_employee = with_polymorphic(
+ Employee, [Engineer], aliased=True, flat=True
+ )
+
+ stmt = select(manager_employee, engineer_employee).join(
+ engineer_employee,
+ engineer_employee.company_id == manager_employee.company_id,
+ )
+
+ with Session(engine) as session:
+ for row in session.execute(stmt):
+ # Should not produce a type error - discussion #13075
+ _ = row._mapping[manager_employee]
+ _ = row._mapping[engineer_employee]
+
+
+def test_with_polymorphic_non_aliased_in_row_mapping() -> None:
+ """Test with_polymorphic without aliased=True in row._mapping."""
+ poly_employee = with_polymorphic(Employee, [Manager, Engineer])
+
+ stmt = select(poly_employee)
+
+ with Session(engine) as session:
+ for row in session.execute(stmt):
+ _ = row._mapping[poly_employee]