use std::fmt::{Debug, Display};
use vantage_expressions::{Expression, Expressive, ExpressiveEnum};
#[derive(Debug, Clone)]
pub struct Window<T: Debug + Display + Clone> {
partition_by: Vec<Expression<T>>,
order_by: Vec<(Expression<T>, vantage_expressions::Order)>,
frame: Option<String>,
named_ref: Option<String>,
}
impl<T: Debug + Display + Clone> Default for Window<T> {
fn default() -> Self {
Self::new()
}
}
impl<T: Debug + Display + Clone> Window<T> {
pub fn new() -> Self {
Self {
partition_by: Vec::new(),
order_by: Vec::new(),
frame: None,
named_ref: None,
}
}
pub fn named(name: impl Into<String>) -> Self {
Self {
partition_by: Vec::new(),
order_by: Vec::new(),
frame: None,
named_ref: Some(name.into()),
}
}
pub fn partition_by(mut self, expr: impl Expressive<T>) -> Self {
self.partition_by.push(expr.expr());
self
}
pub fn order_by(mut self, expr: impl Expressive<T>, order: vantage_expressions::Order) -> Self {
self.order_by.push((expr.expr(), order));
self
}
pub fn rows(mut self, from: &str, to: &str) -> Self {
self.frame = Some(format!("ROWS BETWEEN {} AND {}", from, to));
self
}
pub fn range(mut self, from: &str, to: &str) -> Self {
self.frame = Some(format!("RANGE BETWEEN {} AND {}", from, to));
self
}
pub fn apply(&self, func: impl Expressive<T>) -> Expression<T> {
Expression::new(
"{} OVER {}",
vec![
ExpressiveEnum::Nested(func.expr()),
ExpressiveEnum::Nested(self.spec_expr()),
],
)
}
fn spec_expr(&self) -> Expression<T> {
if let Some(name) = &self.named_ref {
return Expression::new(name.clone(), vec![]);
}
let mut parts: Vec<Expression<T>> = Vec::new();
if !self.partition_by.is_empty() {
parts.push(Expression::new(
"PARTITION BY {}",
vec![ExpressiveEnum::Nested(Expression::from_vec(
self.partition_by.clone(),
", ",
))],
));
}
if !self.order_by.is_empty() {
let order_parts: Vec<Expression<T>> = self
.order_by
.iter()
.map(|(expr, order)| {
Expression::new(
format!("{{}}{}", order.suffix()),
vec![ExpressiveEnum::Nested(expr.clone())],
)
})
.collect();
parts.push(Expression::new(
"ORDER BY {}",
vec![ExpressiveEnum::Nested(Expression::from_vec(
order_parts,
", ",
))],
));
}
if let Some(frame) = &self.frame {
parts.push(Expression::new(frame.clone(), vec![]));
}
let inner = Expression::from_vec(parts, " ");
Expression::new("({})", vec![ExpressiveEnum::Nested(inner)])
}
pub fn definition(&self) -> Expression<T> {
self.spec_expr()
}
}