--- /dev/null
+.. change::
+ :tags: bug, sql
+ :tickets: 11423
+
+ Added missing methods :meth:`_sql.FunctionFilter.within_group`
+ and :meth:`_sql.WithinGroup.filter`
def __init__(
self,
- element: FunctionElement[_T],
+ element: Union[FunctionElement[_T], FunctionFilter[_T]],
*order_by: _ColumnExpressionArgument[Any],
):
self.element = element
tuple(self.order_by) if self.order_by is not None else ()
)
- def over(self, partition_by=None, order_by=None, range_=None, rows=None):
+ def over(
+ self,
+ *,
+ partition_by: Optional[_ByArgument] = None,
+ order_by: Optional[_ByArgument] = None,
+ rows: Optional[typing_Tuple[Optional[int], Optional[int]]] = None,
+ range_: Optional[typing_Tuple[Optional[int], Optional[int]]] = None,
+ ) -> Over[_T]:
"""Produce an OVER clause against this :class:`.WithinGroup`
construct.
rows=rows,
)
+ @overload
+ def filter(self) -> Self: ...
+
+ @overload
+ def filter(
+ self,
+ __criterion0: _ColumnExpressionArgument[bool],
+ *criterion: _ColumnExpressionArgument[bool],
+ ) -> FunctionFilter[_T]: ...
+
+ def filter(
+ self, *criterion: _ColumnExpressionArgument[bool]
+ ) -> Union[Self, FunctionFilter[_T]]:
+ """Produce a FILTER clause against this function."""
+ if not criterion:
+ return self
+ return FunctionFilter(self, *criterion)
+
if not TYPE_CHECKING:
@util.memoized_property
def __init__(
self,
- func: FunctionElement[_T],
+ func: Union[FunctionElement[_T], WithinGroup[_T]],
*criterion: _ColumnExpressionArgument[bool],
):
self.func = func
rows=rows,
)
+ def within_group(
+ self, *order_by: _ColumnExpressionArgument[Any]
+ ) -> WithinGroup[_T]:
+ """Produce a WITHIN GROUP (ORDER BY expr) clause against
+ this function.
+ """
+ return WithinGroup(self, *order_by)
+
+ def within_group_type(
+ self, within_group: WithinGroup[_T]
+ ) -> Optional[TypeEngine[_T]]:
+ return None
+
def self_group(
self, against: Optional[OperatorType] = None
) -> Union[Self, Grouping[_T]]:
)
def test_funcfilter_within_group(self):
+ self.assert_compile(
+ select(
+ func.rank()
+ .filter(table1.c.name > "foo")
+ .within_group(table1.c.name)
+ ),
+ "SELECT rank() FILTER (WHERE mytable.name > :name_1) "
+ "WITHIN GROUP (ORDER BY mytable.name) "
+ "AS anon_1 FROM mytable",
+ )
+
+ def test_within_group(self):
stmt = select(
table1.c.myid,
func.percentile_cont(0.5).within_group(table1.c.name),
{"percentile_cont_1": 0.5},
)
- def test_funcfilter_within_group_multi(self):
+ def test_within_group_multi(self):
stmt = select(
table1.c.myid,
func.percentile_cont(0.5).within_group(
{"percentile_cont_1": 0.5},
)
- def test_funcfilter_within_group_desc(self):
+ def test_within_group_desc(self):
stmt = select(
table1.c.myid,
func.percentile_cont(0.5).within_group(table1.c.name.desc()),
{"percentile_cont_1": 0.5},
)
- def test_funcfilter_within_group_w_over(self):
+ def test_within_group_w_over(self):
stmt = select(
table1.c.myid,
func.percentile_cont(0.5)
{"percentile_cont_1": 0.5},
)
+ def test_within_group_filter(self):
+ stmt = select(
+ table1.c.myid,
+ func.percentile_cont(0.5)
+ .within_group(table1.c.name)
+ .filter(table1.c.myid > 42),
+ )
+ self.assert_compile(
+ stmt,
+ "SELECT mytable.myid, percentile_cont(:percentile_cont_1) "
+ "WITHIN GROUP (ORDER BY mytable.name) "
+ "FILTER (WHERE mytable.myid > :myid_1) "
+ "AS anon_1 "
+ "FROM mytable",
+ {"percentile_cont_1": 0.5, "myid_1": 42},
+ )
+
def test_incorrect_none_type(self):
from sqlalchemy.sql.expression import FunctionElement
c: Mapped[str]
-func.row_number().over(order_by=Foo.a, partition_by=Foo.b.desc())
+# EXPECTED_TYPE: Over[Any]
+reveal_type(func.row_number().over(order_by=Foo.a, partition_by=Foo.b.desc()))
func.row_number().over(order_by=[Foo.a.desc(), Foo.b.desc()])
func.row_number().over(partition_by=[Foo.a.desc(), Foo.b.desc()])
func.row_number().over(order_by="a", partition_by=("a", "b"))
reveal_type(func.row_number().filter())
# EXPECTED_TYPE: FunctionFilter[Any]
reveal_type(func.row_number().filter(Foo.a > 0))
-
+# EXPECTED_TYPE: FunctionFilter[Any]
+reveal_type(func.row_number().within_group(Foo.a).filter(Foo.b < 0))
+# EXPECTED_TYPE: WithinGroup[Any]
+reveal_type(func.row_number().within_group(Foo.a))
+# EXPECTED_TYPE: WithinGroup[Any]
+reveal_type(func.row_number().filter(Foo.a > 0).within_group(Foo.a))
+# EXPECTED_TYPE: Over[Any]
+reveal_type(func.row_number().filter(Foo.a > 0).over())
+# EXPECTED_TYPE: Over[Any]
+reveal_type(func.row_number().within_group(Foo.a).over())
# test #10801
# EXPECTED_TYPE: max[int]
reveal_type(func.max(Foo.b))
-stmt1 = select(
- Foo.a,
- func.min(Foo.b),
-).group_by(Foo.a)
+stmt1 = select(Foo.a, func.min(Foo.b)).group_by(Foo.a)
# EXPECTED_TYPE: Select[int, int]
reveal_type(stmt1)
reveal_type(func.coalesce(Foo.c, "a", "b"))
-stmt2 = select(
- Foo.a,
- func.coalesce(Foo.c, "a", "b"),
-).group_by(Foo.a)
+stmt2 = select(Foo.a, func.coalesce(Foo.c, "a", "b")).group_by(Foo.a)
# EXPECTED_TYPE: Select[int, str]
reveal_type(stmt2)