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