#[cfg(test)]
use crate::{
db::query::plan::expr::projection_field_expr,
db::response::ProjectedRow,
traits::{EntityKind, EntityValue},
types::Id,
};
use crate::{
db::query::plan::{
AccessPlannedQuery,
expr::{ProjectionSpec, projection_field_direct_field_name},
},
error::InternalError,
model::entity::{EntityModel, resolve_field_slot},
value::Value,
};
use std::borrow::Cow;
#[cfg(test)]
use crate::db::executor::projection::eval::eval_scalar_projection_expr_with_value_reader;
use crate::db::executor::projection::eval::{
ProjectionEvalError, ScalarProjectionExpr,
eval_canonical_scalar_projection_expr_with_required_value_reader_cow,
eval_scalar_projection_expr_with_value_ref_reader,
};
#[cfg(test)]
use crate::db::query::plan::expr::compile_scalar_projection_expr;
#[derive(Debug)]
pub(in crate::db) enum PreparedProjectionPlan {
Scalar(Vec<ScalarProjectionExpr>),
}
#[derive(Debug)]
pub(in crate::db) struct PreparedProjectionShape {
projection: ProjectionSpec,
prepared: PreparedProjectionPlan,
projection_is_model_identity: bool,
retained_slot_direct_projection_field_slots: Option<Vec<(String, usize)>>,
data_row_direct_projection_field_slots: Option<Vec<(String, usize)>>,
#[cfg(any(test, feature = "diagnostics"))]
projected_slot_mask: Vec<bool>,
}
impl PreparedProjectionShape {
#[must_use]
pub(in crate::db) const fn projection(&self) -> &ProjectionSpec {
&self.projection
}
#[must_use]
pub(in crate::db) const fn prepared(&self) -> &PreparedProjectionPlan {
&self.prepared
}
#[must_use]
pub(in crate::db) const fn scalar_projection_exprs(&self) -> &[ScalarProjectionExpr] {
let PreparedProjectionPlan::Scalar(compiled_fields) = self.prepared();
compiled_fields.as_slice()
}
#[must_use]
pub(in crate::db::executor) const fn projection_is_model_identity(&self) -> bool {
self.projection_is_model_identity
}
#[must_use]
pub(in crate::db) fn retained_slot_direct_projection_field_slots(
&self,
) -> Option<&[(String, usize)]> {
self.retained_slot_direct_projection_field_slots.as_deref()
}
#[must_use]
pub(in crate::db) fn data_row_direct_projection_field_slots(
&self,
) -> Option<&[(String, usize)]> {
self.data_row_direct_projection_field_slots.as_deref()
}
#[cfg(any(test, feature = "diagnostics"))]
#[must_use]
pub(in crate::db) const fn projected_slot_mask(&self) -> &[bool] {
self.projected_slot_mask.as_slice()
}
#[cfg(test)]
#[must_use]
pub(in crate::db) const fn from_test_parts(
projection: ProjectionSpec,
prepared: PreparedProjectionPlan,
projection_is_model_identity: bool,
retained_slot_direct_projection_field_slots: Option<Vec<(String, usize)>>,
data_row_direct_projection_field_slots: Option<Vec<(String, usize)>>,
projected_slot_mask: Vec<bool>,
) -> Self {
Self {
projection,
prepared,
projection_is_model_identity,
retained_slot_direct_projection_field_slots,
data_row_direct_projection_field_slots,
projected_slot_mask,
}
}
}
pub(in crate::db::executor) type PreparedSlotProjectionValidation = PreparedProjectionShape;
pub(in crate::db::executor) trait ProjectionValidationRow {
#[must_use]
fn projection_validation_slot_value(&self, slot: usize) -> Option<&Value>;
}
#[must_use]
pub(in crate::db) fn prepare_projection_shape_from_plan(
model: &'static EntityModel,
plan: &AccessPlannedQuery,
) -> PreparedProjectionShape {
let projection = plan.frozen_projection_spec().clone();
let prepared = PreparedProjectionPlan::Scalar(
plan.scalar_projection_plan()
.expect(
"scalar execution projection shapes must carry one planner-compiled scalar program",
)
.to_vec(),
);
let retained_slot_direct_projection_field_slots =
retained_slot_direct_projection_field_slots_from_projection(
&projection,
plan.frozen_direct_projection_slots(),
);
let data_row_direct_projection_field_slots =
data_row_direct_projection_field_slots_from_projection(model, &projection);
#[cfg(any(test, feature = "diagnostics"))]
let projected_slot_mask =
projected_slot_mask_from_slots(model.fields().len(), plan.projected_slot_mask());
PreparedProjectionShape {
projection,
prepared,
projection_is_model_identity: plan.projection_is_model_identity(),
retained_slot_direct_projection_field_slots,
data_row_direct_projection_field_slots,
#[cfg(any(test, feature = "diagnostics"))]
projected_slot_mask,
}
}
pub(in crate::db::executor) fn validate_prepared_projection_row(
prepared_validation: &PreparedSlotProjectionValidation,
row: &impl ProjectionValidationRow,
) -> Result<(), InternalError> {
if prepared_validation.projection_is_model_identity() {
return Ok(());
}
let PreparedProjectionPlan::Scalar(compiled_fields) = prepared_validation.prepared();
for compiled in compiled_fields {
let mut read_slot = |slot| row.projection_validation_slot_value(slot);
eval_scalar_projection_expr_with_value_ref_reader(compiled, &mut read_slot)
.map_err(ProjectionEvalError::into_invalid_logical_plan_internal_error)?;
}
Ok(())
}
fn retained_slot_direct_projection_field_slots_from_projection(
projection: &ProjectionSpec,
direct_projection_slots: Option<&[usize]>,
) -> Option<Vec<(String, usize)>> {
let direct_projection_slots = direct_projection_slots?;
let mut field_slots = Vec::with_capacity(direct_projection_slots.len());
for (field, slot) in projection
.fields()
.zip(direct_projection_slots.iter().copied())
{
let field_name = projection_field_direct_field_name(field)?;
field_slots.push((field_name.to_string(), slot));
}
Some(field_slots)
}
fn data_row_direct_projection_field_slots_from_projection(
model: &EntityModel,
projection: &ProjectionSpec,
) -> Option<Vec<(String, usize)>> {
let mut field_slots = Vec::with_capacity(projection.len());
for field in projection.fields() {
let field_name = projection_field_direct_field_name(field)?;
let slot = resolve_field_slot(model, field_name)?;
field_slots.push((field_name.to_string(), slot));
}
Some(field_slots)
}
#[cfg(any(test, feature = "diagnostics"))]
fn projected_slot_mask_from_slots(field_count: usize, projected_slots: &[bool]) -> Vec<bool> {
let mut mask = vec![false; field_count];
for (slot, projected) in projected_slots.iter().copied().enumerate() {
if projected && let Some(entry) = mask.get_mut(slot) {
*entry = true;
}
}
mask
}
#[cfg(test)]
pub(in crate::db::executor::projection) fn project_rows_from_projection<E>(
projection: &ProjectionSpec,
rows: &[(Id<E>, E)],
) -> Result<Vec<ProjectedRow<E>>, ProjectionEvalError>
where
E: EntityKind + EntityValue,
{
let mut compiled_fields = Vec::with_capacity(projection.len());
for field in projection.fields() {
let compiled = compile_scalar_projection_expr(E::MODEL, projection_field_expr(field))
.expect(
"test projection materialization helpers require scalar-compilable expressions",
);
compiled_fields.push(compiled);
}
let prepared = PreparedProjectionPlan::Scalar(compiled_fields);
let mut projected_rows = Vec::with_capacity(rows.len());
for (id, entity) in rows {
let mut values = Vec::with_capacity(projection.len());
let mut read_slot = |slot| entity.get_value_by_index(slot);
visit_prepared_projection_values_with_value_reader(
&prepared,
&mut read_slot,
&mut |value| values.push(value),
)?;
projected_rows.push(ProjectedRow::new(*id, values));
}
Ok(projected_rows)
}
#[cfg(test)]
pub(super) fn visit_prepared_projection_values_with_value_reader(
prepared: &PreparedProjectionPlan,
read_slot: &mut dyn FnMut(usize) -> Option<Value>,
on_value: &mut dyn FnMut(Value),
) -> Result<(), ProjectionEvalError> {
let PreparedProjectionPlan::Scalar(compiled_fields) = prepared;
for compiled in compiled_fields {
on_value(eval_scalar_projection_expr_with_value_reader(
compiled, read_slot,
)?);
}
Ok(())
}
pub(in crate::db) fn visit_prepared_projection_values_with_required_value_reader_cow<'a>(
prepared: &'a PreparedProjectionPlan,
read_slot: &mut dyn FnMut(usize) -> Result<Cow<'a, Value>, InternalError>,
on_value: &mut dyn FnMut(Value),
) -> Result<(), InternalError> {
let PreparedProjectionPlan::Scalar(compiled_fields) = prepared;
for compiled in compiled_fields {
on_value(
eval_canonical_scalar_projection_expr_with_required_value_reader_cow(
compiled, read_slot,
)?
.into_owned(),
);
}
Ok(())
}