Skip to content

Commit 58f03f7

Browse files
Fix relationship.order_by multiple clauses (#105)
Fixes #77
1 parent cadd441 commit 58f03f7

File tree

2 files changed

+77
-4
lines changed

2 files changed

+77
-4
lines changed

sqlalchemy-stubs/orm/relationships.pyi

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ from .. import schema as schema
2727
from .. import sql as sql
2828
from .. import util as util
2929
from ..inspection import inspect as inspect
30-
from ..schema import Column
3130
from ..sql import coercions as coercions
31+
from ..sql import elements as elements
3232
from ..sql import expression as expression
3333
from ..sql import operators as operators
3434
from ..sql import roles as roles
@@ -45,6 +45,19 @@ def foreign(expr: Any): ...
4545
_T = TypeVar("_T")
4646

4747
_InfoDict = Mapping[Any, Any]
48+
_OrderByArgument = Union[
49+
Literal[False],
50+
str,
51+
elements.ColumnElement[Any],
52+
Sequence[elements.ColumnElement[Any]],
53+
Callable[
54+
[],
55+
Union[
56+
elements.ColumnElement[Any],
57+
Sequence[elements.ColumnElement[Any]],
58+
],
59+
],
60+
]
4861

4962
class RelationshipProperty(StrategizedProperty[_T]):
5063
strategy_wildcard_key: str
@@ -91,9 +104,7 @@ class RelationshipProperty(StrategizedProperty[_T]):
91104
secondaryjoin: Optional[Any] = ...,
92105
foreign_keys: Optional[Any] = ...,
93106
uselist: Optional[bool] = ...,
94-
order_by: Union[
95-
Literal[False], str, Column, Callable[[], Column]
96-
] = ...,
107+
order_by: _OrderByArgument = ...,
97108
backref: Union[str, _BackrefResult] = ...,
98109
back_populates: str = ...,
99110
overlaps: Union[AbstractSet[str], str] = ...,
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
from sqlalchemy import Column
2+
from sqlalchemy import create_engine
3+
from sqlalchemy import ForeignKey
4+
from sqlalchemy import Integer
5+
from sqlalchemy import select
6+
from sqlalchemy.orm import joinedload
7+
from sqlalchemy.orm import Mapped
8+
from sqlalchemy.orm import registry
9+
from sqlalchemy.orm import relationship
10+
from sqlalchemy.orm import Session
11+
12+
mapper_registry: registry = registry()
13+
14+
e = create_engine("sqlite:///")
15+
16+
17+
@mapper_registry.mapped
18+
class A:
19+
__tablename__ = "a"
20+
id = Column(Integer, primary_key=True)
21+
b_id = Column(Integer, ForeignKey("b.id"))
22+
number = Column(Integer, primary_key=True)
23+
number2 = Column(Integer, primary_key=True)
24+
25+
26+
@mapper_registry.mapped
27+
class B:
28+
__tablename__ = "b"
29+
id = Column(Integer, primary_key=True)
30+
31+
# Omit order_by
32+
a1: Mapped[A] = relationship("A", uselist=True)
33+
34+
# All kinds of order_by
35+
a2: Mapped[A] = relationship("A", uselist=True, order_by=(A.id, A.number))
36+
a3: Mapped[A] = relationship("A", uselist=True, order_by=[A.id, A.number])
37+
a4: Mapped[A] = relationship("A", uselist=True, order_by=A.id)
38+
a5: Mapped[A] = relationship("A", uselist=True, order_by=A.__table__.c.id)
39+
a6: Mapped[A] = relationship("A", uselist=True, order_by="A.number")
40+
41+
# Same kinds but lambda'd
42+
a7: Mapped[A] = relationship(
43+
"A", uselist=True, order_by=lambda: (A.id, A.number)
44+
)
45+
a8: Mapped[A] = relationship(
46+
"A", uselist=True, order_by=lambda: [A.id, A.number]
47+
)
48+
a9: Mapped[A] = relationship("A", uselist=True, order_by=lambda: A.id)
49+
50+
51+
mapper_registry.metadata.drop_all(e)
52+
mapper_registry.metadata.create_all(e)
53+
54+
with Session(e) as s:
55+
s.execute(select(B).options(joinedload(B.a1)))
56+
s.execute(select(B).options(joinedload(B.a2)))
57+
s.execute(select(B).options(joinedload(B.a3)))
58+
s.execute(select(B).options(joinedload(B.a4)))
59+
s.execute(select(B).options(joinedload(B.a5)))
60+
s.execute(select(B).options(joinedload(B.a7)))
61+
s.execute(select(B).options(joinedload(B.a8)))
62+
s.execute(select(B).options(joinedload(B.a9)))

0 commit comments

Comments
 (0)