1extern crate self as icydb_model;
8
9pub mod application;
10pub mod base;
11pub mod build;
12pub mod error;
13pub mod fragment;
14#[cfg_attr(
17 target_arch = "wasm32",
18 expect(
19 dead_code,
20 reason = "Wasm retains declaration nodes while host code owns whole-graph traversal"
21 )
22)]
23pub mod node;
24pub mod normalize;
25#[cfg_attr(
26 target_arch = "wasm32",
27 expect(dead_code, reason = "whole-graph schema validation is host-owned")
28)]
29mod schema_validate;
30mod typed_adapter;
31pub mod types;
32pub mod validate;
33#[cfg_attr(
34 target_arch = "wasm32",
35 expect(
36 dead_code,
37 reason = "Wasm retains declarations while host code owns graph visitation"
38 )
39)]
40mod visit;
41pub mod visitor;
42
43pub const MAX_ENTITY_NAME_LEN: usize = 64;
45
46pub const MAX_FIELD_NAME_LEN: usize = 64;
48
49pub const MAX_INDEX_FIELDS: usize = 4;
51
52pub const MAX_INDEX_NAME_LEN: usize =
54 MAX_ENTITY_NAME_LEN + (MAX_INDEX_FIELDS * (1 + MAX_FIELD_NAME_LEN));
55
56use crate::{build::BuildError, node::NodeError};
57use thiserror::Error as ThisError;
58
59pub mod prelude {
61 pub(crate) use crate::build::schema_read;
62 pub use crate::{
63 Collection as _, Inner as _, MapCollection as _, NormalizeAndValidate as _, Path as _,
64 base, canister, entity, enum_, err,
65 error::ErrorTree,
66 list, map, newtype,
67 node::*,
68 normalizer, record,
69 schema::*,
70 set, store, tuple,
71 types::{Cardinality, Primitive},
72 validator,
73 visitor::{
74 Issue, Normalize as _, NormalizeAuto, NormalizeCustom, Normalizer as _, Validate as _,
75 ValidateAuto, ValidateCustom, Validator as _, Visitable as _, VisitorContext,
76 },
77 };
78 pub(crate) use crate::{
79 node::{MacroNode, ValidateNode, VisitableNode},
80 visit::Visitor,
81 };
82 pub use candid::CandidType;
83 pub use serde::{Deserialize, Serialize};
84}
85
86pub use application::NormalizeAndValidate;
87pub use icydb_model_macros::{
88 Add, AddAssign, Deref, DerefMut, Display, Div, DivAssign, Inner, Mul, MulAssign, Rem, Sub,
89 SubAssign, Sum, canister, entity, enum_, list, map, newtype, normalizer, record, set, store,
90 tuple, validator,
91};
92pub use normalize::normalize;
93#[doc(hidden)]
94pub use typed_adapter::{
95 TypedAdapterContext, TypedEnumOutput, TypedInputValue, TypedNamedType, TypedOutputValue,
96 TypedScalarValue, TypedValueError,
97};
98pub use validate::validate;
99
100pub trait Path {
102 const PATH: &'static str;
104}
105
106pub trait Inner<T> {
108 fn inner(&self) -> &T;
110
111 fn into_inner(self) -> T;
113}
114
115pub trait Collection {
117 type Item;
119
120 type Iter<'a>: Iterator<Item = &'a Self::Item> + 'a
122 where
123 Self: 'a;
124
125 fn iter(&self) -> Self::Iter<'_>;
127
128 fn len(&self) -> usize;
130
131 fn is_empty(&self) -> bool {
133 self.len() == 0
134 }
135}
136
137pub trait MapCollection {
139 type Key;
141
142 type Value;
144
145 type Iter<'a>: Iterator<Item = (&'a Self::Key, &'a Self::Value)> + 'a
147 where
148 Self: 'a;
149
150 fn iter(&self) -> Self::Iter<'_>;
152
153 fn len(&self) -> usize;
155
156 fn is_empty(&self) -> bool {
158 self.len() == 0
159 }
160}
161
162pub mod schema {
164 pub use icydb_schema::*;
165}
166
167#[doc(hidden)]
169pub mod __reexports {
170 pub use candid;
171 #[cfg(not(target_arch = "wasm32"))]
172 pub use ctor;
173 pub use icydb_model_macros;
174 pub use remain;
175 pub use serde;
176}
177
178#[derive(Debug, ThisError)]
185pub enum Error {
186 #[error(transparent)]
187 BuildError(#[from] BuildError),
188
189 #[error(transparent)]
190 NodeError(#[from] NodeError),
191}
192
193#[cfg(test)]
198mod tests {
199 use super::{Error, build::BuildError, error::ErrorTree, node::NodeError};
200
201 #[test]
202 fn build_errors_remain_in_build_boundary() {
203 let schema_error = Error::from(BuildError::Validation(ErrorTree::from(
204 "missing schema relation target",
205 )));
206
207 match schema_error {
208 Error::BuildError(BuildError::Validation(tree)) => {
209 assert!(
210 tree.messages()
211 .iter()
212 .any(|message| message == "missing schema relation target"),
213 "build validation errors must remain wrapped as build-boundary failures",
214 );
215 }
216 Error::BuildError(BuildError::Graph(error)) => {
217 panic!("unexpected graph error: {error}");
218 }
219 Error::NodeError(_) => {
220 panic!("build validation failures must not be remapped into node-boundary errors");
221 }
222 }
223 }
224
225 #[test]
226 fn node_errors_remain_in_node_boundary() {
227 let schema_error = Error::from(NodeError::PathNotFound("entity.user_id".to_string()));
228
229 match schema_error {
230 Error::NodeError(NodeError::PathNotFound(path)) => {
231 assert_eq!(path, "entity.user_id");
232 }
233 Error::NodeError(NodeError::IncorrectNodeType(path)) => {
234 panic!("unexpected node error kind after conversion for path {path}");
235 }
236 Error::BuildError(_) => {
237 panic!("node errors must not be remapped into build-boundary failures");
238 }
239 }
240 }
241}