use crate::db::query::{
builder::AggregateExpr,
plan::{AggregateKind, expr::Expr},
};
#[derive(Clone, Debug, Eq, PartialEq)]
pub(in crate::db) enum AggregateIdentity {
Count {
input_expr: Option<Expr>,
distinct: bool,
},
Sum {
input_expr: Option<Expr>,
distinct: bool,
},
Avg {
input_expr: Option<Expr>,
distinct: bool,
},
Min {
input_expr: Option<Expr>,
},
Max {
input_expr: Option<Expr>,
},
Exists {
input_expr: Option<Expr>,
distinct: bool,
},
First {
input_expr: Option<Expr>,
distinct: bool,
},
Last {
input_expr: Option<Expr>,
distinct: bool,
},
}
impl AggregateIdentity {
#[must_use]
pub(in crate::db) const fn from_parts(
kind: AggregateKind,
input_expr: Option<Expr>,
distinct: bool,
) -> Self {
match kind {
AggregateKind::Count => Self::Count {
input_expr,
distinct,
},
AggregateKind::Sum => Self::Sum {
input_expr,
distinct,
},
AggregateKind::Avg => Self::Avg {
input_expr,
distinct,
},
AggregateKind::Min => Self::Min { input_expr },
AggregateKind::Max => Self::Max { input_expr },
AggregateKind::Exists => Self::Exists {
input_expr,
distinct,
},
AggregateKind::First => Self::First {
input_expr,
distinct,
},
AggregateKind::Last => Self::Last {
input_expr,
distinct,
},
}
}
#[must_use]
pub(in crate::db) fn from_aggregate_expr(aggregate: &AggregateExpr) -> Self {
Self::from_parts(
aggregate.kind(),
aggregate.input_expr().cloned(),
aggregate.is_distinct(),
)
}
#[must_use]
pub(in crate::db) const fn normalize_distinct_for_kind(
kind: AggregateKind,
distinct: bool,
) -> bool {
match kind {
AggregateKind::Min | AggregateKind::Max => false,
AggregateKind::Count
| AggregateKind::Sum
| AggregateKind::Avg
| AggregateKind::Exists
| AggregateKind::First
| AggregateKind::Last => distinct,
}
}
#[must_use]
pub(in crate::db) const fn kind(&self) -> AggregateKind {
match self {
Self::Count { .. } => AggregateKind::Count,
Self::Sum { .. } => AggregateKind::Sum,
Self::Avg { .. } => AggregateKind::Avg,
Self::Min { .. } => AggregateKind::Min,
Self::Max { .. } => AggregateKind::Max,
Self::Exists { .. } => AggregateKind::Exists,
Self::First { .. } => AggregateKind::First,
Self::Last { .. } => AggregateKind::Last,
}
}
#[must_use]
pub(in crate::db) const fn input_expr(&self) -> Option<&Expr> {
match self {
Self::Count { input_expr, .. }
| Self::Sum { input_expr, .. }
| Self::Avg { input_expr, .. }
| Self::Min { input_expr }
| Self::Max { input_expr }
| Self::Exists { input_expr, .. }
| Self::First { input_expr, .. }
| Self::Last { input_expr, .. } => input_expr.as_ref(),
}
}
#[must_use]
pub(in crate::db) fn into_input_expr(self) -> Option<Expr> {
match self {
Self::Count { input_expr, .. }
| Self::Sum { input_expr, .. }
| Self::Avg { input_expr, .. }
| Self::Min { input_expr }
| Self::Max { input_expr }
| Self::Exists { input_expr, .. }
| Self::First { input_expr, .. }
| Self::Last { input_expr, .. } => input_expr,
}
}
#[must_use]
pub(in crate::db) const fn distinct(&self) -> bool {
match self {
Self::Count { distinct, .. }
| Self::Sum { distinct, .. }
| Self::Avg { distinct, .. }
| Self::Exists { distinct, .. }
| Self::First { distinct, .. }
| Self::Last { distinct, .. } => *distinct,
Self::Min { .. } | Self::Max { .. } => false,
}
}
#[must_use]
pub(in crate::db) const fn target_field(&self) -> Option<&str> {
let Some(Expr::Field(field)) = self.input_expr() else {
return None;
};
Some(field.as_str())
}
#[must_use]
pub(in crate::db) const fn is_count_rows_only(&self) -> bool {
matches!(
self,
Self::Count {
input_expr: None,
distinct: false
}
)
}
#[must_use]
pub(in crate::db) const fn uses_grouped_distinct_value_dedup(&self) -> bool {
matches!(
self,
Self::Count { distinct: true, .. }
| Self::Sum { distinct: true, .. }
| Self::Avg { distinct: true, .. }
)
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub(in crate::db) struct AggregateSemanticKey {
identity: AggregateIdentity,
filter_expr: Option<Expr>,
}
impl AggregateSemanticKey {
#[must_use]
pub(in crate::db) fn from_aggregate_expr(aggregate: &AggregateExpr) -> Self {
Self {
identity: AggregateIdentity::from_aggregate_expr(aggregate),
filter_expr: aggregate.filter_expr().cloned(),
}
}
#[must_use]
pub(in crate::db) const fn from_identity(
identity: AggregateIdentity,
filter_expr: Option<Expr>,
) -> Self {
Self {
identity,
filter_expr,
}
}
#[must_use]
pub(in crate::db) fn into_parts(self) -> (AggregateIdentity, Option<Expr>) {
(self.identity, self.filter_expr)
}
}