use super::expr::{ExprNode, IntoExpr, OrderExpr};
#[derive(Clone, Default)]
pub struct WindowSpec {
pub(super) partitions: Vec<ExprNode>,
pub(super) orders: Vec<OrderExpr>,
pub(super) frame: Option<WindowFrame>,
}
#[derive(Clone)]
pub struct WindowFrame {
pub(super) unit: FrameUnit,
pub(super) start: FrameBound,
pub(super) end: FrameBound,
}
#[derive(Clone)]
pub struct FrameBound {
pub(super) kind: FrameBoundKind,
pub(super) expr: Option<Box<ExprNode>>,
}
#[derive(Clone, Copy)]
pub(super) enum FrameUnit {
Rows,
Range,
}
#[derive(Clone, Copy)]
pub(super) enum FrameBoundKind {
UnboundedPreceding,
Preceding,
CurrentRow,
Following,
UnboundedFollowing,
}
impl WindowSpec {
pub(super) fn new() -> Self {
Self::default()
}
pub fn partition_by<T>(mut self, expr: impl IntoExpr<T>) -> Self {
self.partitions.push(expr.into_expr().node);
self
}
pub fn order_by(mut self, order: OrderExpr) -> Self {
self.orders.push(order);
self
}
pub fn rows_between(mut self, start: FrameBound, end: FrameBound) -> Self {
self.frame = Some(rows_between(start, end));
self
}
pub fn range_between(mut self, start: FrameBound, end: FrameBound) -> Self {
self.frame = Some(range_between(start, end));
self
}
pub fn frame(mut self, frame: WindowFrame) -> Self {
self.frame = Some(frame);
self
}
}
pub fn window() -> WindowSpec {
WindowSpec::new()
}
pub fn rows_between(start: FrameBound, end: FrameBound) -> WindowFrame {
WindowFrame {
unit: FrameUnit::Rows,
start,
end,
}
}
pub fn range_between(start: FrameBound, end: FrameBound) -> WindowFrame {
WindowFrame {
unit: FrameUnit::Range,
start,
end,
}
}
pub fn unbounded_preceding() -> FrameBound {
FrameBound::plain(FrameBoundKind::UnboundedPreceding)
}
pub fn preceding(offset: impl IntoExpr<i64>) -> FrameBound {
FrameBound::with_expr(FrameBoundKind::Preceding, offset.into_expr().node)
}
pub fn current_row() -> FrameBound {
FrameBound::plain(FrameBoundKind::CurrentRow)
}
pub fn following(offset: impl IntoExpr<i64>) -> FrameBound {
FrameBound::with_expr(FrameBoundKind::Following, offset.into_expr().node)
}
pub fn unbounded_following() -> FrameBound {
FrameBound::plain(FrameBoundKind::UnboundedFollowing)
}
impl FrameBound {
fn plain(kind: FrameBoundKind) -> Self {
Self { kind, expr: None }
}
fn with_expr(kind: FrameBoundKind, expr: ExprNode) -> Self {
Self {
kind,
expr: Some(Box::new(expr)),
}
}
}