Skip to content

Commit

Permalink
Fix relationship.order_by multiple clauses (#105)
Browse files Browse the repository at this point in the history
Fixes #77
  • Loading branch information
MaicoTimmerman authored May 11, 2021
1 parent cadd441 commit 58f03f7
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 4 deletions.
19 changes: 15 additions & 4 deletions sqlalchemy-stubs/orm/relationships.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ from .. import schema as schema
from .. import sql as sql
from .. import util as util
from ..inspection import inspect as inspect
from ..schema import Column
from ..sql import coercions as coercions
from ..sql import elements as elements
from ..sql import expression as expression
from ..sql import operators as operators
from ..sql import roles as roles
Expand All @@ -45,6 +45,19 @@ def foreign(expr: Any): ...
_T = TypeVar("_T")

_InfoDict = Mapping[Any, Any]
_OrderByArgument = Union[
Literal[False],
str,
elements.ColumnElement[Any],
Sequence[elements.ColumnElement[Any]],
Callable[
[],
Union[
elements.ColumnElement[Any],
Sequence[elements.ColumnElement[Any]],
],
],
]

class RelationshipProperty(StrategizedProperty[_T]):
strategy_wildcard_key: str
Expand Down Expand Up @@ -91,9 +104,7 @@ class RelationshipProperty(StrategizedProperty[_T]):
secondaryjoin: Optional[Any] = ...,
foreign_keys: Optional[Any] = ...,
uselist: Optional[bool] = ...,
order_by: Union[
Literal[False], str, Column, Callable[[], Column]
] = ...,
order_by: _OrderByArgument = ...,
backref: Union[str, _BackrefResult] = ...,
back_populates: str = ...,
overlaps: Union[AbstractSet[str], str] = ...,
Expand Down
62 changes: 62 additions & 0 deletions test/files/relationship_order_by_ticket_77.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
from sqlalchemy import Column
from sqlalchemy import create_engine
from sqlalchemy import ForeignKey
from sqlalchemy import Integer
from sqlalchemy import select
from sqlalchemy.orm import joinedload
from sqlalchemy.orm import Mapped
from sqlalchemy.orm import registry
from sqlalchemy.orm import relationship
from sqlalchemy.orm import Session

mapper_registry: registry = registry()

e = create_engine("sqlite:///")


@mapper_registry.mapped
class A:
__tablename__ = "a"
id = Column(Integer, primary_key=True)
b_id = Column(Integer, ForeignKey("b.id"))
number = Column(Integer, primary_key=True)
number2 = Column(Integer, primary_key=True)


@mapper_registry.mapped
class B:
__tablename__ = "b"
id = Column(Integer, primary_key=True)

# Omit order_by
a1: Mapped[A] = relationship("A", uselist=True)

# All kinds of order_by
a2: Mapped[A] = relationship("A", uselist=True, order_by=(A.id, A.number))
a3: Mapped[A] = relationship("A", uselist=True, order_by=[A.id, A.number])
a4: Mapped[A] = relationship("A", uselist=True, order_by=A.id)
a5: Mapped[A] = relationship("A", uselist=True, order_by=A.__table__.c.id)
a6: Mapped[A] = relationship("A", uselist=True, order_by="A.number")

# Same kinds but lambda'd
a7: Mapped[A] = relationship(
"A", uselist=True, order_by=lambda: (A.id, A.number)
)
a8: Mapped[A] = relationship(
"A", uselist=True, order_by=lambda: [A.id, A.number]
)
a9: Mapped[A] = relationship("A", uselist=True, order_by=lambda: A.id)


mapper_registry.metadata.drop_all(e)
mapper_registry.metadata.create_all(e)

with Session(e) as s:
s.execute(select(B).options(joinedload(B.a1)))
s.execute(select(B).options(joinedload(B.a2)))
s.execute(select(B).options(joinedload(B.a3)))
s.execute(select(B).options(joinedload(B.a4)))
s.execute(select(B).options(joinedload(B.a5)))
s.execute(select(B).options(joinedload(B.a7)))
s.execute(select(B).options(joinedload(B.a8)))
s.execute(select(B).options(joinedload(B.a9)))

0 comments on commit 58f03f7

Please sign in to comment.