use crate::{
db::{
DbSession, EntityResponse, PersistedRow, Query, QueryError,
executor::{
ScalarProjectionBoundaryOutput, ScalarProjectionBoundaryRequest,
ScalarTerminalBoundaryOutput, ScalarTerminalBoundaryRequest,
},
query::builder::{
PreparedFluentExistingRowsTerminalRuntimeRequest,
PreparedFluentExistingRowsTerminalStrategy, PreparedFluentNumericFieldStrategy,
PreparedFluentOrderSensitiveTerminalStrategy, PreparedFluentProjectionRuntimeRequest,
PreparedFluentProjectionStrategy, PreparedFluentScalarTerminalStrategy,
},
query::fluent::load::{FluentProjectionTerminalOutput, FluentScalarTerminalOutput},
query::plan::FieldSlot,
},
traits::{CanisterKind, EntityValue},
types::{Decimal, Id},
value::Value,
};
impl<C: CanisterKind> DbSession<C> {
fn execute_scalar_terminal_boundary<E>(
&self,
query: &Query<E>,
request: ScalarTerminalBoundaryRequest,
) -> Result<ScalarTerminalBoundaryOutput, QueryError>
where
E: PersistedRow<Canister = C> + EntityValue,
{
self.execute_with_plan(query, move |load, plan| {
load.execute_scalar_terminal_request(plan, request)
})
}
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)
})
}
pub(in crate::db) fn execute_fluent_existing_rows_terminal<E>(
&self,
query: &Query<E>,
strategy: PreparedFluentExistingRowsTerminalStrategy,
) -> Result<FluentScalarTerminalOutput<E>, QueryError>
where
E: PersistedRow<Canister = C> + EntityValue,
{
let (request, output_shape) = strategy.into_executor_request();
let output = self.execute_scalar_terminal_boundary(query, request)?;
match output_shape {
PreparedFluentExistingRowsTerminalRuntimeRequest::CountRows => output
.into_count()
.map(FluentScalarTerminalOutput::Count)
.map_err(QueryError::execute),
PreparedFluentExistingRowsTerminalRuntimeRequest::ExistsRows => output
.into_exists()
.map(FluentScalarTerminalOutput::Exists)
.map_err(QueryError::execute),
}
}
pub(in crate::db) fn execute_fluent_scalar_terminal<E>(
&self,
query: &Query<E>,
strategy: PreparedFluentScalarTerminalStrategy,
) -> Result<FluentScalarTerminalOutput<E>, QueryError>
where
E: PersistedRow<Canister = C> + EntityValue,
{
let request = strategy.into_executor_request();
self.execute_scalar_terminal_boundary(query, request)?
.into_id::<E>()
.map(FluentScalarTerminalOutput::Id)
.map_err(QueryError::execute)
}
pub(in crate::db) fn execute_fluent_order_sensitive_terminal<E>(
&self,
query: &Query<E>,
strategy: PreparedFluentOrderSensitiveTerminalStrategy,
) -> Result<FluentScalarTerminalOutput<E>, QueryError>
where
E: PersistedRow<Canister = C> + EntityValue,
{
let (request, returns_id_pair) = strategy.into_executor_request();
let output = self.execute_scalar_terminal_boundary(query, request)?;
if returns_id_pair {
return output
.into_id_pair::<E>()
.map(FluentScalarTerminalOutput::IdPair)
.map_err(QueryError::execute);
}
output
.into_id::<E>()
.map(FluentScalarTerminalOutput::Id)
.map_err(QueryError::execute)
}
pub(in crate::db) fn execute_fluent_numeric_field_terminal<E>(
&self,
query: &Query<E>,
strategy: PreparedFluentNumericFieldStrategy,
) -> Result<Option<Decimal>, QueryError>
where
E: PersistedRow<Canister = C> + EntityValue,
{
let (target_field, request) = strategy.into_executor_request();
self.execute_with_plan(query, move |load, plan| {
load.execute_numeric_field_boundary(plan, target_field, request)
})
}
pub(in crate::db) fn execute_fluent_projection_terminal<E>(
&self,
query: &Query<E>,
strategy: PreparedFluentProjectionStrategy,
) -> Result<FluentProjectionTerminalOutput<E>, QueryError>
where
E: PersistedRow<Canister = C> + EntityValue,
{
let (target_field, request, output_shape) = strategy.into_executor_request();
let output = self.execute_scalar_projection_boundary(query, target_field, request)?;
match output_shape {
PreparedFluentProjectionRuntimeRequest::Values
| PreparedFluentProjectionRuntimeRequest::DistinctValues => output
.into_values()
.map(FluentProjectionTerminalOutput::Values)
.map_err(QueryError::execute),
PreparedFluentProjectionRuntimeRequest::CountDistinct => output
.into_count()
.map(FluentProjectionTerminalOutput::Count)
.map_err(QueryError::execute),
PreparedFluentProjectionRuntimeRequest::ValuesWithIds => output
.into_values_with_ids::<E>()
.map(FluentProjectionTerminalOutput::ValuesWithIds)
.map_err(QueryError::execute),
PreparedFluentProjectionRuntimeRequest::TerminalValue { .. } => output
.into_terminal_value()
.map(FluentProjectionTerminalOutput::TerminalValue)
.map_err(QueryError::execute),
}
}
pub(in crate::db) fn execute_fluent_bytes<E>(&self, query: &Query<E>) -> Result<u64, QueryError>
where
E: PersistedRow<Canister = C> + EntityValue,
{
self.execute_with_plan(query, |load, plan| load.bytes(plan))
}
pub(in crate::db) fn execute_fluent_bytes_by_slot<E>(
&self,
query: &Query<E>,
target_slot: FieldSlot,
) -> Result<u64, QueryError>
where
E: PersistedRow<Canister = C> + EntityValue,
{
self.execute_with_plan(query, move |load, plan| {
load.bytes_by_slot(plan, target_slot)
})
}
pub(in crate::db) fn execute_fluent_take<E>(
&self,
query: &Query<E>,
take_count: u32,
) -> Result<EntityResponse<E>, QueryError>
where
E: PersistedRow<Canister = C> + EntityValue,
{
self.execute_with_plan(query, move |load, plan| load.take(plan, take_count))
}
pub(in crate::db) fn execute_fluent_ranked_rows_by_slot<E>(
&self,
query: &Query<E>,
target_slot: FieldSlot,
take_count: u32,
descending: bool,
) -> Result<EntityResponse<E>, QueryError>
where
E: PersistedRow<Canister = C> + EntityValue,
{
self.execute_with_plan(query, move |load, plan| {
if descending {
load.top_k_by_slot(plan, target_slot, take_count)
} else {
load.bottom_k_by_slot(plan, target_slot, take_count)
}
})
}
pub(in crate::db) fn execute_fluent_ranked_values_by_slot<E>(
&self,
query: &Query<E>,
target_slot: FieldSlot,
take_count: u32,
descending: bool,
) -> Result<Vec<Value>, QueryError>
where
E: PersistedRow<Canister = C> + EntityValue,
{
self.execute_with_plan(query, move |load, plan| {
if descending {
load.top_k_by_values_slot(plan, target_slot, take_count)
} else {
load.bottom_k_by_values_slot(plan, target_slot, take_count)
}
})
}
pub(in crate::db) fn execute_fluent_ranked_values_with_ids_by_slot<E>(
&self,
query: &Query<E>,
target_slot: FieldSlot,
take_count: u32,
descending: bool,
) -> Result<Vec<(Id<E>, Value)>, QueryError>
where
E: PersistedRow<Canister = C> + EntityValue,
{
self.execute_with_plan(query, move |load, plan| {
if descending {
load.top_k_by_with_ids_slot(plan, target_slot, take_count)
} else {
load.bottom_k_by_with_ids_slot(plan, target_slot, take_count)
}
})
}
}