use crate::{
db::{
access::{AccessPlanError, validate_access_structure_model},
cursor::{CursorPlanError, PlannedCursor},
data::StorageKey,
executor::terminal::RowLayout,
index::IndexKey,
query::plan::{
AccessPlannedQuery, CoveringReadExecutionPlan, PlannedContinuationContract,
covering_read_execution_plan_from_fields,
},
relation::model_has_strong_relation_targets,
schema::SchemaInfo,
},
error::InternalError,
model::{entity::EntityModel, field::FieldModel, index::IndexModel},
traits::{EntityKind, Path},
types::EntityTag,
value::Value,
};
#[derive(Clone, Copy, Debug)]
pub struct EntityAuthority {
model: &'static EntityModel,
row_layout: RowLayout,
primary_key_name: &'static str,
entity_tag: EntityTag,
store_path: &'static str,
}
impl EntityAuthority {
#[must_use]
pub const fn new(
model: &'static EntityModel,
entity_tag: EntityTag,
store_path: &'static str,
) -> Self {
Self {
model,
row_layout: RowLayout::from_model(model),
primary_key_name: model.primary_key.name,
entity_tag,
store_path,
}
}
#[must_use]
pub const fn for_type<E: EntityKind>() -> Self {
Self::new(E::MODEL, E::ENTITY_TAG, E::Store::PATH)
}
#[must_use]
pub const fn model(&self) -> &'static EntityModel {
self.model
}
#[must_use]
pub(in crate::db) fn schema_info(&self) -> &'static SchemaInfo {
SchemaInfo::cached_for_entity_model(self.model)
}
#[must_use]
pub(in crate::db) const fn fields(&self) -> &'static [FieldModel] {
self.model.fields()
}
#[must_use]
pub(in crate::db) const fn row_layout(&self) -> RowLayout {
self.row_layout
}
#[must_use]
pub const fn primary_key_name(&self) -> &'static str {
self.primary_key_name
}
#[must_use]
pub const fn entity_tag(&self) -> EntityTag {
self.entity_tag
}
#[must_use]
pub const fn entity_path(&self) -> &'static str {
self.model.path()
}
#[must_use]
pub const fn store_path(&self) -> &'static str {
self.store_path
}
pub(in crate::db) fn finalize_static_planning_shape(self, plan: &mut AccessPlannedQuery) {
plan.finalize_static_planning_shape_for_model(self.model)
.expect("executable plan core requires planner-frozen static execution shape");
}
pub(in crate::db::executor) fn finalize_planner_route_profile(
self,
plan: &mut AccessPlannedQuery,
) {
plan.finalize_planner_route_profile_for_model(self.model);
}
pub(in crate::db::executor) fn validate_executor_plan(
self,
plan: &AccessPlannedQuery,
) -> Result<(), InternalError> {
validate_access_structure_model(self.schema_info(), self.model, &plan.access)
.map_err(AccessPlanError::into_internal_error)
}
pub(in crate::db::executor) fn prepare_scalar_cursor(
self,
contract: &PlannedContinuationContract,
bytes: Option<&[u8]>,
) -> Result<PlannedCursor, CursorPlanError> {
contract.prepare_scalar_cursor(self.entity_path(), self.entity_tag, self.model, bytes)
}
pub(in crate::db::executor) fn revalidate_scalar_cursor(
self,
contract: &PlannedContinuationContract,
cursor: PlannedCursor,
) -> Result<PlannedCursor, CursorPlanError> {
contract.revalidate_scalar_cursor(self.entity_tag, self.model, cursor)
}
#[must_use]
pub(in crate::db::executor) fn covering_read_execution_plan(
self,
plan: &AccessPlannedQuery,
strict_predicate_compatible: bool,
) -> Option<CoveringReadExecutionPlan> {
covering_read_execution_plan_from_fields(
self.fields(),
plan,
self.primary_key_name,
strict_predicate_compatible,
)
}
#[must_use]
pub(in crate::db::executor) fn has_strong_relation_targets(self) -> bool {
model_has_strong_relation_targets(self.model)
}
pub(in crate::db::executor) fn index_key_from_slot_ref_reader<'a>(
self,
storage_key: StorageKey,
index: &IndexModel,
read_slot: &mut dyn FnMut(usize) -> Option<&'a Value>,
) -> Result<Option<IndexKey>, InternalError> {
IndexKey::new_from_slot_ref_reader(
self.entity_tag,
storage_key,
self.model,
index,
read_slot,
)
}
}