1pub(crate) mod access;
8pub(crate) mod cursor;
9pub(crate) mod diagnostics;
10pub(crate) mod identity;
11#[cfg(feature = "diagnostics")]
12pub(crate) mod physical_access;
13pub(crate) mod predicate;
14pub(crate) mod query;
15pub(crate) mod registry;
16pub(crate) mod response;
17pub(crate) mod runtime_hooks;
18pub(crate) mod scalar_expr;
19pub(crate) mod schema;
20pub(crate) mod session;
21#[cfg(feature = "sql")]
22pub(crate) mod sql;
23
24pub(in crate::db) mod codec;
25pub(in crate::db) mod commit;
26pub(in crate::db) mod data;
27pub(in crate::db) mod direction;
28pub(in crate::db) mod executor;
29pub(in crate::db) mod index;
30pub(in crate::db) mod numeric;
31pub(in crate::db) mod relation;
32pub(in crate::db) mod sql_shared;
33#[cfg(test)]
34mod tests;
35
36use crate::{
37 db::{
38 commit::{CommitRowOp, PreparedRowCommitOp, ensure_recovered},
39 data::RawDataKey,
40 executor::Context,
41 registry::StoreHandle,
42 },
43 error::InternalError,
44 traits::{CanisterKind, EntityKind, EntityValue},
45 types::EntityTag,
46};
47use std::{collections::BTreeSet, marker::PhantomData, thread::LocalKey};
48
49#[doc(hidden)]
50pub use codec::hex::encode_hex_lower;
51pub use cursor::{decode_cursor, encode_cursor};
52pub use runtime_hooks::EntityRuntimeHooks;
53pub use data::{DataStore, PersistedRow, SlotReader, SlotWriter, StructuralPatch};
57#[doc(hidden)]
58pub use data::{
59 PersistedScalar, ScalarSlotValueRef, ScalarValueRef,
60 decode_persisted_many_slot_payload_by_meta, decode_persisted_option_scalar_slot_payload,
61 decode_persisted_option_slot_payload_by_kind, decode_persisted_option_slot_payload_by_meta,
62 decode_persisted_scalar_slot_payload, decode_persisted_slot_payload_by_kind,
63 decode_persisted_slot_payload_by_meta, decode_persisted_structured_many_slot_payload,
64 decode_persisted_structured_slot_payload, decode_slot_into_runtime_value,
65 encode_persisted_many_slot_payload_by_meta, encode_persisted_option_scalar_slot_payload,
66 encode_persisted_option_slot_payload_by_meta, encode_persisted_scalar_slot_payload,
67 encode_persisted_slot_payload_by_kind, encode_persisted_slot_payload_by_meta,
68 encode_persisted_structured_many_slot_payload, encode_persisted_structured_slot_payload,
69 encode_runtime_value_into_slot,
70};
71#[cfg(feature = "diagnostics")]
72#[doc(hidden)]
73pub use data::{StructuralReadMetrics, with_structural_read_metrics};
74#[cfg(all(test, not(feature = "diagnostics")))]
75#[expect(unused_imports)]
76pub(crate) use data::{StructuralReadMetrics, with_structural_read_metrics};
77pub use diagnostics::{
78 DataStoreSnapshot, EntitySnapshot, ExecutionAccessPathVariant, ExecutionMetrics,
79 ExecutionOptimization, ExecutionStats, ExecutionTrace, IndexStoreSnapshot, IntegrityReport,
80 IntegrityStoreSnapshot, IntegrityTotals, StorageReport,
81};
82#[doc(hidden)]
83pub use executor::EntityAuthority;
84pub use executor::MutationMode;
85pub use executor::{ExecutionFamily, RouteExecutionMode};
86#[cfg(feature = "diagnostics")]
87#[doc(hidden)]
88pub use executor::{RowCheckMetrics, with_row_check_metrics};
89#[cfg(all(test, not(feature = "diagnostics")))]
90#[expect(unused_imports)]
91pub(crate) use executor::{RowCheckMetrics, with_row_check_metrics};
92#[cfg(feature = "diagnostics")]
93#[doc(hidden)]
94pub use executor::{ScalarMaterializationLaneMetrics, with_scalar_materialization_lane_metrics};
95#[cfg(all(test, not(feature = "diagnostics")))]
96#[expect(unused_imports)]
97pub(crate) use executor::{
98 ScalarMaterializationLaneMetrics, with_scalar_materialization_lane_metrics,
99};
100pub use identity::{EntityName, IndexName};
101pub use index::{IndexState, IndexStore};
102pub use predicate::{
103 CoercionId, CompareFieldsPredicate, CompareOp, ComparePredicate, MissingRowPolicy, Predicate,
104 UnsupportedQueryFeature,
105};
106#[doc(hidden)]
107pub use predicate::{
108 parse_generated_index_predicate_sql, validate_generated_index_predicate_fields,
109};
110pub use query::{
111 api::ResponseCardinalityExt,
112 builder::{
113 AggregateExpr, FieldRef, NumericProjectionExpr, RoundProjectionExpr, TextProjectionExpr,
114 ValueProjectionExpr, add, avg, contains, count, count_by, div, ends_with, exists, first,
115 last, left, length, lower, ltrim, max, max_by, min, min_by, mul, position, replace, right,
116 round, round_expr, rtrim, starts_with, sub, substring, substring_with_length, sum, trim,
117 upper,
118 },
119 explain::{
120 ExplainAggregateTerminalPlan, ExplainExecutionDescriptor, ExplainExecutionMode,
121 ExplainExecutionNodeDescriptor, ExplainExecutionNodeType, ExplainExecutionOrderingSource,
122 ExplainPlan,
123 },
124 expr::{FilterExpr, FilterValue, OrderExpr, OrderTerm, asc, desc, field},
125 fluent::{
126 delete::FluentDeleteQuery,
127 load::{FluentLoadQuery, LoadQueryResult, PagedLoadQuery},
128 },
129 intent::{CompiledQuery, IntentError, PlannedQuery, Query, QueryError, QueryExecutionError},
130 plan::{DeleteSpec, LoadSpec, OrderDirection, PlanError, QueryMode},
131 trace::{QueryTracePlan, TraceExecutionFamily, TraceReuseArtifactClass, TraceReuseEvent},
132};
133pub use registry::StoreRegistry;
134pub use response::{
135 EntityResponse, GroupedRow, PagedGroupedExecution, PagedGroupedExecutionWithTrace,
136 PagedLoadExecution, PagedLoadExecutionWithTrace, ProjectedRow, ProjectionResponse,
137 Response as RowResponse, ResponseError, ResponseRow, Row, WriteBatchResponse,
138};
139pub use schema::{
140 EntityFieldDescription, EntityIndexDescription, EntityRelationCardinality,
141 EntityRelationDescription, EntityRelationStrength, EntitySchemaDescription, SchemaStore,
142 ValidateError,
143};
144#[cfg(not(feature = "sql"))]
145pub use session::DbSession;
146#[cfg(feature = "sql")]
147pub use session::{DbSession, SqlStatementResult};
148#[cfg(feature = "diagnostics")]
149pub use session::{
150 DirectDataRowAttribution, GroupedCountAttribution, GroupedExecutionAttribution,
151 QueryExecutionAttribution,
152};
153#[cfg(all(feature = "sql", feature = "diagnostics"))]
154pub use session::{
155 SqlCompileAttribution, SqlExecutionAttribution, SqlPureCoveringAttribution,
156 SqlQueryCacheAttribution, SqlQueryExecutionAttribution, SqlScalarAggregateAttribution,
157};
158#[cfg(all(feature = "sql", feature = "diagnostics"))]
159#[doc(hidden)]
160pub use session::{
161 SqlProjectionMaterializationMetrics, with_sql_projection_materialization_metrics,
162};
163#[cfg(feature = "sql")]
164pub use sql::identifier::{
165 identifier_last_segment, identifiers_tail_match, normalize_identifier_to_scope,
166 split_qualified_identifier,
167};
168#[cfg(feature = "sql")]
169pub use sql::lowering::LoweredSqlCommand;
170
171#[doc(hidden)]
173pub type GeneratedStructuralMapPayloadSlices<'a> = Vec<(&'a [u8], &'a [u8])>;
174
175#[doc(hidden)]
177pub type GeneratedStructuralEnumPayload<'a> = (String, Option<String>, Option<&'a [u8]>);
178
179#[doc(hidden)]
181#[must_use]
182pub(crate) fn encode_generated_structural_text_payload_bytes(value: &str) -> Vec<u8> {
183 data::encode_value_storage_text(value)
184}
185
186#[doc(hidden)]
188#[must_use]
189pub(crate) fn encode_generated_structural_list_payload_bytes(items: &[&[u8]]) -> Vec<u8> {
190 data::encode_value_storage_list_item_slices(items)
191}
192
193#[doc(hidden)]
195#[must_use]
196pub(crate) fn encode_generated_structural_map_payload_bytes(entries: &[(&[u8], &[u8])]) -> Vec<u8> {
197 data::encode_value_storage_map_entry_slices(entries)
198}
199
200#[doc(hidden)]
202#[must_use]
203pub(crate) fn encode_generated_structural_enum_payload_bytes(
204 variant: &str,
205 path: Option<&str>,
206 payload: Option<&[u8]>,
207) -> Vec<u8> {
208 data::encode_enum(variant, path, payload)
209}
210
211#[doc(hidden)]
213pub(crate) fn decode_generated_structural_text_payload_bytes(
214 raw_bytes: &[u8],
215) -> Result<String, InternalError> {
216 data::decode_value_storage_text(raw_bytes).map_err(InternalError::persisted_row_decode_failed)
217}
218
219#[doc(hidden)]
221pub(crate) fn decode_generated_structural_list_payload_bytes(
222 raw_bytes: &[u8],
223) -> Result<Vec<&[u8]>, InternalError> {
224 data::decode_value_storage_list_item_slices(raw_bytes)
225 .map_err(InternalError::persisted_row_decode_failed)
226}
227
228#[doc(hidden)]
230pub(crate) fn decode_generated_structural_map_payload_bytes(
231 raw_bytes: &[u8],
232) -> Result<GeneratedStructuralMapPayloadSlices<'_>, InternalError> {
233 data::decode_value_storage_map_entry_slices(raw_bytes)
234 .map_err(InternalError::persisted_row_decode_failed)
235}
236
237#[doc(hidden)]
239pub(crate) fn decode_generated_structural_enum_payload_bytes(
240 raw_bytes: &[u8],
241) -> Result<GeneratedStructuralEnumPayload<'_>, InternalError> {
242 data::decode_enum(raw_bytes).map_err(InternalError::persisted_row_decode_failed)
243}
244
245#[doc(hidden)]
247pub(crate) fn generated_persisted_structured_payload_decode_failed(
248 detail: impl std::fmt::Display,
249) -> InternalError {
250 InternalError::persisted_row_decode_failed(detail)
251}
252
253pub(crate) struct Db<C: CanisterKind> {
259 store: &'static LocalKey<StoreRegistry>,
260 entity_runtime_hooks: &'static [EntityRuntimeHooks<C>],
261 _marker: PhantomData<C>,
262}
263
264impl<C: CanisterKind> Db<C> {
265 #[must_use]
267 #[cfg(test)]
268 pub(crate) const fn new(store: &'static LocalKey<StoreRegistry>) -> Self {
269 Self::new_with_hooks(store, &[])
270 }
271
272 #[must_use]
274 pub(crate) const fn new_with_hooks(
275 store: &'static LocalKey<StoreRegistry>,
276 entity_runtime_hooks: &'static [EntityRuntimeHooks<C>],
277 ) -> Self {
278 #[cfg(debug_assertions)]
279 {
280 let _ = crate::db::runtime_hooks::debug_assert_unique_runtime_hook_tags(
281 entity_runtime_hooks,
282 );
283 }
284
285 Self {
286 store,
287 entity_runtime_hooks,
288 _marker: PhantomData,
289 }
290 }
291
292 #[must_use]
293 pub(in crate::db) const fn context<E>(&self) -> Context<'_, E>
294 where
295 E: EntityKind<Canister = C> + EntityValue,
296 {
297 Context::new(self)
298 }
299
300 pub(in crate::db) fn recovered_store(&self, path: &str) -> Result<StoreHandle, InternalError> {
302 ensure_recovered(self)?;
303
304 self.store_handle(path)
305 }
306
307 pub(in crate::db) fn store_handle(&self, path: &str) -> Result<StoreHandle, InternalError> {
313 self.with_store_registry(|registry| registry.try_get_store(path))
314 }
315
316 pub(crate) fn ensure_recovered_state(&self) -> Result<(), InternalError> {
318 ensure_recovered(self)
319 }
320
321 pub(crate) fn with_store_registry<R>(&self, f: impl FnOnce(&StoreRegistry) -> R) -> R {
323 self.store.with(|reg| f(reg))
324 }
325
326 #[must_use]
333 pub(in crate::db) fn cache_scope_id(&self) -> usize {
334 std::ptr::from_ref::<LocalKey<StoreRegistry>>(self.store) as usize
335 }
336
337 #[must_use]
339 pub(in crate::db) fn store_resolver(&self) -> executor::StoreResolver<'_> {
340 executor::StoreResolver::new(self)
341 }
342
343 pub(in crate::db) fn mark_all_registered_index_stores_ready(&self) {
348 self.with_store_registry(|registry| {
349 for (_, handle) in registry.iter() {
350 handle.mark_index_ready();
351 }
352 });
353 }
354
355 pub(crate) fn storage_report(
357 &self,
358 name_to_path: &[(&'static str, &'static str)],
359 ) -> Result<StorageReport, InternalError> {
360 diagnostics::storage_report(self, name_to_path)
361 }
362
363 pub(crate) fn storage_report_default(&self) -> Result<StorageReport, InternalError> {
365 diagnostics::storage_report_default(self)
366 }
367
368 pub(crate) fn integrity_report(&self) -> Result<IntegrityReport, InternalError> {
370 diagnostics::integrity_report(self)
371 }
372
373 pub(in crate::db) fn prepare_row_commit_op(
374 &self,
375 op: &CommitRowOp,
376 ) -> Result<PreparedRowCommitOp, InternalError> {
377 runtime_hooks::prepare_row_commit_with_hook(self, self.entity_runtime_hooks, op)
378 }
379
380 pub(crate) fn validate_delete_strong_relations(
382 &self,
383 target_path: &str,
384 deleted_target_keys: &BTreeSet<RawDataKey>,
385 ) -> Result<(), InternalError> {
386 runtime_hooks::validate_delete_strong_relations_with_hooks(
387 self,
388 self.entity_runtime_hooks,
389 target_path,
390 deleted_target_keys,
391 )
392 }
393}
394
395impl<C: CanisterKind> Db<C> {
396 #[must_use]
398 pub(crate) const fn has_runtime_hooks(&self) -> bool {
399 runtime_hooks::has_runtime_hooks(self.entity_runtime_hooks)
400 }
401
402 #[must_use]
404 pub(crate) fn runtime_entity_names(&self) -> Vec<String> {
405 self.entity_runtime_hooks
406 .iter()
407 .map(|hooks| hooks.model.name().to_string())
408 .collect()
409 }
410
411 pub(crate) fn runtime_hook_for_entity_tag(
414 &self,
415 entity_tag: EntityTag,
416 ) -> Result<&EntityRuntimeHooks<C>, InternalError> {
417 runtime_hooks::resolve_runtime_hook_by_tag(self.entity_runtime_hooks, entity_tag)
418 }
419
420 pub(crate) fn runtime_hook_for_entity_path(
423 &self,
424 entity_path: &str,
425 ) -> Result<&EntityRuntimeHooks<C>, InternalError> {
426 runtime_hooks::resolve_runtime_hook_by_path(self.entity_runtime_hooks, entity_path)
427 }
428}
429
430impl<C: CanisterKind> Copy for Db<C> {}
431
432impl<C: CanisterKind> Clone for Db<C> {
433 fn clone(&self) -> Self {
434 *self
435 }
436}