use crate::{
db::{
DbSession, PersistedRow, Query, QueryError,
executor::{ScalarProjectionBoundaryOutput, ScalarProjectionBoundaryRequest},
query::{
builder::{
CountDistinctBySlotTerminal, DistinctValuesBySlotTerminal,
FirstValueBySlotTerminal, LastValueBySlotTerminal, ValuesBySlotTerminal,
ValuesBySlotWithIdsTerminal,
},
plan::{AggregateKind, FieldSlot, expr::Expr},
},
},
error::InternalError,
traits::{CanisterKind, EntityValue},
types::Id,
value::Value,
};
impl<C: CanisterKind> DbSession<C> {
fn execute_scalar_projection_boundary<E>(
&self,
query: &Query<E>,
target_field: FieldSlot,
request: ScalarProjectionBoundaryRequest,
) -> Result<ScalarProjectionBoundaryOutput, QueryError>
where
E: PersistedRow<Canister = C> + EntityValue,
{
self.execute_with_plan(query, move |load, plan| {
load.execute_scalar_projection_boundary(plan, target_field, request)
})
}
fn execute_scalar_projection_value<E, T>(
&self,
query: &Query<E>,
target_field: FieldSlot,
request: ScalarProjectionBoundaryRequest,
decode: impl FnOnce(ScalarProjectionBoundaryOutput) -> Result<T, InternalError>,
) -> Result<T, QueryError>
where
E: PersistedRow<Canister = C> + EntityValue,
{
decode(self.execute_scalar_projection_boundary(query, target_field, request)?)
.map_err(QueryError::execute)
}
pub(in crate::db) fn execute_fluent_values_by_slot<E>(
&self,
query: &Query<E>,
strategy: ValuesBySlotTerminal,
) -> Result<Vec<Value>, QueryError>
where
E: PersistedRow<Canister = C> + EntityValue,
{
let (target_field, request) = strategy.into_executor_request();
self.execute_scalar_projection_value(
query,
target_field,
request,
ScalarProjectionBoundaryOutput::into_values,
)
}
pub(in crate::db) fn execute_fluent_project_values_by_slot<E>(
&self,
query: &Query<E>,
target_field: FieldSlot,
projection: Expr,
) -> Result<Vec<Value>, QueryError>
where
E: PersistedRow<Canister = C> + EntityValue,
{
self.execute_scalar_projection_value(
query,
target_field,
ScalarProjectionBoundaryRequest::ProjectedValues { projection },
ScalarProjectionBoundaryOutput::into_values,
)
}
pub(in crate::db) fn execute_fluent_distinct_values_by_slot<E>(
&self,
query: &Query<E>,
strategy: DistinctValuesBySlotTerminal,
) -> Result<Vec<Value>, QueryError>
where
E: PersistedRow<Canister = C> + EntityValue,
{
let (target_field, request) = strategy.into_executor_request();
self.execute_scalar_projection_value(
query,
target_field,
request,
ScalarProjectionBoundaryOutput::into_values,
)
}
pub(in crate::db) fn execute_fluent_count_distinct_by_slot<E>(
&self,
query: &Query<E>,
strategy: CountDistinctBySlotTerminal,
) -> Result<u32, QueryError>
where
E: PersistedRow<Canister = C> + EntityValue,
{
let (target_field, request) = strategy.into_executor_request();
self.execute_scalar_projection_value(
query,
target_field,
request,
ScalarProjectionBoundaryOutput::into_count,
)
}
pub(in crate::db) fn execute_fluent_values_by_with_ids_slot<E>(
&self,
query: &Query<E>,
strategy: ValuesBySlotWithIdsTerminal,
) -> Result<Vec<(Id<E>, Value)>, QueryError>
where
E: PersistedRow<Canister = C> + EntityValue,
{
let (target_field, request) = strategy.into_executor_request();
self.execute_scalar_projection_value(
query,
target_field,
request,
ScalarProjectionBoundaryOutput::into_values_with_ids::<E>,
)
}
pub(in crate::db) fn execute_fluent_project_values_with_ids_by_slot<E>(
&self,
query: &Query<E>,
target_field: FieldSlot,
projection: Expr,
) -> Result<Vec<(Id<E>, Value)>, QueryError>
where
E: PersistedRow<Canister = C> + EntityValue,
{
self.execute_scalar_projection_value(
query,
target_field,
ScalarProjectionBoundaryRequest::ProjectedValuesWithIds { projection },
ScalarProjectionBoundaryOutput::into_values_with_ids::<E>,
)
}
pub(in crate::db) fn execute_fluent_first_value_by_slot<E>(
&self,
query: &Query<E>,
strategy: FirstValueBySlotTerminal,
) -> Result<Option<Value>, QueryError>
where
E: PersistedRow<Canister = C> + EntityValue,
{
let (target_field, request) = strategy.into_executor_request();
self.execute_scalar_projection_value(
query,
target_field,
request,
ScalarProjectionBoundaryOutput::into_terminal_value,
)
}
pub(in crate::db) fn execute_fluent_last_value_by_slot<E>(
&self,
query: &Query<E>,
strategy: LastValueBySlotTerminal,
) -> Result<Option<Value>, QueryError>
where
E: PersistedRow<Canister = C> + EntityValue,
{
let (target_field, request) = strategy.into_executor_request();
self.execute_scalar_projection_value(
query,
target_field,
request,
ScalarProjectionBoundaryOutput::into_terminal_value,
)
}
pub(in crate::db) fn execute_fluent_project_terminal_value_by_slot<E>(
&self,
query: &Query<E>,
target_field: FieldSlot,
terminal_kind: AggregateKind,
projection: Expr,
) -> Result<Option<Value>, QueryError>
where
E: PersistedRow<Canister = C> + EntityValue,
{
self.execute_scalar_projection_value(
query,
target_field,
ScalarProjectionBoundaryRequest::ProjectedTerminalValue {
terminal_kind,
projection,
},
ScalarProjectionBoundaryOutput::into_terminal_value,
)
}
}