pub(crate) mod access;
pub(crate) mod contracts;
pub(crate) mod cursor;
pub(crate) mod diagnostics;
pub(crate) mod identity;
#[cfg(feature = "diagnostics")]
pub(crate) mod physical_access;
pub(crate) mod predicate;
pub(crate) mod query;
pub(crate) mod registry;
pub(crate) mod response;
pub(crate) mod scalar_expr;
pub(crate) mod schema;
pub(crate) mod session;
#[cfg(feature = "sql")]
pub(crate) mod sql;
pub(in crate::db) mod codec;
pub(in crate::db) mod commit;
pub(in crate::db) mod data;
pub(in crate::db) mod direction;
pub(in crate::db) mod executor;
pub(in crate::db) mod index;
pub(in crate::db) mod migration;
pub(in crate::db) mod numeric;
pub(in crate::db) mod relation;
pub(in crate::db) mod sql_shared;
use crate::{
db::{
commit::{CommitRowOp, PreparedRowCommitOp, ensure_recovered},
data::RawDataKey,
executor::Context,
registry::StoreHandle,
relation::model_has_strong_relations_to_target,
},
error::InternalError,
traits::{CanisterKind, EntityKind, EntityValue},
types::EntityTag,
};
use std::{collections::BTreeSet, marker::PhantomData, thread::LocalKey};
pub use codec::cursor::{decode_cursor, encode_cursor};
pub use commit::EntityRuntimeHooks;
pub use data::{
DataStore, PersistedRow, PersistedScalar, ScalarSlotValueRef, ScalarValueRef, SlotReader,
SlotWriter, UpdatePatch, decode_persisted_custom_many_slot_payload,
decode_persisted_custom_slot_payload, decode_persisted_non_null_slot_payload_by_kind,
decode_persisted_option_scalar_slot_payload, decode_persisted_option_slot_payload_by_kind,
decode_persisted_option_slot_payload_by_meta, decode_persisted_scalar_slot_payload,
decode_persisted_slot_payload_by_kind, decode_persisted_slot_payload_by_meta,
encode_persisted_custom_many_slot_payload, encode_persisted_custom_slot_payload,
encode_persisted_option_scalar_slot_payload, encode_persisted_option_slot_payload_by_meta,
encode_persisted_scalar_slot_payload, encode_persisted_slot_payload_by_kind,
encode_persisted_slot_payload_by_meta,
};
#[cfg(feature = "diagnostics")]
#[doc(hidden)]
pub use data::{StructuralReadMetrics, with_structural_read_metrics};
#[cfg(all(test, not(feature = "diagnostics")))]
#[expect(unused_imports)]
pub(crate) use data::{StructuralReadMetrics, with_structural_read_metrics};
pub use diagnostics::{
ExecutionAccessPathVariant, ExecutionMetrics, ExecutionOptimization, ExecutionTrace,
IntegrityReport, IntegrityStoreSnapshot, IntegrityTotals, StorageReport,
};
#[doc(hidden)]
pub use executor::EntityAuthority;
pub use executor::MutationMode;
pub use executor::{ExecutionFamily, RouteExecutionMode};
#[cfg(feature = "diagnostics")]
#[doc(hidden)]
pub use executor::{RowCheckMetrics, with_row_check_metrics};
#[cfg(all(test, not(feature = "diagnostics")))]
#[expect(unused_imports)]
pub(crate) use executor::{RowCheckMetrics, with_row_check_metrics};
#[cfg(feature = "diagnostics")]
#[doc(hidden)]
pub use executor::{ScalarMaterializationLaneMetrics, with_scalar_materialization_lane_metrics};
#[cfg(all(test, not(feature = "diagnostics")))]
#[expect(unused_imports)]
pub(crate) use executor::{
ScalarMaterializationLaneMetrics, with_scalar_materialization_lane_metrics,
};
pub use identity::{EntityName, IndexName};
pub use index::{IndexState, IndexStore};
pub use migration::{
MigrationCursor, MigrationPlan, MigrationRowOp, MigrationRunOutcome, MigrationRunState,
MigrationStep,
};
pub use predicate::{
CoercionId, CompareFieldsPredicate, CompareOp, ComparePredicate, MissingRowPolicy, Predicate,
UnsupportedQueryFeature,
};
#[doc(hidden)]
pub use predicate::{
parse_generated_index_predicate_sql, validate_generated_index_predicate_fields,
};
pub use query::{
api::ResponseCardinalityExt,
builder::{
AggregateExpr, FieldRef, NumericProjectionExpr, RoundProjectionExpr, TextProjectionExpr,
ValueProjectionExpr, add, avg, contains, count, count_by, div, ends_with, exists, first,
last, left, length, lower, ltrim, max, max_by, min, min_by, mul, position, replace, right,
round, round_expr, rtrim, starts_with, sub, substring, substring_with_length, sum, trim,
upper,
},
explain::{
ExplainAggregateTerminalPlan, ExplainExecutionDescriptor, ExplainExecutionMode,
ExplainExecutionNodeDescriptor, ExplainExecutionNodeType, ExplainExecutionOrderingSource,
ExplainPlan,
},
expr::{FilterExpr, OrderExpr, OrderTerm, asc, desc, field},
fluent::{
delete::FluentDeleteQuery,
load::{FluentLoadQuery, LoadQueryResult, PagedLoadQuery},
},
intent::{CompiledQuery, IntentError, PlannedQuery, Query, QueryError, QueryExecutionError},
plan::{DeleteSpec, LoadSpec, OrderDirection, PlanError, QueryMode},
trace::{QueryTracePlan, TraceExecutionFamily},
};
pub use registry::StoreRegistry;
pub use response::{
EntityResponse, GroupedRow, PagedGroupedExecution, PagedGroupedExecutionWithTrace,
PagedLoadExecution, PagedLoadExecutionWithTrace, ProjectedRow, ProjectionResponse,
Response as RowResponse, ResponseError, ResponseRow, Row, WriteBatchResponse,
};
pub use schema::{
EntityFieldDescription, EntityIndexDescription, EntityRelationCardinality,
EntityRelationDescription, EntityRelationStrength, EntitySchemaDescription, ValidateError,
};
#[cfg(not(feature = "sql"))]
pub use session::DbSession;
#[cfg(feature = "diagnostics")]
pub use session::QueryExecutionAttribution;
#[cfg(all(feature = "sql", feature = "diagnostics"))]
pub use session::SqlQueryExecutionAttribution;
#[cfg(feature = "sql")]
pub use session::{DbSession, SqlStatementResult};
#[cfg(all(feature = "sql", feature = "diagnostics"))]
#[doc(hidden)]
pub use session::{
SqlProjectionMaterializationMetrics, with_sql_projection_materialization_metrics,
};
#[cfg(feature = "sql")]
pub use sql::identifier::{
identifier_last_segment, identifiers_tail_match, normalize_identifier_to_scope,
split_qualified_identifier,
};
#[cfg(feature = "sql")]
pub use sql::lowering::LoweredSqlCommand;
pub(crate) struct Db<C: CanisterKind> {
store: &'static LocalKey<StoreRegistry>,
entity_runtime_hooks: &'static [EntityRuntimeHooks<C>],
_marker: PhantomData<C>,
}
impl<C: CanisterKind> Db<C> {
#[must_use]
#[cfg(test)]
pub(crate) const fn new(store: &'static LocalKey<StoreRegistry>) -> Self {
Self::new_with_hooks(store, &[])
}
#[must_use]
pub(crate) const fn new_with_hooks(
store: &'static LocalKey<StoreRegistry>,
entity_runtime_hooks: &'static [EntityRuntimeHooks<C>],
) -> Self {
#[cfg(debug_assertions)]
{
let _ = crate::db::commit::debug_assert_unique_runtime_hook_tags(entity_runtime_hooks);
}
Self {
store,
entity_runtime_hooks,
_marker: PhantomData,
}
}
#[must_use]
pub(in crate::db) const fn context<E>(&self) -> Context<'_, E>
where
E: EntityKind<Canister = C> + EntityValue,
{
Context::new(self)
}
pub(in crate::db) fn recovered_store(&self, path: &str) -> Result<StoreHandle, InternalError> {
ensure_recovered(self)?;
self.store_handle(path)
}
fn store_handle(&self, path: &str) -> Result<StoreHandle, InternalError> {
self.with_store_registry(|registry| registry.try_get_store(path))
}
pub(crate) fn ensure_recovered_state(&self) -> Result<(), InternalError> {
ensure_recovered(self)
}
pub(crate) fn with_store_registry<R>(&self, f: impl FnOnce(&StoreRegistry) -> R) -> R {
self.store.with(|reg| f(reg))
}
#[must_use]
pub(in crate::db) fn cache_scope_id(&self) -> usize {
std::ptr::from_ref::<LocalKey<StoreRegistry>>(self.store) as usize
}
#[must_use]
pub(in crate::db) fn store_resolver(&self) -> executor::StoreResolver<'_> {
executor::StoreResolver::new(self)
}
pub(in crate::db) fn mark_all_registered_index_stores_ready(&self) {
self.with_store_registry(|registry| {
for (_, handle) in registry.iter() {
handle.mark_index_ready();
}
});
}
pub(crate) fn storage_report(
&self,
name_to_path: &[(&'static str, &'static str)],
) -> Result<StorageReport, InternalError> {
diagnostics::storage_report(self, name_to_path)
}
pub(crate) fn storage_report_default(&self) -> Result<StorageReport, InternalError> {
diagnostics::storage_report_default(self)
}
pub(crate) fn integrity_report(&self) -> Result<IntegrityReport, InternalError> {
diagnostics::integrity_report(self)
}
pub(in crate::db) fn prepare_row_commit_op(
&self,
op: &CommitRowOp,
) -> Result<PreparedRowCommitOp, InternalError> {
let hooks = self.runtime_hook_for_entity_path(op.entity_path.as_ref())?;
let store = self.store_handle(hooks.store_path)?;
(hooks.prepare_row_commit_with_readers)(self, op, &store, &store)
}
pub(crate) fn execute_migration_plan(
&self,
plan: &migration::MigrationPlan,
max_steps: usize,
) -> Result<migration::MigrationRunOutcome, InternalError> {
migration::execute_migration_plan(self, plan, max_steps)
}
pub(crate) fn validate_delete_strong_relations(
&self,
target_path: &str,
deleted_target_keys: &BTreeSet<RawDataKey>,
) -> Result<(), InternalError> {
if deleted_target_keys.is_empty() {
return Ok(());
}
for hooks in self.entity_runtime_hooks {
if !model_has_strong_relations_to_target(hooks.model, target_path) {
continue;
}
(hooks.validate_delete_strong_relations)(self, target_path, deleted_target_keys)?;
}
Ok(())
}
}
impl<C: CanisterKind> Db<C> {
#[must_use]
pub(crate) const fn has_runtime_hooks(&self) -> bool {
commit::has_runtime_hooks(self.entity_runtime_hooks)
}
#[must_use]
pub(crate) fn runtime_entity_names(&self) -> Vec<String> {
self.entity_runtime_hooks
.iter()
.map(|hooks| hooks.model.name().to_string())
.collect()
}
pub(crate) fn runtime_hook_for_entity_tag(
&self,
entity_tag: EntityTag,
) -> Result<&EntityRuntimeHooks<C>, InternalError> {
commit::resolve_runtime_hook_by_tag(self.entity_runtime_hooks, entity_tag)
}
pub(crate) fn runtime_hook_for_entity_path(
&self,
entity_path: &str,
) -> Result<&EntityRuntimeHooks<C>, InternalError> {
commit::resolve_runtime_hook_by_path(self.entity_runtime_hooks, entity_path)
}
}
impl<C: CanisterKind> Copy for Db<C> {}
impl<C: CanisterKind> Clone for Db<C> {
fn clone(&self) -> Self {
*self
}
}