use crate::db::query::plan::AggregateKind;
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct AggregateExpr {
kind: AggregateKind,
target_field: Option<String>,
distinct: bool,
}
impl AggregateExpr {
const fn new(kind: AggregateKind, target_field: Option<String>) -> Self {
Self {
kind,
target_field,
distinct: false,
}
}
#[must_use]
pub const fn distinct(mut self) -> Self {
self.distinct = true;
self
}
#[must_use]
pub(crate) const fn kind(&self) -> AggregateKind {
self.kind
}
#[must_use]
pub(crate) fn target_field(&self) -> Option<&str> {
self.target_field.as_deref()
}
#[must_use]
pub(crate) const fn is_distinct(&self) -> bool {
self.distinct
}
pub(in crate::db::query) const fn from_semantic_parts(
kind: AggregateKind,
target_field: Option<String>,
distinct: bool,
) -> Self {
Self {
kind,
target_field,
distinct,
}
}
#[must_use]
pub(in crate::db) fn terminal_for_kind(kind: AggregateKind) -> Self {
match kind {
AggregateKind::Count => count(),
AggregateKind::Exists => exists(),
AggregateKind::Min => min(),
AggregateKind::Max => max(),
AggregateKind::First => first(),
AggregateKind::Last => last(),
AggregateKind::Sum | AggregateKind::Avg => unreachable!(
"AggregateExpr::terminal_for_kind does not support SUM/AVG field-target kinds"
),
}
}
#[must_use]
pub(in crate::db) fn field_target_extrema_for_kind(
kind: AggregateKind,
field: impl AsRef<str>,
) -> Self {
match kind {
AggregateKind::Min => min_by(field),
AggregateKind::Max => max_by(field),
_ => unreachable!("AggregateExpr::field_target_extrema_for_kind requires MIN/MAX kind"),
}
}
}
#[must_use]
pub const fn count() -> AggregateExpr {
AggregateExpr::new(AggregateKind::Count, None)
}
#[must_use]
pub fn count_by(field: impl AsRef<str>) -> AggregateExpr {
AggregateExpr::new(AggregateKind::Count, Some(field.as_ref().to_string()))
}
#[must_use]
pub fn sum(field: impl AsRef<str>) -> AggregateExpr {
AggregateExpr::new(AggregateKind::Sum, Some(field.as_ref().to_string()))
}
#[must_use]
pub fn avg(field: impl AsRef<str>) -> AggregateExpr {
AggregateExpr::new(AggregateKind::Avg, Some(field.as_ref().to_string()))
}
#[must_use]
pub const fn exists() -> AggregateExpr {
AggregateExpr::new(AggregateKind::Exists, None)
}
#[must_use]
pub const fn first() -> AggregateExpr {
AggregateExpr::new(AggregateKind::First, None)
}
#[must_use]
pub const fn last() -> AggregateExpr {
AggregateExpr::new(AggregateKind::Last, None)
}
#[must_use]
pub const fn min() -> AggregateExpr {
AggregateExpr::new(AggregateKind::Min, None)
}
#[must_use]
pub fn min_by(field: impl AsRef<str>) -> AggregateExpr {
AggregateExpr::new(AggregateKind::Min, Some(field.as_ref().to_string()))
}
#[must_use]
pub const fn max() -> AggregateExpr {
AggregateExpr::new(AggregateKind::Max, None)
}
#[must_use]
pub fn max_by(field: impl AsRef<str>) -> AggregateExpr {
AggregateExpr::new(AggregateKind::Max, Some(field.as_ref().to_string()))
}