expression.py 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. from typing import (
  2. Any,
  3. Iterable,
  4. Mapping,
  5. Optional,
  6. Sequence,
  7. Tuple,
  8. Type,
  9. TypeVar,
  10. Union,
  11. )
  12. import sqlalchemy
  13. from sqlalchemy import (
  14. Column,
  15. ColumnElement,
  16. Extract,
  17. FunctionElement,
  18. FunctionFilter,
  19. Label,
  20. Over,
  21. TypeCoerce,
  22. WithinGroup,
  23. )
  24. from sqlalchemy.orm import InstrumentedAttribute, Mapped
  25. from sqlalchemy.sql._typing import (
  26. _ColumnExpressionArgument,
  27. _ColumnExpressionOrLiteralArgument,
  28. _ColumnExpressionOrStrLabelArgument,
  29. )
  30. from sqlalchemy.sql.elements import (
  31. BinaryExpression,
  32. Case,
  33. Cast,
  34. CollectionAggregate,
  35. ColumnClause,
  36. TryCast,
  37. UnaryExpression,
  38. )
  39. from sqlalchemy.sql.type_api import TypeEngine
  40. from typing_extensions import Literal
  41. from ._expression_select_cls import Select as Select
  42. from ._expression_select_cls import SelectOfScalar as SelectOfScalar
  43. from ._expression_select_gen import select as select
  44. _T = TypeVar("_T")
  45. _TypeEngineArgument = Union[Type[TypeEngine[_T]], TypeEngine[_T]]
  46. # Redefine operatos that would only take a column expresion to also take the (virtual)
  47. # types of Pydantic models, e.g. str instead of only Mapped[str].
  48. def all_(expr: Union[_ColumnExpressionArgument[_T], _T]) -> CollectionAggregate[bool]:
  49. return sqlalchemy.all_(expr) # type: ignore[arg-type]
  50. def and_(
  51. initial_clause: Union[Literal[True], _ColumnExpressionArgument[bool], bool],
  52. *clauses: Union[_ColumnExpressionArgument[bool], bool],
  53. ) -> ColumnElement[bool]:
  54. return sqlalchemy.and_(initial_clause, *clauses) # type: ignore[arg-type]
  55. def any_(expr: Union[_ColumnExpressionArgument[_T], _T]) -> CollectionAggregate[bool]:
  56. return sqlalchemy.any_(expr) # type: ignore[arg-type]
  57. def asc(
  58. column: Union[_ColumnExpressionOrStrLabelArgument[_T], _T],
  59. ) -> UnaryExpression[_T]:
  60. return sqlalchemy.asc(column) # type: ignore[arg-type]
  61. def collate(
  62. expression: Union[_ColumnExpressionArgument[str], str], collation: str
  63. ) -> BinaryExpression[str]:
  64. return sqlalchemy.collate(expression, collation) # type: ignore[arg-type]
  65. def between(
  66. expr: Union[_ColumnExpressionOrLiteralArgument[_T], _T],
  67. lower_bound: Any,
  68. upper_bound: Any,
  69. symmetric: bool = False,
  70. ) -> BinaryExpression[bool]:
  71. return sqlalchemy.between(expr, lower_bound, upper_bound, symmetric=symmetric)
  72. def not_(clause: Union[_ColumnExpressionArgument[_T], _T]) -> ColumnElement[_T]:
  73. return sqlalchemy.not_(clause) # type: ignore[arg-type]
  74. def case(
  75. *whens: Union[
  76. Tuple[Union[_ColumnExpressionArgument[bool], bool], Any], Mapping[Any, Any]
  77. ],
  78. value: Optional[Any] = None,
  79. else_: Optional[Any] = None,
  80. ) -> Case[Any]:
  81. return sqlalchemy.case(*whens, value=value, else_=else_) # type: ignore[arg-type]
  82. def cast(
  83. expression: Union[_ColumnExpressionOrLiteralArgument[Any], Any],
  84. type_: "_TypeEngineArgument[_T]",
  85. ) -> Cast[_T]:
  86. return sqlalchemy.cast(expression, type_)
  87. def try_cast(
  88. expression: Union[_ColumnExpressionOrLiteralArgument[Any], Any],
  89. type_: "_TypeEngineArgument[_T]",
  90. ) -> TryCast[_T]:
  91. return sqlalchemy.try_cast(expression, type_)
  92. def desc(
  93. column: Union[_ColumnExpressionOrStrLabelArgument[_T], _T],
  94. ) -> UnaryExpression[_T]:
  95. return sqlalchemy.desc(column) # type: ignore[arg-type]
  96. def distinct(expr: Union[_ColumnExpressionArgument[_T], _T]) -> UnaryExpression[_T]:
  97. return sqlalchemy.distinct(expr) # type: ignore[arg-type]
  98. def bitwise_not(expr: Union[_ColumnExpressionArgument[_T], _T]) -> UnaryExpression[_T]:
  99. return sqlalchemy.bitwise_not(expr) # type: ignore[arg-type]
  100. def extract(field: str, expr: Union[_ColumnExpressionArgument[Any], Any]) -> Extract:
  101. return sqlalchemy.extract(field, expr)
  102. def funcfilter(
  103. func: FunctionElement[_T], *criterion: Union[_ColumnExpressionArgument[bool], bool]
  104. ) -> FunctionFilter[_T]:
  105. return sqlalchemy.funcfilter(func, *criterion) # type: ignore[arg-type]
  106. def label(
  107. name: str,
  108. element: Union[_ColumnExpressionArgument[_T], _T],
  109. type_: Optional["_TypeEngineArgument[_T]"] = None,
  110. ) -> Label[_T]:
  111. return sqlalchemy.label(name, element, type_=type_) # type: ignore[arg-type]
  112. def nulls_first(
  113. column: Union[_ColumnExpressionArgument[_T], _T],
  114. ) -> UnaryExpression[_T]:
  115. return sqlalchemy.nulls_first(column) # type: ignore[arg-type]
  116. def nulls_last(column: Union[_ColumnExpressionArgument[_T], _T]) -> UnaryExpression[_T]:
  117. return sqlalchemy.nulls_last(column) # type: ignore[arg-type]
  118. def or_(
  119. initial_clause: Union[Literal[False], _ColumnExpressionArgument[bool], bool],
  120. *clauses: Union[_ColumnExpressionArgument[bool], bool],
  121. ) -> ColumnElement[bool]:
  122. return sqlalchemy.or_(initial_clause, *clauses) # type: ignore[arg-type]
  123. def over(
  124. element: FunctionElement[_T],
  125. partition_by: Optional[
  126. Union[
  127. Iterable[Union[_ColumnExpressionArgument[Any], Any]],
  128. _ColumnExpressionArgument[Any],
  129. Any,
  130. ]
  131. ] = None,
  132. order_by: Optional[
  133. Union[
  134. Iterable[Union[_ColumnExpressionArgument[Any], Any]],
  135. _ColumnExpressionArgument[Any],
  136. Any,
  137. ]
  138. ] = None,
  139. range_: Optional[Tuple[Optional[int], Optional[int]]] = None,
  140. rows: Optional[Tuple[Optional[int], Optional[int]]] = None,
  141. ) -> Over[_T]:
  142. return sqlalchemy.over(
  143. element, partition_by=partition_by, order_by=order_by, range_=range_, rows=rows
  144. )
  145. def tuple_(
  146. *clauses: Union[_ColumnExpressionArgument[Any], Any],
  147. types: Optional[Sequence["_TypeEngineArgument[Any]"]] = None,
  148. ) -> Tuple[Any, ...]:
  149. return sqlalchemy.tuple_(*clauses, types=types) # type: ignore[return-value]
  150. def type_coerce(
  151. expression: Union[_ColumnExpressionOrLiteralArgument[Any], Any],
  152. type_: "_TypeEngineArgument[_T]",
  153. ) -> TypeCoerce[_T]:
  154. return sqlalchemy.type_coerce(expression, type_)
  155. def within_group(
  156. element: FunctionElement[_T], *order_by: Union[_ColumnExpressionArgument[Any], Any]
  157. ) -> WithinGroup[_T]:
  158. return sqlalchemy.within_group(element, *order_by)
  159. def col(column_expression: _T) -> Mapped[_T]:
  160. if not isinstance(column_expression, (ColumnClause, Column, InstrumentedAttribute)):
  161. raise RuntimeError(f"Not a SQLAlchemy column: {column_expression}")
  162. return column_expression # type: ignore