use std::marker::PhantomData;
use crate::expr::{BigInt, ExprKind, IntoExpr, Keyed, SortDir};
use crate::scope::{Concat, Nil};
use crate::select::OrderKey;
pub struct Window<Req> {
partition_by: Vec<ExprKind>,
order_by: Vec<(ExprKind, SortDir)>,
_marker: PhantomData<fn() -> Req>,
}
pub fn window() -> Window<Nil> {
Window {
partition_by: Vec::new(),
order_by: Vec::new(),
_marker: PhantomData,
}
}
impl<Req> Window<Req> {
pub fn partition_by<Req2>(
self,
key: impl IntoExpr<Req = Req2>,
) -> Window<<Req as Concat<Req2>>::Output>
where
Req: Concat<Req2>,
{
let mut partition_by = self.partition_by;
partition_by.push(key.into_expr().kind);
Window {
partition_by,
order_by: self.order_by,
_marker: PhantomData,
}
}
pub fn order_by<Req2>(self, key: OrderKey<Req2>) -> Window<<Req as Concat<Req2>>::Output>
where
Req: Concat<Req2>,
{
let mut order_by = self.order_by;
order_by.push(key.into_parts());
Window {
partition_by: self.partition_by,
order_by,
_marker: PhantomData,
}
}
}
pub struct WindowFunc<K> {
sql: &'static str,
_marker: PhantomData<fn() -> K>,
}
impl<K> crate::row::RowKey for WindowFunc<K> {
type Key = K;
}
impl<K: crate::row::Spelled> crate::row::LookupKey for WindowFunc<K> {}
impl<K> WindowFunc<K> {
pub fn over<WindowReq>(self, window: Window<WindowReq>) -> Keyed<K, WindowReq, BigInt> {
Keyed::from_kind(ExprKind::Window {
func: self.sql,
partition_by: window.partition_by,
order_by: window.order_by,
})
}
}
fn window_func<K>(sql: &'static str) -> WindowFunc<K> {
WindowFunc {
sql,
_marker: PhantomData,
}
}
crate::row::expr_key!(
RowNumber,
HasRowNumber,
row_number,
"The identity a selected `row_number() OVER (..)` is filed under in a row.",
'r',
'o',
'w',
'_',
'n',
'u',
'm',
'b',
'e',
'r'
);
crate::row::expr_key!(
Rank,
HasRank,
rank,
"The identity a selected `rank() OVER (..)` is filed under in a row.",
'r',
'a',
'n',
'k'
);
crate::row::expr_key!(
DenseRank,
HasDenseRank,
dense_rank,
"The identity a selected `dense_rank() OVER (..)` is filed under in a row.",
'd',
'e',
'n',
's',
'e',
'_',
'r',
'a',
'n',
'k'
);
pub fn row_number() -> WindowFunc<RowNumber> {
window_func("row_number()")
}
pub fn rank() -> WindowFunc<Rank> {
window_func("rank()")
}
pub fn dense_rank() -> WindowFunc<DenseRank> {
window_func("dense_rank()")
}