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;
20pub mod types;
21pub mod validate;
22#[cfg_attr(target_arch = "wasm32", allow(dead_code))]
23mod visit;
24pub mod visitor;
25
26pub const MAX_ENTITY_NAME_LEN: usize = 64;
28
29pub const MAX_FIELD_NAME_LEN: usize = 64;
31
32pub const MAX_INDEX_FIELDS: usize = 4;
34
35pub const MAX_INDEX_NAME_LEN: usize =
37 MAX_ENTITY_NAME_LEN + (MAX_INDEX_FIELDS * (1 + MAX_FIELD_NAME_LEN));
38
39use crate::{build::BuildError, node::NodeError};
40use thiserror::Error as ThisError;
41
42pub mod prelude {
44 pub(crate) use crate::build::schema_read;
45 pub use crate::{
46 Collection as _, Inner as _, MapCollection as _, Path as _, base, canister, entity, enum_,
47 err,
48 error::ErrorTree,
49 list, map, newtype,
50 node::*,
51 normalizer, record,
52 schema::*,
53 set, store, tuple,
54 types::{Cardinality, Primitive},
55 validator,
56 visitor::{
57 Issue, Normalize as _, NormalizeAuto, NormalizeCustom, Normalizer as _, Validate as _,
58 ValidateAuto, ValidateCustom, Validator as _, Visitable as _, VisitorContext,
59 },
60 };
61 pub(crate) use crate::{
62 node::{MacroNode, ValidateNode, VisitableNode},
63 visit::Visitor,
64 };
65 pub use candid::CandidType;
66 pub use serde::{Deserialize, Serialize};
67}
68
69pub use icydb_model_macros::{
70 Add, AddAssign, Deref, DerefMut, Display, Div, DivAssign, Inner, Mul, MulAssign, Rem, Sub,
71 SubAssign, Sum, canister, entity, enum_, list, map, newtype, normalizer, record, set, store,
72 tuple, validator,
73};
74pub use normalize::normalize;
75pub use validate::validate;
76
77pub trait Path {
79 const PATH: &'static str;
81}
82
83pub trait Inner<T> {
85 fn inner(&self) -> &T;
87
88 fn into_inner(self) -> T;
90}
91
92pub trait Collection {
94 type Item;
96
97 type Iter<'a>: Iterator<Item = &'a Self::Item> + 'a
99 where
100 Self: 'a;
101
102 fn iter(&self) -> Self::Iter<'_>;
104
105 fn len(&self) -> usize;
107
108 fn is_empty(&self) -> bool {
110 self.len() == 0
111 }
112}
113
114pub trait MapCollection {
116 type Key;
118
119 type Value;
121
122 type Iter<'a>: Iterator<Item = (&'a Self::Key, &'a Self::Value)> + 'a
124 where
125 Self: 'a;
126
127 fn iter(&self) -> Self::Iter<'_>;
129
130 fn len(&self) -> usize;
132
133 fn is_empty(&self) -> bool {
135 self.len() == 0
136 }
137}
138
139pub mod schema {
141 pub use icydb_schema::*;
142}
143
144#[doc(hidden)]
146pub mod __reexports {
147 pub use candid;
148 #[cfg(not(target_arch = "wasm32"))]
149 pub use ctor;
150 pub use icydb_model_macros;
151 pub use remain;
152 pub use serde;
153}
154
155#[derive(Debug, ThisError)]
162pub enum Error {
163 #[error(transparent)]
164 BuildError(#[from] BuildError),
165
166 #[error(transparent)]
167 NodeError(#[from] NodeError),
168}
169
170#[cfg(test)]
175mod tests {
176 use super::{Error, build::BuildError, error::ErrorTree, node::NodeError};
177
178 #[test]
179 fn build_errors_remain_in_build_boundary() {
180 let schema_error = Error::from(BuildError::Validation(ErrorTree::from(
181 "missing schema relation target",
182 )));
183
184 match schema_error {
185 Error::BuildError(BuildError::Validation(tree)) => {
186 assert!(
187 tree.messages()
188 .iter()
189 .any(|message| message == "missing schema relation target"),
190 "build validation errors must remain wrapped as build-boundary failures",
191 );
192 }
193 Error::BuildError(BuildError::Graph(error)) => {
194 panic!("unexpected graph error: {error}");
195 }
196 Error::NodeError(_) => {
197 panic!("build validation failures must not be remapped into node-boundary errors");
198 }
199 }
200 }
201
202 #[test]
203 fn node_errors_remain_in_node_boundary() {
204 let schema_error = Error::from(NodeError::PathNotFound("entity.user_id".to_string()));
205
206 match schema_error {
207 Error::NodeError(NodeError::PathNotFound(path)) => {
208 assert_eq!(path, "entity.user_id");
209 }
210 Error::NodeError(NodeError::IncorrectNodeType(path)) => {
211 panic!("unexpected node error kind after conversion for path {path}");
212 }
213 Error::BuildError(_) => {
214 panic!("node errors must not be remapped into build-boundary failures");
215 }
216 }
217 }
218}