use crate::db::{
query::plan::{
AggregateIdentity, AggregateKind, AggregateSemanticKey, FieldSlot,
expr::{Expr, FieldId},
},
sql::lowering::aggregate::terminal::{AggregateInput, SqlGlobalAggregateTerminal},
};
pub(in crate::db::sql::lowering::aggregate) fn aggregate_input_from_semantics(
semantic_identity: AggregateIdentity,
) -> AggregateInput {
match semantic_identity.into_input_expr() {
None => AggregateInput::Rows,
Some(Expr::Field(field)) => AggregateInput::Field(field.as_str().to_string()),
Some(input_expr) => AggregateInput::Expr(input_expr),
}
}
fn semantic_identity_from_terminal(terminal: &SqlGlobalAggregateTerminal) -> AggregateIdentity {
let input_expr = match terminal.input.clone() {
AggregateInput::Rows => None,
AggregateInput::Field(field) => Some(Expr::Field(FieldId::new(field))),
AggregateInput::Expr(input_expr) => Some(input_expr),
};
AggregateIdentity::from_parts(terminal.kind, input_expr, terminal.distinct)
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub(in crate::db::sql::lowering::aggregate) struct AggregateTerminalSemantics {
semantic_key: AggregateSemanticKey,
}
impl AggregateTerminalSemantics {
#[must_use]
pub(in crate::db::sql::lowering::aggregate) fn from_terminal(
terminal: &SqlGlobalAggregateTerminal,
) -> Self {
Self {
semantic_key: AggregateSemanticKey::from_identity(
semantic_identity_from_terminal(terminal),
terminal.filter_expr.clone(),
),
}
}
#[must_use]
pub(in crate::db::sql::lowering::aggregate) fn from_owned_terminal(
terminal: SqlGlobalAggregateTerminal,
) -> Self {
Self {
semantic_key: AggregateSemanticKey::from_identity(
semantic_identity_from_terminal(&terminal),
terminal.filter_expr,
),
}
}
pub(in crate::db::sql::lowering::aggregate) fn into_parts(
self,
) -> (AggregateIdentity, Option<Expr>) {
self.semantic_key.into_parts()
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub(in crate::db::sql::lowering::aggregate) enum PreparedAggregateTarget {
Rows,
Field(FieldSlot),
Expr(Expr),
}
impl PreparedAggregateTarget {
pub(in crate::db::sql::lowering::aggregate) const fn field_slot(&self) -> Option<&FieldSlot> {
match self {
Self::Field(field_slot) => Some(field_slot),
Self::Rows | Self::Expr(_) => None,
}
}
#[cfg(test)]
pub(in crate::db::sql::lowering::aggregate) const fn input_expr(&self) -> Option<&Expr> {
match self {
Self::Expr(input_expr) => Some(input_expr),
Self::Rows | Self::Field(_) => None,
}
}
pub(in crate::db::sql::lowering::aggregate) fn into_executor_parts(
self,
) -> (Option<FieldSlot>, Option<Expr>) {
match self {
Self::Rows => (None, None),
Self::Field(target_slot) => (Some(target_slot), None),
Self::Expr(input_expr) => (None, Some(input_expr)),
}
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub(in crate::db::sql::lowering::aggregate) enum PreparedAggregateSemantics {
Count {
target: PreparedAggregateTarget,
distinct: bool,
},
Sum {
target: PreparedAggregateTarget,
distinct: bool,
},
Avg {
target: PreparedAggregateTarget,
distinct: bool,
},
Min {
target: PreparedAggregateTarget,
},
Max {
target: PreparedAggregateTarget,
},
}
impl PreparedAggregateSemantics {
pub(in crate::db::sql::lowering::aggregate) fn from_parts(
kind: AggregateKind,
target: PreparedAggregateTarget,
distinct: bool,
) -> Self {
match kind {
AggregateKind::Count => Self::Count { target, distinct },
AggregateKind::Sum => Self::Sum { target, distinct },
AggregateKind::Avg => Self::Avg { target, distinct },
AggregateKind::Min => Self::Min { target },
AggregateKind::Max => Self::Max { target },
AggregateKind::Exists | AggregateKind::First | AggregateKind::Last => {
unreachable!("unsupported SQL aggregate kind reached prepared aggregate semantics")
}
}
}
pub(in crate::db::sql::lowering::aggregate) const fn aggregate_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,
}
}
pub(in crate::db::sql::lowering::aggregate) const fn distinct_input(&self) -> bool {
match self {
Self::Count { distinct, .. }
| Self::Sum { distinct, .. }
| Self::Avg { distinct, .. } => *distinct,
Self::Min { .. } | Self::Max { .. } => false,
}
}
const fn target(&self) -> &PreparedAggregateTarget {
match self {
Self::Count { target, .. }
| Self::Sum { target, .. }
| Self::Avg { target, .. }
| Self::Min { target }
| Self::Max { target } => target,
}
}
pub(in crate::db::sql::lowering::aggregate) const fn target_slot(&self) -> Option<&FieldSlot> {
self.target().field_slot()
}
#[cfg(test)]
pub(in crate::db::sql::lowering::aggregate) const fn input_expr(&self) -> Option<&Expr> {
self.target().input_expr()
}
pub(in crate::db::sql::lowering::aggregate) fn into_executor_parts(
self,
) -> (Option<FieldSlot>, Option<Expr>) {
match self {
Self::Count { target, .. }
| Self::Sum { target, .. }
| Self::Avg { target, .. }
| Self::Min { target }
| Self::Max { target } => target.into_executor_parts(),
}
}
}