Skip to main content

icydb/
lib.rs

1//! # icydb
2//!
3//! `icydb` is the **public facade crate** for the IcyDB runtime.
4//! It is the recommended dependency for downstream canister projects.
5//!
6//! This crate exposes:
7//! - the stable runtime surface used inside canister actor code,
8//! - schema and design-time helpers for macros and validation,
9//! - and a small set of macros and entry points that wire generated code.
10//!
11//! Low-level execution, storage, and engine internals live in
12//! `icydb-core` and are re-exposed selectively through stable facade modules.
13//!
14//! ## Crate layout
15//!
16//! - `base`
17//!   Design-time helpers, sanitizers, and validators used by schemas and macros.
18//!
19//! - `build`
20//!   Internal code generation helpers used by macros and tests
21//!   (not intended for direct use).
22//!
23//! - `traits` / `types` / `value` / `visitor`
24//!   Stable runtime and schema-facing building blocks used by generated code.
25//!
26//! - `model` / `metrics` *(internal)*
27//!   Runtime model and metrics internals. Exposed for advanced tooling only;
28//!   not part of the supported semver surface.
29//!
30//! - `error`
31//!   Shared error types for generated code and runtime boundaries.
32//!
33//! - `macros`
34//!   Derive macros for entities, canisters, and schema helpers.
35//!
36//! - `schema`
37//!   Schema AST, builders, and validation utilities.
38//!
39//! - `db`
40//!   The public database façade: session handles, query builders,
41//!   and typed responses.
42//!
43//! ## Preludes
44//!
45//! - `prelude`
46//!   Opinionated runtime prelude for canister actor code.
47//!   Intended to be glob-imported in `lib.rs` to keep endpoints concise.
48//!
49//! - `design::prelude`
50//!   Prelude for schema and design-time code (macros, validators,
51//!   and base helpers).
52//!
53//! ## Internal boundaries
54//!
55//! Generated code targets explicit facade surfaces (`traits`, `patch`,
56//! and `__macro`) instead of a broad internal-export module.
57
58// export so things just work in base/
59extern crate self as icydb;
60
61use icydb_core::{
62    error::{ErrorClass, ErrorOrigin, InternalError},
63    traits::Visitable,
64};
65use serde::{Serialize, de::DeserializeOwned};
66
67// crates
68pub use icydb_build as build;
69pub use icydb_build::build;
70pub use icydb_schema as schema;
71pub use icydb_schema_derive as macros;
72
73// core modules
74#[doc(hidden)]
75pub use icydb_core::{types, value};
76
77#[doc(hidden)]
78pub mod model {
79    pub mod entity {
80        pub use icydb_core::model::EntityModel;
81    }
82
83    pub mod field {
84        pub use icydb_core::model::{
85            EnumVariantModel, FieldInsertGeneration, FieldKind, FieldModel, FieldStorageDecode,
86            FieldWriteManagement, RelationStrength,
87        };
88    }
89
90    pub mod index {
91        pub use icydb_core::model::{
92            IndexExpression, IndexKeyItem, IndexKeyItemsRef, IndexModel, IndexPredicateMetadata,
93        };
94    }
95
96    pub use entity::EntityModel;
97    pub use field::FieldModel;
98    pub use index::{IndexExpression, IndexModel};
99}
100
101#[doc(hidden)]
102pub mod metrics {
103    pub use icydb_core::metrics::{
104        EventCounters, EventReport, MetricsSink, metrics_report, metrics_reset_all,
105    };
106}
107
108pub mod visitor {
109    pub use icydb_core::visitor::{
110        Issue, PathSegment, SanitizeFieldDescriptor, ScopedContext, ValidateFieldDescriptor,
111        VisitableFieldDescriptor, VisitorContext, VisitorCore, VisitorError, VisitorIssues,
112        VisitorMutCore, drive_sanitize_fields, drive_validate_fields, drive_visitable_fields,
113        drive_visitable_fields_mut, perform_visit, perform_visit_mut,
114    };
115    pub use icydb_core::{
116        sanitize::{SanitizeWriteContext, SanitizeWriteMode, sanitize, sanitize_with_context},
117        validate::validate,
118    };
119}
120
121// facade modules
122pub mod base;
123pub mod db;
124pub mod error;
125pub mod traits;
126pub use error::Error;
127
128// Macro/runtime wiring surface used by generated code.
129// This is intentionally narrow and not semver-stable.
130#[doc(hidden)]
131pub mod __macro {
132    pub use crate::db::execute_generated_storage_report;
133    #[cfg(feature = "sql")]
134    pub use icydb_core::db::LoweredSqlCommand;
135    pub use icydb_core::db::{
136        DataStore, DbSession as CoreDbSession, EntityRuntimeHooks, IndexStore, StoreRegistry,
137    };
138}
139
140// re-exports
141//
142// macros can use these, stops the user having to specify all the dependencies
143// in the Cargo.toml file manually
144//
145// these have to be in icydb_core because of the base library not being able to import icydb
146#[doc(hidden)]
147pub mod __reexports {
148    pub use candid;
149    pub use canic_cdk;
150    pub use canic_memory;
151    pub use ctor;
152    pub use derive_more;
153    pub use icydb_derive;
154    pub use remain;
155    pub use serde;
156}
157
158//
159// Actor Prelude
160// using _ brings traits into scope and avoids name conflicts
161//
162
163pub mod prelude {
164    pub use crate::{
165        db,
166        db::{
167            query,
168            query::{
169                FilterExpr, SortExpr,
170                builder::{
171                    FieldRef, count, count_by, exists, first, last, max, max_by, min, min_by, sum,
172                },
173                predicate::Predicate,
174            },
175        },
176        traits::{
177            Collection as _, EntityKind as _, EntityValue, Inner as _, MapCollection as _,
178            Path as _,
179        },
180        types::*,
181        value::Value,
182    };
183    pub use candid::CandidType;
184    pub use serde::{Deserialize, Serialize};
185}
186
187//
188// Design Prelude
189// For schema/design code (macros, traits, base helpers).
190//
191
192pub mod design {
193    pub mod prelude {
194        pub use ::candid::CandidType;
195        pub use ::derive_more;
196
197        pub use crate::{
198            base, db,
199            db::query::builder::{
200                FieldRef, count, count_by, exists, first, last, max, max_by, min, min_by, sum,
201            },
202            macros::*,
203            traits::{
204                Collection as _, EntityKind, EntityValue as _, FieldValue as _, Inner as _,
205                MapCollection as _, Path as _, Sanitize as _, Sanitizer, Serialize as _,
206                Validate as _, ValidateCustom, Validator, Visitable as _,
207            },
208            types::*,
209            value::Value,
210            visitor::VisitorContext,
211            visitor::{SanitizeWriteContext, SanitizeWriteMode},
212        };
213    }
214}
215
216//
217// -------------------------- CODE -----------------------------------
218//
219//
220// Consts
221//
222
223// Workspace version re-export for downstream tooling/tests.
224pub const VERSION: &str = env!("CARGO_PKG_VERSION");
225
226//
227// Macros
228//
229
230// Include the generated actor module emitted by `build!` (placed in `OUT_DIR/actor.rs`).
231#[macro_export]
232macro_rules! start {
233    () => {
234        // actor.rs
235        include!(concat!(env!("OUT_DIR"), "/actor.rs"));
236    };
237}
238
239// Access the current canister's database session; use `db!().debug()` for verbose tracing.
240#[macro_export]
241#[expect(clippy::crate_in_macro_def)]
242macro_rules! db {
243    () => {
244        crate::db()
245    };
246}
247
248//
249// Helpers
250//
251
252// Run sanitization over a mutable visitable tree.
253pub fn sanitize(node: &mut dyn Visitable) -> Result<(), Error> {
254    icydb_core::sanitize::sanitize(node)
255        .map_err(InternalError::from)
256        .map_err(Error::from)
257}
258
259// Validate a visitable tree, collecting issues by path.
260pub fn validate(node: &dyn Visitable) -> Result<(), Error> {
261    icydb_core::validate::validate(node)
262        .map_err(InternalError::from)
263        .map_err(Error::from)
264}
265
266// Serialize a visitable value into bytes.
267//
268// The encoding format is an internal detail of icydb and is only
269// guaranteed to round-trip via `deserialize`.
270pub fn serialize<T>(ty: &T) -> Result<Vec<u8>, Error>
271where
272    T: Serialize,
273{
274    icydb_core::serialize::serialize(ty)
275        .map_err(|err| {
276            InternalError::new(
277                ErrorClass::Internal,
278                ErrorOrigin::Serialize,
279                err.to_string(),
280            )
281        })
282        .map_err(Error::from)
283}
284
285// Deserialize bytes into a concrete visitable value.
286//
287// This is intended for testing, tooling, and round-trip verification.
288// It should not be used in hot runtime paths.
289pub fn deserialize<T>(bytes: &[u8]) -> Result<T, Error>
290where
291    T: DeserializeOwned,
292{
293    icydb_core::serialize::deserialize(bytes)
294        .map_err(|err| {
295            InternalError::new(
296                ErrorClass::Internal,
297                ErrorOrigin::Serialize,
298                err.to_string(),
299            )
300        })
301        .map_err(Error::from)
302}