use crate::{
db::{
PersistedRow,
executor::{
LoadExecutor, PreparedExecutionPlan, ScalarNumericFieldBoundaryRequest,
ScalarProjectionBoundaryRequest, ScalarTerminalBoundaryOutput,
ScalarTerminalBoundaryRequest,
},
query::{
api::ResponseCardinalityExt,
builder::{
PreparedFluentAggregateExplainStrategy,
PreparedFluentExistingRowsTerminalRuntimeRequest,
PreparedFluentExistingRowsTerminalStrategy,
PreparedFluentNumericFieldRuntimeRequest, PreparedFluentNumericFieldStrategy,
PreparedFluentOrderSensitiveTerminalRuntimeRequest,
PreparedFluentOrderSensitiveTerminalStrategy,
PreparedFluentProjectionRuntimeRequest, PreparedFluentProjectionStrategy,
PreparedFluentScalarTerminalRuntimeRequest, PreparedFluentScalarTerminalStrategy,
TextProjectionExpr,
},
explain::{ExplainAggregateTerminalPlan, ExplainExecutionNodeDescriptor},
fluent::load::{FluentLoadQuery, LoadQueryResult},
intent::QueryError,
plan::AggregateKind,
},
response::EntityResponse,
},
error::InternalError,
traits::EntityValue,
types::{Decimal, Id},
value::Value,
};
type MinMaxByIds<E> = Option<(Id<E>, Id<E>)>;
impl<E> FluentLoadQuery<'_, E>
where
E: PersistedRow,
{
pub fn execute(&self) -> Result<LoadQueryResult<E>, QueryError>
where
E: EntityValue,
{
self.ensure_non_paged_mode_ready()?;
if self.query().has_grouping() {
return self
.session
.execute_grouped(self.query(), self.cursor_token.as_deref())
.map(LoadQueryResult::Grouped);
}
self.session
.execute_query(self.query())
.map(LoadQueryResult::Rows)
}
fn execute_scalar_non_paged_terminal<T, F>(&self, execute: F) -> Result<T, QueryError>
where
E: EntityValue,
F: FnOnce(LoadExecutor<E>, PreparedExecutionPlan<E>) -> Result<T, InternalError>,
{
self.ensure_non_paged_mode_ready()?;
self.session.execute_load_query_with(self.query(), execute)
}
fn explain_prepared_aggregate_non_paged_terminal<S>(
&self,
strategy: &S,
) -> Result<ExplainAggregateTerminalPlan, QueryError>
where
E: EntityValue,
S: PreparedFluentAggregateExplainStrategy,
{
self.ensure_non_paged_mode_ready()?;
self.session
.explain_query_prepared_aggregate_terminal_with_visible_indexes(self.query(), strategy)
}
fn explain_prepared_projection_non_paged_terminal(
&self,
strategy: &PreparedFluentProjectionStrategy,
) -> Result<ExplainExecutionNodeDescriptor, QueryError>
where
E: EntityValue,
{
self.ensure_non_paged_mode_ready()?;
self.session
.explain_query_prepared_projection_terminal_with_visible_indexes(self.query(), strategy)
}
fn execute_prepared_scalar_terminal_output(
&self,
strategy: PreparedFluentScalarTerminalStrategy,
) -> Result<ScalarTerminalBoundaryOutput, QueryError>
where
E: EntityValue,
{
let runtime_request = strategy.into_runtime_request();
self.execute_scalar_non_paged_terminal(move |load, plan| {
load.execute_scalar_terminal_request(
plan,
scalar_terminal_boundary_request_from_prepared(runtime_request),
)
})
}
fn execute_prepared_existing_rows_terminal_output(
&self,
strategy: PreparedFluentExistingRowsTerminalStrategy,
) -> Result<ScalarTerminalBoundaryOutput, QueryError>
where
E: EntityValue,
{
let runtime_request = strategy.into_runtime_request();
self.execute_scalar_non_paged_terminal(move |load, plan| {
load.execute_scalar_terminal_request(
plan,
existing_rows_terminal_boundary_request_from_prepared(runtime_request),
)
})
}
fn execute_prepared_numeric_field_terminal(
&self,
strategy: PreparedFluentNumericFieldStrategy,
) -> Result<Option<Decimal>, QueryError>
where
E: EntityValue,
{
let (target_field, runtime_request) = strategy.into_runtime_parts();
self.execute_scalar_non_paged_terminal(move |load, plan| {
load.execute_numeric_field_boundary(
plan,
target_field,
numeric_field_boundary_request_from_prepared(runtime_request),
)
})
}
fn execute_prepared_order_sensitive_terminal_output(
&self,
strategy: PreparedFluentOrderSensitiveTerminalStrategy,
) -> Result<ScalarTerminalBoundaryOutput, QueryError>
where
E: EntityValue,
{
let runtime_request = strategy.into_runtime_request();
self.execute_scalar_non_paged_terminal(move |load, plan| {
load.execute_scalar_terminal_request(
plan,
order_sensitive_terminal_boundary_request_from_prepared(runtime_request),
)
})
}
fn execute_prepared_projection_terminal_output(
&self,
strategy: PreparedFluentProjectionStrategy,
) -> Result<crate::db::executor::ScalarProjectionBoundaryOutput, QueryError>
where
E: EntityValue,
{
let (target_field, runtime_request) = strategy.into_runtime_parts();
self.execute_scalar_non_paged_terminal(move |load, plan| {
load.execute_scalar_projection_boundary(
plan,
target_field,
projection_boundary_request_from_prepared(runtime_request),
)
})
}
fn project_terminal_values(
projection: &TextProjectionExpr,
values: Vec<Value>,
) -> Result<Vec<Value>, QueryError> {
values
.into_iter()
.map(|value| projection.apply_value(value))
.collect()
}
fn project_terminal_optional_value(
projection: &TextProjectionExpr,
value: Option<Value>,
) -> Result<Option<Value>, QueryError> {
value.map(|value| projection.apply_value(value)).transpose()
}
fn project_terminal_values_with_ids(
projection: &TextProjectionExpr,
values: Vec<(Id<E>, Value)>,
) -> Result<Vec<(Id<E>, Value)>, QueryError> {
values
.into_iter()
.map(|(id, value)| Ok((id, projection.apply_value(value)?)))
.collect()
}
pub fn is_empty(&self) -> Result<bool, QueryError>
where
E: EntityValue,
{
self.not_exists()
}
pub fn not_exists(&self) -> Result<bool, QueryError>
where
E: EntityValue,
{
Ok(!self.exists()?)
}
pub fn exists(&self) -> Result<bool, QueryError>
where
E: EntityValue,
{
self.execute_prepared_existing_rows_terminal_output(
PreparedFluentExistingRowsTerminalStrategy::exists_rows(),
)?
.into_exists()
.map_err(QueryError::execute)
}
pub fn explain_exists(&self) -> Result<ExplainAggregateTerminalPlan, QueryError>
where
E: EntityValue,
{
self.explain_prepared_aggregate_non_paged_terminal(
&PreparedFluentExistingRowsTerminalStrategy::exists_rows(),
)
}
pub fn explain_not_exists(&self) -> Result<ExplainAggregateTerminalPlan, QueryError>
where
E: EntityValue,
{
self.explain_exists()
}
pub fn explain_execution(&self) -> Result<ExplainExecutionNodeDescriptor, QueryError>
where
E: EntityValue,
{
self.session
.explain_query_execution_with_visible_indexes(self.query())
}
pub fn explain_execution_text(&self) -> Result<String, QueryError>
where
E: EntityValue,
{
self.session
.explain_query_execution_text_with_visible_indexes(self.query())
}
pub fn explain_execution_json(&self) -> Result<String, QueryError>
where
E: EntityValue,
{
self.session
.explain_query_execution_json_with_visible_indexes(self.query())
}
pub fn explain_execution_verbose(&self) -> Result<String, QueryError>
where
E: EntityValue,
{
self.session
.explain_query_execution_verbose_with_visible_indexes(self.query())
}
pub fn count(&self) -> Result<u32, QueryError>
where
E: EntityValue,
{
self.execute_prepared_existing_rows_terminal_output(
PreparedFluentExistingRowsTerminalStrategy::count_rows(),
)?
.into_count()
.map_err(QueryError::execute)
}
pub fn bytes(&self) -> Result<u64, QueryError>
where
E: EntityValue,
{
self.execute_scalar_non_paged_terminal(|load, plan| load.bytes(plan))
}
pub fn bytes_by(&self, field: impl AsRef<str>) -> Result<u64, QueryError>
where
E: EntityValue,
{
self.ensure_non_paged_mode_ready()?;
Self::with_slot(field, |target_slot| {
self.session
.execute_load_query_with(self.query(), move |load, plan| {
load.bytes_by_slot(plan, target_slot)
})
})
}
pub fn explain_bytes_by(
&self,
field: impl AsRef<str>,
) -> Result<ExplainExecutionNodeDescriptor, QueryError>
where
E: EntityValue,
{
self.ensure_non_paged_mode_ready()?;
Self::with_slot(field, |target_slot| {
self.session
.explain_query_bytes_by_with_visible_indexes(self.query(), target_slot.field())
})
}
pub fn min(&self) -> Result<Option<Id<E>>, QueryError>
where
E: EntityValue,
{
self.execute_prepared_scalar_terminal_output(
PreparedFluentScalarTerminalStrategy::id_terminal(AggregateKind::Min),
)?
.into_id()
.map_err(QueryError::execute)
}
pub fn explain_min(&self) -> Result<ExplainAggregateTerminalPlan, QueryError>
where
E: EntityValue,
{
self.explain_prepared_aggregate_non_paged_terminal(
&PreparedFluentScalarTerminalStrategy::id_terminal(AggregateKind::Min),
)
}
pub fn min_by(&self, field: impl AsRef<str>) -> Result<Option<Id<E>>, QueryError>
where
E: EntityValue,
{
self.ensure_non_paged_mode_ready()?;
Self::with_slot(field, |target_slot| {
self.execute_prepared_scalar_terminal_output(
PreparedFluentScalarTerminalStrategy::id_by_slot(AggregateKind::Min, target_slot),
)?
.into_id()
.map_err(QueryError::execute)
})
}
pub fn max(&self) -> Result<Option<Id<E>>, QueryError>
where
E: EntityValue,
{
self.execute_prepared_scalar_terminal_output(
PreparedFluentScalarTerminalStrategy::id_terminal(AggregateKind::Max),
)?
.into_id()
.map_err(QueryError::execute)
}
pub fn explain_max(&self) -> Result<ExplainAggregateTerminalPlan, QueryError>
where
E: EntityValue,
{
self.explain_prepared_aggregate_non_paged_terminal(
&PreparedFluentScalarTerminalStrategy::id_terminal(AggregateKind::Max),
)
}
pub fn max_by(&self, field: impl AsRef<str>) -> Result<Option<Id<E>>, QueryError>
where
E: EntityValue,
{
self.ensure_non_paged_mode_ready()?;
Self::with_slot(field, |target_slot| {
self.execute_prepared_scalar_terminal_output(
PreparedFluentScalarTerminalStrategy::id_by_slot(AggregateKind::Max, target_slot),
)?
.into_id()
.map_err(QueryError::execute)
})
}
pub fn nth_by(&self, field: impl AsRef<str>, nth: usize) -> Result<Option<Id<E>>, QueryError>
where
E: EntityValue,
{
self.ensure_non_paged_mode_ready()?;
Self::with_slot(field, |target_slot| {
self.execute_prepared_order_sensitive_terminal_output(
PreparedFluentOrderSensitiveTerminalStrategy::nth_by_slot(target_slot, nth),
)?
.into_id()
.map_err(QueryError::execute)
})
}
pub fn sum_by(&self, field: impl AsRef<str>) -> Result<Option<Decimal>, QueryError>
where
E: EntityValue,
{
self.ensure_non_paged_mode_ready()?;
Self::with_slot(field, |target_slot| {
self.execute_prepared_numeric_field_terminal(
PreparedFluentNumericFieldStrategy::sum_by_slot(target_slot),
)
})
}
pub fn explain_sum_by(
&self,
field: impl AsRef<str>,
) -> Result<ExplainAggregateTerminalPlan, QueryError>
where
E: EntityValue,
{
self.ensure_non_paged_mode_ready()?;
Self::with_slot(field, |target_slot| {
self.explain_prepared_aggregate_non_paged_terminal(
&PreparedFluentNumericFieldStrategy::sum_by_slot(target_slot),
)
})
}
pub fn sum_distinct_by(&self, field: impl AsRef<str>) -> Result<Option<Decimal>, QueryError>
where
E: EntityValue,
{
self.ensure_non_paged_mode_ready()?;
Self::with_slot(field, |target_slot| {
self.execute_prepared_numeric_field_terminal(
PreparedFluentNumericFieldStrategy::sum_distinct_by_slot(target_slot),
)
})
}
pub fn explain_sum_distinct_by(
&self,
field: impl AsRef<str>,
) -> Result<ExplainAggregateTerminalPlan, QueryError>
where
E: EntityValue,
{
self.ensure_non_paged_mode_ready()?;
Self::with_slot(field, |target_slot| {
self.explain_prepared_aggregate_non_paged_terminal(
&PreparedFluentNumericFieldStrategy::sum_distinct_by_slot(target_slot),
)
})
}
pub fn avg_by(&self, field: impl AsRef<str>) -> Result<Option<Decimal>, QueryError>
where
E: EntityValue,
{
self.ensure_non_paged_mode_ready()?;
Self::with_slot(field, |target_slot| {
self.execute_prepared_numeric_field_terminal(
PreparedFluentNumericFieldStrategy::avg_by_slot(target_slot),
)
})
}
pub fn explain_avg_by(
&self,
field: impl AsRef<str>,
) -> Result<ExplainAggregateTerminalPlan, QueryError>
where
E: EntityValue,
{
self.ensure_non_paged_mode_ready()?;
Self::with_slot(field, |target_slot| {
self.explain_prepared_aggregate_non_paged_terminal(
&PreparedFluentNumericFieldStrategy::avg_by_slot(target_slot),
)
})
}
pub fn avg_distinct_by(&self, field: impl AsRef<str>) -> Result<Option<Decimal>, QueryError>
where
E: EntityValue,
{
self.ensure_non_paged_mode_ready()?;
Self::with_slot(field, |target_slot| {
self.execute_prepared_numeric_field_terminal(
PreparedFluentNumericFieldStrategy::avg_distinct_by_slot(target_slot),
)
})
}
pub fn explain_avg_distinct_by(
&self,
field: impl AsRef<str>,
) -> Result<ExplainAggregateTerminalPlan, QueryError>
where
E: EntityValue,
{
self.ensure_non_paged_mode_ready()?;
Self::with_slot(field, |target_slot| {
self.explain_prepared_aggregate_non_paged_terminal(
&PreparedFluentNumericFieldStrategy::avg_distinct_by_slot(target_slot),
)
})
}
pub fn median_by(&self, field: impl AsRef<str>) -> Result<Option<Id<E>>, QueryError>
where
E: EntityValue,
{
self.ensure_non_paged_mode_ready()?;
Self::with_slot(field, |target_slot| {
self.execute_prepared_order_sensitive_terminal_output(
PreparedFluentOrderSensitiveTerminalStrategy::median_by_slot(target_slot),
)?
.into_id()
.map_err(QueryError::execute)
})
}
pub fn count_distinct_by(&self, field: impl AsRef<str>) -> Result<u32, QueryError>
where
E: EntityValue,
{
self.ensure_non_paged_mode_ready()?;
Self::with_slot(field, |target_slot| {
self.execute_prepared_projection_terminal_output(
PreparedFluentProjectionStrategy::count_distinct_by_slot(target_slot),
)?
.into_count()
.map_err(QueryError::execute)
})
}
pub fn explain_count_distinct_by(
&self,
field: impl AsRef<str>,
) -> Result<ExplainExecutionNodeDescriptor, QueryError>
where
E: EntityValue,
{
self.ensure_non_paged_mode_ready()?;
Self::with_slot(field, |target_slot| {
self.explain_prepared_projection_non_paged_terminal(
&PreparedFluentProjectionStrategy::count_distinct_by_slot(target_slot),
)
})
}
pub fn min_max_by(&self, field: impl AsRef<str>) -> Result<MinMaxByIds<E>, QueryError>
where
E: EntityValue,
{
self.ensure_non_paged_mode_ready()?;
Self::with_slot(field, |target_slot| {
self.execute_prepared_order_sensitive_terminal_output(
PreparedFluentOrderSensitiveTerminalStrategy::min_max_by_slot(target_slot),
)?
.into_id_pair()
.map_err(QueryError::execute)
})
}
pub fn values_by(&self, field: impl AsRef<str>) -> Result<Vec<Value>, QueryError>
where
E: EntityValue,
{
self.ensure_non_paged_mode_ready()?;
Self::with_slot(field, |target_slot| {
self.execute_prepared_projection_terminal_output(
PreparedFluentProjectionStrategy::values_by_slot(target_slot),
)?
.into_values()
.map_err(QueryError::execute)
})
}
pub fn project_values(&self, projection: &TextProjectionExpr) -> Result<Vec<Value>, QueryError>
where
E: EntityValue,
{
self.ensure_non_paged_mode_ready()?;
Self::with_slot(projection.field(), |target_slot| {
let values = self
.execute_prepared_projection_terminal_output(
PreparedFluentProjectionStrategy::values_by_slot(target_slot),
)?
.into_values()
.map_err(QueryError::execute)?;
Self::project_terminal_values(projection, values)
})
}
pub fn explain_project_values(
&self,
projection: &TextProjectionExpr,
) -> Result<ExplainExecutionNodeDescriptor, QueryError>
where
E: EntityValue,
{
self.ensure_non_paged_mode_ready()?;
Self::with_slot(projection.field(), |target_slot| {
self.explain_prepared_projection_non_paged_terminal(
&PreparedFluentProjectionStrategy::values_by_slot(target_slot),
)
})
}
pub fn explain_values_by(
&self,
field: impl AsRef<str>,
) -> Result<ExplainExecutionNodeDescriptor, QueryError>
where
E: EntityValue,
{
self.ensure_non_paged_mode_ready()?;
Self::with_slot(field, |target_slot| {
self.explain_prepared_projection_non_paged_terminal(
&PreparedFluentProjectionStrategy::values_by_slot(target_slot),
)
})
}
pub fn take(&self, take_count: u32) -> Result<EntityResponse<E>, QueryError>
where
E: EntityValue,
{
self.execute_scalar_non_paged_terminal(|load, plan| load.take(plan, take_count))
}
pub fn top_k_by(
&self,
field: impl AsRef<str>,
take_count: u32,
) -> Result<EntityResponse<E>, QueryError>
where
E: EntityValue,
{
self.ensure_non_paged_mode_ready()?;
Self::with_slot(field, |target_slot| {
self.session
.execute_load_query_with(self.query(), move |load, plan| {
load.top_k_by_slot(plan, target_slot, take_count)
})
})
}
pub fn bottom_k_by(
&self,
field: impl AsRef<str>,
take_count: u32,
) -> Result<EntityResponse<E>, QueryError>
where
E: EntityValue,
{
self.ensure_non_paged_mode_ready()?;
Self::with_slot(field, |target_slot| {
self.session
.execute_load_query_with(self.query(), move |load, plan| {
load.bottom_k_by_slot(plan, target_slot, take_count)
})
})
}
pub fn top_k_by_values(
&self,
field: impl AsRef<str>,
take_count: u32,
) -> Result<Vec<Value>, QueryError>
where
E: EntityValue,
{
self.ensure_non_paged_mode_ready()?;
Self::with_slot(field, |target_slot| {
self.session
.execute_load_query_with(self.query(), move |load, plan| {
load.top_k_by_values_slot(plan, target_slot, take_count)
})
})
}
pub fn bottom_k_by_values(
&self,
field: impl AsRef<str>,
take_count: u32,
) -> Result<Vec<Value>, QueryError>
where
E: EntityValue,
{
self.ensure_non_paged_mode_ready()?;
Self::with_slot(field, |target_slot| {
self.session
.execute_load_query_with(self.query(), move |load, plan| {
load.bottom_k_by_values_slot(plan, target_slot, take_count)
})
})
}
pub fn top_k_by_with_ids(
&self,
field: impl AsRef<str>,
take_count: u32,
) -> Result<Vec<(Id<E>, Value)>, QueryError>
where
E: EntityValue,
{
self.ensure_non_paged_mode_ready()?;
Self::with_slot(field, |target_slot| {
self.session
.execute_load_query_with(self.query(), move |load, plan| {
load.top_k_by_with_ids_slot(plan, target_slot, take_count)
})
})
}
pub fn bottom_k_by_with_ids(
&self,
field: impl AsRef<str>,
take_count: u32,
) -> Result<Vec<(Id<E>, Value)>, QueryError>
where
E: EntityValue,
{
self.ensure_non_paged_mode_ready()?;
Self::with_slot(field, |target_slot| {
self.session
.execute_load_query_with(self.query(), move |load, plan| {
load.bottom_k_by_with_ids_slot(plan, target_slot, take_count)
})
})
}
pub fn distinct_values_by(&self, field: impl AsRef<str>) -> Result<Vec<Value>, QueryError>
where
E: EntityValue,
{
self.ensure_non_paged_mode_ready()?;
Self::with_slot(field, |target_slot| {
self.execute_prepared_projection_terminal_output(
PreparedFluentProjectionStrategy::distinct_values_by_slot(target_slot),
)?
.into_values()
.map_err(QueryError::execute)
})
}
pub fn explain_distinct_values_by(
&self,
field: impl AsRef<str>,
) -> Result<ExplainExecutionNodeDescriptor, QueryError>
where
E: EntityValue,
{
self.ensure_non_paged_mode_ready()?;
Self::with_slot(field, |target_slot| {
self.explain_prepared_projection_non_paged_terminal(
&PreparedFluentProjectionStrategy::distinct_values_by_slot(target_slot),
)
})
}
pub fn values_by_with_ids(
&self,
field: impl AsRef<str>,
) -> Result<Vec<(Id<E>, Value)>, QueryError>
where
E: EntityValue,
{
self.ensure_non_paged_mode_ready()?;
Self::with_slot(field, |target_slot| {
self.execute_prepared_projection_terminal_output(
PreparedFluentProjectionStrategy::values_by_with_ids_slot(target_slot),
)?
.into_values_with_ids()
.map_err(QueryError::execute)
})
}
pub fn project_values_with_ids(
&self,
projection: &TextProjectionExpr,
) -> Result<Vec<(Id<E>, Value)>, QueryError>
where
E: EntityValue,
{
self.ensure_non_paged_mode_ready()?;
Self::with_slot(projection.field(), |target_slot| {
let values = self
.execute_prepared_projection_terminal_output(
PreparedFluentProjectionStrategy::values_by_with_ids_slot(target_slot),
)?
.into_values_with_ids::<E>()
.map_err(QueryError::execute)?;
Self::project_terminal_values_with_ids(projection, values)
})
}
pub fn explain_values_by_with_ids(
&self,
field: impl AsRef<str>,
) -> Result<ExplainExecutionNodeDescriptor, QueryError>
where
E: EntityValue,
{
self.ensure_non_paged_mode_ready()?;
Self::with_slot(field, |target_slot| {
self.explain_prepared_projection_non_paged_terminal(
&PreparedFluentProjectionStrategy::values_by_with_ids_slot(target_slot),
)
})
}
pub fn first_value_by(&self, field: impl AsRef<str>) -> Result<Option<Value>, QueryError>
where
E: EntityValue,
{
self.ensure_non_paged_mode_ready()?;
Self::with_slot(field, |target_slot| {
self.execute_prepared_projection_terminal_output(
PreparedFluentProjectionStrategy::first_value_by_slot(target_slot),
)?
.into_terminal_value()
.map_err(QueryError::execute)
})
}
pub fn project_first_value(
&self,
projection: &TextProjectionExpr,
) -> Result<Option<Value>, QueryError>
where
E: EntityValue,
{
self.ensure_non_paged_mode_ready()?;
Self::with_slot(projection.field(), |target_slot| {
let value = self
.execute_prepared_projection_terminal_output(
PreparedFluentProjectionStrategy::first_value_by_slot(target_slot),
)?
.into_terminal_value()
.map_err(QueryError::execute)?;
Self::project_terminal_optional_value(projection, value)
})
}
pub fn explain_first_value_by(
&self,
field: impl AsRef<str>,
) -> Result<ExplainExecutionNodeDescriptor, QueryError>
where
E: EntityValue,
{
self.ensure_non_paged_mode_ready()?;
Self::with_slot(field, |target_slot| {
self.explain_prepared_projection_non_paged_terminal(
&PreparedFluentProjectionStrategy::first_value_by_slot(target_slot),
)
})
}
pub fn last_value_by(&self, field: impl AsRef<str>) -> Result<Option<Value>, QueryError>
where
E: EntityValue,
{
self.ensure_non_paged_mode_ready()?;
Self::with_slot(field, |target_slot| {
self.execute_prepared_projection_terminal_output(
PreparedFluentProjectionStrategy::last_value_by_slot(target_slot),
)?
.into_terminal_value()
.map_err(QueryError::execute)
})
}
pub fn project_last_value(
&self,
projection: &TextProjectionExpr,
) -> Result<Option<Value>, QueryError>
where
E: EntityValue,
{
self.ensure_non_paged_mode_ready()?;
Self::with_slot(projection.field(), |target_slot| {
let value = self
.execute_prepared_projection_terminal_output(
PreparedFluentProjectionStrategy::last_value_by_slot(target_slot),
)?
.into_terminal_value()
.map_err(QueryError::execute)?;
Self::project_terminal_optional_value(projection, value)
})
}
pub fn explain_last_value_by(
&self,
field: impl AsRef<str>,
) -> Result<ExplainExecutionNodeDescriptor, QueryError>
where
E: EntityValue,
{
self.ensure_non_paged_mode_ready()?;
Self::with_slot(field, |target_slot| {
self.explain_prepared_projection_non_paged_terminal(
&PreparedFluentProjectionStrategy::last_value_by_slot(target_slot),
)
})
}
pub fn first(&self) -> Result<Option<Id<E>>, QueryError>
where
E: EntityValue,
{
self.execute_prepared_order_sensitive_terminal_output(
PreparedFluentOrderSensitiveTerminalStrategy::first(),
)?
.into_id()
.map_err(QueryError::execute)
}
pub fn explain_first(&self) -> Result<ExplainAggregateTerminalPlan, QueryError>
where
E: EntityValue,
{
self.explain_prepared_aggregate_non_paged_terminal(
&PreparedFluentOrderSensitiveTerminalStrategy::first(),
)
}
pub fn last(&self) -> Result<Option<Id<E>>, QueryError>
where
E: EntityValue,
{
self.execute_prepared_order_sensitive_terminal_output(
PreparedFluentOrderSensitiveTerminalStrategy::last(),
)?
.into_id()
.map_err(QueryError::execute)
}
pub fn explain_last(&self) -> Result<ExplainAggregateTerminalPlan, QueryError>
where
E: EntityValue,
{
self.explain_prepared_aggregate_non_paged_terminal(
&PreparedFluentOrderSensitiveTerminalStrategy::last(),
)
}
pub fn require_one(&self) -> Result<(), QueryError>
where
E: EntityValue,
{
self.execute()?.into_rows()?.require_one()?;
Ok(())
}
pub fn require_some(&self) -> Result<(), QueryError>
where
E: EntityValue,
{
self.execute()?.into_rows()?.require_some()?;
Ok(())
}
}
fn scalar_terminal_boundary_request_from_prepared(
request: PreparedFluentScalarTerminalRuntimeRequest,
) -> ScalarTerminalBoundaryRequest {
match request {
PreparedFluentScalarTerminalRuntimeRequest::IdTerminal { kind } => {
ScalarTerminalBoundaryRequest::IdTerminal { kind }
}
PreparedFluentScalarTerminalRuntimeRequest::IdBySlot { kind, target_field } => {
ScalarTerminalBoundaryRequest::IdBySlot { kind, target_field }
}
}
}
const fn existing_rows_terminal_boundary_request_from_prepared(
request: PreparedFluentExistingRowsTerminalRuntimeRequest,
) -> ScalarTerminalBoundaryRequest {
match request {
PreparedFluentExistingRowsTerminalRuntimeRequest::CountRows => {
ScalarTerminalBoundaryRequest::Count
}
PreparedFluentExistingRowsTerminalRuntimeRequest::ExistsRows => {
ScalarTerminalBoundaryRequest::Exists
}
}
}
const fn numeric_field_boundary_request_from_prepared(
request: PreparedFluentNumericFieldRuntimeRequest,
) -> ScalarNumericFieldBoundaryRequest {
match request {
PreparedFluentNumericFieldRuntimeRequest::Sum => ScalarNumericFieldBoundaryRequest::Sum,
PreparedFluentNumericFieldRuntimeRequest::SumDistinct => {
ScalarNumericFieldBoundaryRequest::SumDistinct
}
PreparedFluentNumericFieldRuntimeRequest::Avg => ScalarNumericFieldBoundaryRequest::Avg,
PreparedFluentNumericFieldRuntimeRequest::AvgDistinct => {
ScalarNumericFieldBoundaryRequest::AvgDistinct
}
}
}
fn order_sensitive_terminal_boundary_request_from_prepared(
request: PreparedFluentOrderSensitiveTerminalRuntimeRequest,
) -> ScalarTerminalBoundaryRequest {
match request {
PreparedFluentOrderSensitiveTerminalRuntimeRequest::ResponseOrder { kind } => {
ScalarTerminalBoundaryRequest::IdTerminal { kind }
}
PreparedFluentOrderSensitiveTerminalRuntimeRequest::NthBySlot { target_field, nth } => {
ScalarTerminalBoundaryRequest::NthBySlot { target_field, nth }
}
PreparedFluentOrderSensitiveTerminalRuntimeRequest::MedianBySlot { target_field } => {
ScalarTerminalBoundaryRequest::MedianBySlot { target_field }
}
PreparedFluentOrderSensitiveTerminalRuntimeRequest::MinMaxBySlot { target_field } => {
ScalarTerminalBoundaryRequest::MinMaxBySlot { target_field }
}
}
}
const fn projection_boundary_request_from_prepared(
request: PreparedFluentProjectionRuntimeRequest,
) -> ScalarProjectionBoundaryRequest {
match request {
PreparedFluentProjectionRuntimeRequest::Values => ScalarProjectionBoundaryRequest::Values,
PreparedFluentProjectionRuntimeRequest::DistinctValues => {
ScalarProjectionBoundaryRequest::DistinctValues
}
PreparedFluentProjectionRuntimeRequest::CountDistinct => {
ScalarProjectionBoundaryRequest::CountDistinct
}
PreparedFluentProjectionRuntimeRequest::ValuesWithIds => {
ScalarProjectionBoundaryRequest::ValuesWithIds
}
PreparedFluentProjectionRuntimeRequest::TerminalValue { terminal_kind } => {
ScalarProjectionBoundaryRequest::TerminalValue { terminal_kind }
}
}
}