use std::fmt;
use glaredb_error::Result;
use super::Expression;
use crate::arrays::datatype::DataType;
use crate::explain::context_display::{ContextDisplay, ContextDisplayMode, ContextDisplayWrapper};
use crate::functions::aggregate::PlannedAggregateFunction;
use crate::logical::binder::bind_query::bind_modifier::BoundOrderByExpr;
use crate::util::fmt::displayable::IntoDisplayableSlice;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum WindowFrameUnit {
Rows,
Range,
Groups,
}
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
pub enum WindowFrameExclusion {
ExcludeCurrentRow,
ExcludeGroup,
ExcludeTies,
#[default]
ExcludeNoOthers,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum WindowFrameBound {
UnboundedPreceding(WindowFrameUnit),
Preceding(WindowFrameUnit, i64),
UnboundedFollowing(WindowFrameUnit),
Following(WindowFrameUnit, i64),
CurrentRow(WindowFrameUnit),
}
impl WindowFrameBound {
pub const fn default_start() -> Self {
WindowFrameBound::UnboundedPreceding(WindowFrameUnit::Range)
}
pub const fn default_end() -> Self {
WindowFrameBound::CurrentRow(WindowFrameUnit::Range)
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct WindowExpr {
pub agg: PlannedAggregateFunction,
pub partition_by: Vec<Expression>,
pub order_by: Vec<BoundOrderByExpr>,
pub start: WindowFrameBound,
pub end: WindowFrameBound,
pub exclude: WindowFrameExclusion,
}
impl WindowExpr {
pub fn datatype(&self) -> Result<DataType> {
Ok(self.agg.state.return_type.clone())
}
}
impl ContextDisplay for WindowExpr {
fn fmt_using_context(
&self,
mode: ContextDisplayMode,
f: &mut fmt::Formatter<'_>,
) -> fmt::Result {
write!(f, "{}", self.agg.name)?;
let inputs = self
.agg
.state
.inputs
.iter()
.map(|expr| ContextDisplayWrapper::with_mode(expr, mode).to_string())
.collect::<Vec<_>>()
.join(", ");
write!(f, "({}) OVER (", inputs)?;
if !self.partition_by.is_empty() {
write!(
f,
"PARTION BY {} ",
self.partition_by
.iter()
.map(|expr| ContextDisplayWrapper::with_mode(expr, mode))
.collect::<Vec<_>>()
.display_as_list()
)?;
}
if !self.order_by.is_empty() {
write!(f, "ORDER BY {} ", self.order_by.display_as_list())?;
}
write!(f, ")")?;
Ok(())
}
}