use crate::ast::{AggregateFunc, Cage, Condition, Expr, SortOrder, Value, aggregate_sort_cage};
fn column_aggregate(column: &str, func: AggregateFunc) -> AggregateBuilder {
AggregateBuilder {
col: column.to_string(),
func,
distinct: false,
filter: None,
alias: None,
args: Vec::new(),
order_by: Vec::new(),
within_group: Vec::new(),
}
}
pub fn count() -> AggregateBuilder {
column_aggregate("*", AggregateFunc::Count)
}
pub fn count_distinct(column: &str) -> AggregateBuilder {
column_aggregate(column, AggregateFunc::Count).distinct()
}
pub fn count_filter(conditions: Vec<Condition>) -> AggregateBuilder {
column_aggregate("*", AggregateFunc::Count).filter(conditions)
}
pub fn sum(column: &str) -> AggregateBuilder {
column_aggregate(column, AggregateFunc::Sum)
}
pub fn avg(column: &str) -> AggregateBuilder {
column_aggregate(column, AggregateFunc::Avg)
}
pub fn min(column: &str) -> AggregateBuilder {
column_aggregate(column, AggregateFunc::Min)
}
pub fn max(column: &str) -> AggregateBuilder {
column_aggregate(column, AggregateFunc::Max)
}
pub fn array_agg(column: &str) -> AggregateBuilder {
column_aggregate(column, AggregateFunc::ArrayAgg)
}
pub fn json_agg(column: &str) -> AggregateBuilder {
column_aggregate(column, AggregateFunc::JsonAgg)
}
pub fn jsonb_agg(column: &str) -> AggregateBuilder {
column_aggregate(column, AggregateFunc::JsonbAgg)
}
pub fn bool_and(column: &str) -> AggregateBuilder {
column_aggregate(column, AggregateFunc::BoolAnd)
}
pub fn bool_or(column: &str) -> AggregateBuilder {
column_aggregate(column, AggregateFunc::BoolOr)
}
pub fn aggregate(func: AggregateFunc, args: impl IntoIterator<Item = Expr>) -> AggregateBuilder {
AggregateBuilder {
args: args.into_iter().collect(),
..column_aggregate("", func)
}
}
pub fn percentile_cont(fraction: f64) -> AggregateBuilder {
aggregate(
AggregateFunc::PercentileCont,
[Expr::Literal(Value::Float(fraction))],
)
}
pub fn percentile_disc(fraction: f64) -> AggregateBuilder {
aggregate(
AggregateFunc::PercentileDisc,
[Expr::Literal(Value::Float(fraction))],
)
}
pub fn mode() -> AggregateBuilder {
aggregate(AggregateFunc::Mode, [])
}
#[derive(Debug, Clone)]
pub struct AggregateBuilder {
pub(crate) col: String,
pub(crate) func: AggregateFunc,
pub(crate) distinct: bool,
pub(crate) filter: Option<Vec<Condition>>,
pub(crate) alias: Option<String>,
pub(crate) args: Vec<Expr>,
pub(crate) order_by: Vec<Cage>,
pub(crate) within_group: Vec<Cage>,
}
impl AggregateBuilder {
pub fn distinct(mut self) -> Self {
self.distinct = true;
self
}
pub fn filter(mut self, conditions: Vec<Condition>) -> Self {
self.filter = Some(conditions);
self
}
pub fn order_by(mut self, key: impl Into<Expr>, order: SortOrder) -> Self {
self.order_by.push(aggregate_sort_cage(key.into(), order));
self
}
pub fn within_group(mut self, key: impl Into<Expr>, order: SortOrder) -> Self {
self.within_group
.push(aggregate_sort_cage(key.into(), order));
self
}
pub fn alias(mut self, name: &str) -> Expr {
self.alias = Some(name.to_string());
self.build()
}
pub fn build(self) -> Expr {
Expr::Aggregate {
col: self.col,
func: self.func,
distinct: self.distinct,
filter: self.filter,
alias: self.alias,
args: self.args,
order_by: self.order_by,
within_group: self.within_group,
}
}
}
impl From<AggregateBuilder> for Expr {
fn from(builder: AggregateBuilder) -> Self {
builder.build()
}
}