Coverage for sqlmodel / sql / expression.py: 70%
64 statements
« prev ^ index » next coverage.py v7.13.0, created at 2026-11-09 00:02 +0000
« prev ^ index » next coverage.py v7.13.0, created at 2026-11-09 00:02 +0000
1from collections.abc import Iterable, Mapping, Sequence 1abcdefghi
2from typing import ( 1abcdefghi
3 Any,
4 Literal,
5 Optional,
6 TypeVar,
7)
8from typing import cast as typing_cast 1abcdefghi
10import sqlalchemy 1abcdefghi
11from sqlalchemy import ( 1abcdefghi
12 Column,
13 ColumnElement,
14 Extract,
15 FunctionElement,
16 FunctionFilter,
17 Label,
18 Over,
19 TypeCoerce,
20 WithinGroup,
21)
22from sqlalchemy.orm import InstrumentedAttribute, Mapped 1abcdefghi
23from sqlalchemy.sql._typing import ( 1abcdefghi
24 _ColumnExpressionArgument,
25 _ColumnExpressionOrLiteralArgument,
26 _ColumnExpressionOrStrLabelArgument,
27)
28from sqlalchemy.sql.elements import ( 1abcdefghi
29 BinaryExpression,
30 Case,
31 Cast,
32 CollectionAggregate,
33 ColumnClause,
34 TryCast,
35 UnaryExpression,
36)
37from sqlalchemy.sql.type_api import TypeEngine 1abcdefghi
39from ._expression_select_cls import Select as Select 1abcdefghi
40from ._expression_select_cls import SelectOfScalar as SelectOfScalar 1abcdefghi
41from ._expression_select_gen import select as select 1abcdefghi
43_T = TypeVar("_T") 1abcdefghi
45_TypeEngineArgument = type[TypeEngine[_T]] | TypeEngine[_T] 1abcdefghi
47# Redefine operators that would only take a column expression to also take the (virtual)
48# types of Pydantic models, e.g. str instead of only Mapped[str].
51def all_(expr: _ColumnExpressionArgument[_T] | _T) -> CollectionAggregate[bool]: 1abcdefghi
52 return sqlalchemy.all_(expr) # ty: ignore[invalid-argument-type]
55def and_( 1abcdefghi
56 initial_clause: Literal[True] | _ColumnExpressionArgument[bool] | bool,
57 *clauses: _ColumnExpressionArgument[bool] | bool,
58) -> ColumnElement[bool]:
59 return sqlalchemy.and_(initial_clause, *clauses) # ty: ignore[invalid-argument-type]
62def any_(expr: _ColumnExpressionArgument[_T] | _T) -> CollectionAggregate[bool]: 1abcdefghi
63 return sqlalchemy.any_(expr) # ty: ignore[invalid-argument-type]
66def asc( 1abcdefghi
67 column: _ColumnExpressionOrStrLabelArgument[_T] | _T,
68) -> UnaryExpression[_T]:
69 return sqlalchemy.asc(typing_cast(ColumnElement[_T], column)) 1jklmnopqr
72def collate( 1abcdefghi
73 expression: _ColumnExpressionArgument[str] | str, collation: str
74) -> BinaryExpression[str]:
75 return sqlalchemy.collate(expression, collation) # ty: ignore[invalid-argument-type]
78def between( 1abcdefghi
79 expr: _ColumnExpressionOrLiteralArgument[_T] | _T,
80 lower_bound: Any,
81 upper_bound: Any,
82 symmetric: bool = False,
83) -> BinaryExpression[bool]:
84 return sqlalchemy.between(expr, lower_bound, upper_bound, symmetric=symmetric)
87def not_(clause: _ColumnExpressionArgument[_T] | _T) -> ColumnElement[_T]: 1abcdefghi
88 return sqlalchemy.not_(clause) # ty: ignore[no-matching-overload]
91def case( 1abcdefghi
92 *whens: tuple[_ColumnExpressionArgument[bool] | bool, Any] | Mapping[Any, Any],
93 value: Any | None = None,
94 else_: Any | None = None,
95) -> Case[Any]:
96 return sqlalchemy.case(*whens, value=value, else_=else_) # ty: ignore[invalid-argument-type]
99def cast( 1abcdefghi
100 expression: _ColumnExpressionOrLiteralArgument[Any] | Any,
101 type_: "_TypeEngineArgument[_T]",
102) -> Cast[_T]:
103 return sqlalchemy.cast(expression, type_)
106def try_cast( 1abcdefghi
107 expression: _ColumnExpressionOrLiteralArgument[Any] | Any,
108 type_: "_TypeEngineArgument[_T]",
109) -> TryCast[_T]:
110 return sqlalchemy.try_cast(expression, type_)
113def desc( 1abcdefghi
114 column: _ColumnExpressionOrStrLabelArgument[_T] | _T,
115) -> UnaryExpression[_T]:
116 return sqlalchemy.desc(typing_cast(ColumnElement[_T], column)) 1jklmnopqr
119def distinct(expr: _ColumnExpressionArgument[_T] | _T) -> UnaryExpression[_T]: 1abcdefghi
120 return sqlalchemy.distinct(expr) # ty: ignore[invalid-argument-type]
123def bitwise_not(expr: _ColumnExpressionArgument[_T] | _T) -> UnaryExpression[_T]: 1abcdefghi
124 return sqlalchemy.bitwise_not(expr) # ty: ignore[invalid-argument-type]
127def extract(field: str, expr: _ColumnExpressionArgument[Any] | Any) -> Extract: 1abcdefghi
128 return sqlalchemy.extract(field, expr)
131def funcfilter( 1abcdefghi
132 func: FunctionElement[_T], *criterion: _ColumnExpressionArgument[bool] | bool
133) -> FunctionFilter[_T]:
134 return sqlalchemy.funcfilter(func, *criterion) # ty: ignore[invalid-argument-type]
137def label( 1abcdefghi
138 name: str,
139 element: _ColumnExpressionArgument[_T] | _T,
140 type_: Optional["_TypeEngineArgument[_T]"] = None,
141) -> Label[_T]:
142 return sqlalchemy.label(name, element, type_=type_) # ty: ignore[invalid-argument-type]
145def nulls_first( 1abcdefghi
146 column: _ColumnExpressionArgument[_T] | _T,
147) -> UnaryExpression[_T]:
148 return sqlalchemy.nulls_first(typing_cast(ColumnElement[_T], column)) 1jklmnopqr
151def nulls_last(column: _ColumnExpressionArgument[_T] | _T) -> UnaryExpression[_T]: 1abcdefghi
152 return sqlalchemy.nulls_last(typing_cast(ColumnElement[_T], column)) 1jklmnopqr
155def or_( 1abcdefghi
156 initial_clause: Literal[False] | _ColumnExpressionArgument[bool] | bool,
157 *clauses: _ColumnExpressionArgument[bool] | bool,
158) -> ColumnElement[bool]:
159 return sqlalchemy.or_(initial_clause, *clauses) # ty: ignore[invalid-argument-type] 123456789!
162def over( 1abcdefghi
163 element: FunctionElement[_T],
164 partition_by: Iterable[_ColumnExpressionArgument[Any] | Any]
165 | _ColumnExpressionArgument[Any]
166 | Any
167 | None = None,
168 order_by: Iterable[_ColumnExpressionArgument[Any] | Any]
169 | _ColumnExpressionArgument[Any]
170 | Any
171 | None = None,
172 range_: tuple[int | None, int | None] | None = None,
173 rows: tuple[int | None, int | None] | None = None,
174) -> Over[_T]:
175 return sqlalchemy.over(
176 element, partition_by=partition_by, order_by=order_by, range_=range_, rows=rows
177 )
180def tuple_( 1abcdefghi
181 *clauses: _ColumnExpressionArgument[Any] | Any,
182 types: Sequence["_TypeEngineArgument[Any]"] | None = None,
183) -> sqlalchemy.Tuple:
184 return sqlalchemy.tuple_(*clauses, types=types)
187def type_coerce( 1abcdefghi
188 expression: _ColumnExpressionOrLiteralArgument[Any] | Any,
189 type_: "_TypeEngineArgument[_T]",
190) -> TypeCoerce[_T]:
191 return sqlalchemy.type_coerce(expression, type_)
194def within_group( 1abcdefghi
195 element: FunctionElement[_T], *order_by: _ColumnExpressionArgument[Any] | Any
196) -> WithinGroup[_T]:
197 return sqlalchemy.within_group(element, *order_by)
200def col(column_expression: _T) -> Mapped[_T]: 1abcdefghi
201 if not isinstance(column_expression, (ColumnClause, Column, InstrumentedAttribute)): 1stuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01
202 raise RuntimeError(f"Not a SQLAlchemy column: {column_expression}")
203 return column_expression # type: ignore 1stuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01