use crate::{
db::{
DbSession, PersistedRow, Query,
query::{
builder::{
AvgBySlotTerminal, AvgDistinctBySlotTerminal, CountDistinctBySlotTerminal,
CountRowsTerminal, DistinctValuesBySlotTerminal, ExistsRowsTerminal,
FirstIdTerminal, FirstValueBySlotTerminal, LastIdTerminal, LastValueBySlotTerminal,
MaxIdBySlotTerminal, MaxIdTerminal, MedianIdBySlotTerminal, MinIdBySlotTerminal,
MinIdTerminal, MinMaxIdBySlotTerminal, NthIdBySlotTerminal, SumBySlotTerminal,
SumDistinctBySlotTerminal, ValuesBySlotTerminal, ValuesBySlotWithIdsTerminal,
},
explain::{ExplainAggregateTerminalPlan, ExplainExecutionNodeDescriptor},
intent::QueryError,
},
},
traits::EntityValue,
types::{Decimal, Id},
value::Value,
};
pub(super) type MinMaxByIds<E> = Option<(Id<E>, Id<E>)>;
pub(super) trait TerminalStrategyDriver<E: PersistedRow + EntityValue> {
type Output;
type ExplainOutput;
fn execute(
self,
session: &DbSession<E::Canister>,
query: &Query<E>,
) -> Result<Self::Output, QueryError>;
fn explain(
&self,
session: &DbSession<E::Canister>,
query: &Query<E>,
) -> Result<Self::ExplainOutput, QueryError>;
}
macro_rules! impl_aggregate_terminal_driver {
($terminal:ty, $output:ty, $execute:ident) => {
impl<E> TerminalStrategyDriver<E> for $terminal
where
E: PersistedRow + EntityValue,
{
type Output = $output;
type ExplainOutput = ExplainAggregateTerminalPlan;
fn execute(
self,
session: &DbSession<E::Canister>,
query: &Query<E>,
) -> Result<Self::Output, QueryError> {
session.$execute(query, self)
}
fn explain(
&self,
session: &DbSession<E::Canister>,
query: &Query<E>,
) -> Result<Self::ExplainOutput, QueryError> {
session.explain_query_prepared_aggregate_terminal_with_visible_indexes(query, self)
}
}
};
}
macro_rules! impl_projection_terminal_driver {
($terminal:ty, $output:ty, $execute:ident) => {
impl<E> TerminalStrategyDriver<E> for $terminal
where
E: PersistedRow + EntityValue,
{
type Output = $output;
type ExplainOutput = ExplainExecutionNodeDescriptor;
fn execute(
self,
session: &DbSession<E::Canister>,
query: &Query<E>,
) -> Result<Self::Output, QueryError> {
session.$execute(query, self)
}
fn explain(
&self,
session: &DbSession<E::Canister>,
query: &Query<E>,
) -> Result<Self::ExplainOutput, QueryError> {
session.explain_query_prepared_projection_terminal_with_visible_indexes(query, self)
}
}
};
}
impl_aggregate_terminal_driver!(CountRowsTerminal, u32, execute_fluent_count_rows_terminal);
impl_aggregate_terminal_driver!(
ExistsRowsTerminal,
bool,
execute_fluent_exists_rows_terminal
);
impl_aggregate_terminal_driver!(MinIdTerminal, Option<Id<E>>, execute_fluent_min_id_terminal);
impl_aggregate_terminal_driver!(MaxIdTerminal, Option<Id<E>>, execute_fluent_max_id_terminal);
impl_aggregate_terminal_driver!(
MinIdBySlotTerminal,
Option<Id<E>>,
execute_fluent_min_id_by_slot
);
impl_aggregate_terminal_driver!(
MaxIdBySlotTerminal,
Option<Id<E>>,
execute_fluent_max_id_by_slot
);
impl_aggregate_terminal_driver!(
SumBySlotTerminal,
Option<Decimal>,
execute_fluent_sum_by_slot
);
impl_aggregate_terminal_driver!(
SumDistinctBySlotTerminal,
Option<Decimal>,
execute_fluent_sum_distinct_by_slot
);
impl_aggregate_terminal_driver!(
AvgBySlotTerminal,
Option<Decimal>,
execute_fluent_avg_by_slot
);
impl_aggregate_terminal_driver!(
AvgDistinctBySlotTerminal,
Option<Decimal>,
execute_fluent_avg_distinct_by_slot
);
impl_aggregate_terminal_driver!(
FirstIdTerminal,
Option<Id<E>>,
execute_fluent_first_id_terminal
);
impl_aggregate_terminal_driver!(
LastIdTerminal,
Option<Id<E>>,
execute_fluent_last_id_terminal
);
impl_aggregate_terminal_driver!(
NthIdBySlotTerminal,
Option<Id<E>>,
execute_fluent_nth_id_by_slot
);
impl_aggregate_terminal_driver!(
MedianIdBySlotTerminal,
Option<Id<E>>,
execute_fluent_median_id_by_slot
);
impl_aggregate_terminal_driver!(
MinMaxIdBySlotTerminal,
MinMaxByIds<E>,
execute_fluent_min_max_id_by_slot
);
impl_projection_terminal_driver!(
ValuesBySlotTerminal,
Vec<Value>,
execute_fluent_values_by_slot
);
impl_projection_terminal_driver!(
DistinctValuesBySlotTerminal,
Vec<Value>,
execute_fluent_distinct_values_by_slot
);
impl_projection_terminal_driver!(
CountDistinctBySlotTerminal,
u32,
execute_fluent_count_distinct_by_slot
);
impl_projection_terminal_driver!(
ValuesBySlotWithIdsTerminal,
Vec<(Id<E>, Value)>,
execute_fluent_values_by_with_ids_slot
);
impl_projection_terminal_driver!(
FirstValueBySlotTerminal,
Option<Value>,
execute_fluent_first_value_by_slot
);
impl_projection_terminal_driver!(
LastValueBySlotTerminal,
Option<Value>,
execute_fluent_last_value_by_slot
);