use crate::{error::InternalError, value::StorageKey};
pub(in crate::db::executor) use crate::db::query::plan::AggregateKind;
pub(in crate::db::executor) enum ScalarAggregateOutput {
Count(u32),
Exists(bool),
Min(Option<StorageKey>),
Max(Option<StorageKey>),
First(Option<StorageKey>),
Last(Option<StorageKey>),
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub(in crate::db::executor) enum ScalarTerminalKind {
Count,
Exists,
Min,
Max,
First,
Last,
}
impl ScalarAggregateOutput {
fn output_kind_mismatch(mismatch_context: &'static str) -> InternalError {
InternalError::query_executor_invariant(mismatch_context)
}
pub(in crate::db::executor) fn into_count(
self,
mismatch_context: &'static str,
) -> Result<u32, InternalError> {
match self {
Self::Count(value) => Ok(value),
_ => Err(Self::output_kind_mismatch(mismatch_context)),
}
}
pub(in crate::db::executor) fn into_exists(
self,
mismatch_context: &'static str,
) -> Result<bool, InternalError> {
match self {
Self::Exists(value) => Ok(value),
_ => Err(Self::output_kind_mismatch(mismatch_context)),
}
}
pub(in crate::db::executor) fn into_optional_id_terminal(
self,
kind: AggregateKind,
mismatch_context: &'static str,
) -> Result<Option<StorageKey>, InternalError> {
match (kind, self) {
(AggregateKind::Min, Self::Min(value))
| (AggregateKind::Max, Self::Max(value))
| (AggregateKind::First, Self::First(value))
| (AggregateKind::Last, Self::Last(value)) => Ok(value),
_ => Err(Self::output_kind_mismatch(mismatch_context)),
}
}
}
impl ScalarTerminalKind {
fn unsupported_aggregate_kind(kind: AggregateKind) -> InternalError {
InternalError::query_executor_invariant(format!(
"scalar terminal reducer requires COUNT/EXISTS/MIN/MAX/FIRST/LAST aggregate kind, found {kind:?}",
))
}
pub(in crate::db::executor) fn try_from_aggregate_kind(
kind: AggregateKind,
) -> Result<Self, InternalError> {
match kind {
AggregateKind::Count => Ok(Self::Count),
AggregateKind::Exists => Ok(Self::Exists),
AggregateKind::Min => Ok(Self::Min),
AggregateKind::Max => Ok(Self::Max),
AggregateKind::First => Ok(Self::First),
AggregateKind::Last => Ok(Self::Last),
AggregateKind::Sum | AggregateKind::Avg => Err(Self::unsupported_aggregate_kind(kind)),
}
}
#[must_use]
pub(in crate::db::executor) const fn aggregate_kind(self) -> AggregateKind {
match self {
Self::Count => AggregateKind::Count,
Self::Exists => AggregateKind::Exists,
Self::Min => AggregateKind::Min,
Self::Max => AggregateKind::Max,
Self::First => AggregateKind::First,
Self::Last => AggregateKind::Last,
}
}
#[must_use]
pub(in crate::db::executor) const fn zero_output(self) -> ScalarAggregateOutput {
match self {
Self::Count => ScalarAggregateOutput::Count(0),
Self::Exists => ScalarAggregateOutput::Exists(false),
Self::Min => ScalarAggregateOutput::Min(None),
Self::Max => ScalarAggregateOutput::Max(None),
Self::First => ScalarAggregateOutput::First(None),
Self::Last => ScalarAggregateOutput::Last(None),
}
}
}
impl AggregateKind {
#[must_use]
pub(in crate::db::executor) const fn extrema_output(
self,
key: Option<StorageKey>,
) -> Option<ScalarAggregateOutput> {
match self {
Self::Min => Some(ScalarAggregateOutput::Min(key)),
Self::Max => Some(ScalarAggregateOutput::Max(key)),
Self::Count | Self::Sum | Self::Avg | Self::Exists | Self::First | Self::Last => None,
}
}
#[must_use]
pub(in crate::db::executor) const fn is_unresolved_extrema_output(
self,
output: &ScalarAggregateOutput,
) -> bool {
matches!(
(self, output),
(Self::Min, ScalarAggregateOutput::Min(None))
| (Self::Max, ScalarAggregateOutput::Max(None))
)
}
}