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(
18 target_arch = "wasm32",
19 allow(
20 dead_code,
21 reason = "Wasm retains declaration nodes while host code owns whole-graph traversal"
22 )
23)]
24pub mod node;
25pub mod normalize;
26#[cfg_attr(
27 target_arch = "wasm32",
28 expect(dead_code, reason = "whole-graph schema validation is host-owned")
29)]
30mod schema_validate;
31mod typed_adapter;
32pub mod types;
33pub mod validate;
34#[cfg_attr(
35 target_arch = "wasm32",
36 allow(
37 dead_code,
38 reason = "Wasm retains declarations while host code owns graph visitation"
39 )
40)]
41mod visit;
42pub mod visitor;
43
44pub const MAX_ENTITY_NAME_LEN: usize = 64;
46
47pub const MAX_FIELD_NAME_LEN: usize = 64;
49
50pub const MAX_INDEX_NAME_LEN: usize =
52 MAX_ENTITY_NAME_LEN + (MAX_INDEX_FIELDS * (1 + MAX_FIELD_NAME_LEN));
53
54use crate::{build::BuildError, node::NodeError};
55use thiserror::Error as ThisError;
56
57pub mod prelude {
59 pub(crate) use crate::build::schema_read;
60 pub use crate::{
61 EntitySource as _, Inner as _, NormalizeAndValidate as _, Path as _, base, canister,
62 entity, enum_, err,
63 error::ErrorTree,
64 list, map, newtype,
65 node::*,
66 normalizer, record,
67 schema::*,
68 set, store, tuple,
69 types::{Cardinality, Primitive},
70 validator,
71 visitor::{
72 Issue, Normalize as _, NormalizeAuto, NormalizeCustom, Normalizer as _, Validate as _,
73 ValidateAuto, ValidateCustom, Validator as _, Visitable as _, VisitorContext,
74 },
75 };
76 pub(crate) use crate::{
77 node::{MacroNode, ValidateNode, VisitableNode},
78 visit::Visitor,
79 };
80
81 pub use serde::{Deserialize, Serialize};
82}
83
84pub use application::NormalizeAndValidate;
85pub use icydb_model_macros::{
86 Add, AddAssign, Deref, DerefMut, Display, Div, DivAssign, Inner, Mul, MulAssign, Neg, Product,
87 Rem, RemAssign, Sub, SubAssign, Sum, canister, entity, enum_, list, map, newtype, normalizer,
88 record, set, store, tuple, validator,
89};
90pub use icydb_schema::MAX_INDEX_FIELDS;
91pub use normalize::normalize;
92#[doc(hidden)]
93pub use typed_adapter::{
94 TypedAdapterContext, TypedEnumDescriptor, TypedEnumSelection, TypedInputValue, TypedNamedType,
95 TypedOutputValue, TypedScalarValue, TypedValueError,
96};
97pub use validate::validate;
98
99pub trait Path {
101 const PATH: &'static str;
103}
104
105pub trait EntitySource {
111 const ENTITY: &'static str;
113}
114
115pub trait Inner<T> {
117 fn inner(&self) -> &T;
119
120 fn into_inner(self) -> T;
122}
123
124pub mod schema {
126 pub use icydb_schema::*;
127}
128
129#[doc(hidden)]
131pub mod __reexports {
132
133 #[cfg(not(target_arch = "wasm32"))]
134 pub use ctor;
135 pub use icydb_model_macros;
136 pub use remain;
137 pub use serde;
138}
139
140#[derive(Debug, ThisError)]
147pub enum Error {
148 #[error(transparent)]
149 BuildError(#[from] BuildError),
150
151 #[error(transparent)]
152 NodeError(#[from] NodeError),
153}
154
155#[cfg(test)]
160mod tests {
161 use super::{Error, build::BuildError, error::ErrorTree, node::NodeError};
162
163 #[test]
164 fn build_errors_remain_in_build_boundary() {
165 let schema_error = Error::from(BuildError::Validation(ErrorTree::from(
166 "missing schema relation target",
167 )));
168
169 match schema_error {
170 Error::BuildError(BuildError::Validation(tree)) => {
171 assert!(
172 tree.messages()
173 .iter()
174 .any(|message| message == "missing schema relation target"),
175 "build validation errors must remain wrapped as build-boundary failures",
176 );
177 }
178 Error::BuildError(BuildError::Graph(error)) => {
179 panic!("unexpected graph error: {error}");
180 }
181 Error::NodeError(_) => {
182 panic!("build validation failures must not be remapped into node-boundary errors");
183 }
184 }
185 }
186
187 #[test]
188 fn node_errors_remain_in_node_boundary() {
189 let schema_error = Error::from(NodeError::PathNotFound("entity.user_id".to_string()));
190
191 match schema_error {
192 Error::NodeError(NodeError::PathNotFound(path)) => {
193 assert_eq!(path, "entity.user_id");
194 }
195 Error::NodeError(NodeError::IncorrectNodeType(path)) => {
196 panic!("unexpected node error kind after conversion for path {path}");
197 }
198 Error::BuildError(_) => {
199 panic!("node errors must not be remapped into build-boundary failures");
200 }
201 }
202 }
203}