Skip to main content

icydb_schema/
lib.rs

1pub mod build;
2pub mod error;
3pub mod node;
4pub mod types;
5pub mod validate;
6pub mod visit;
7
8// Maximum length for entity schema identifiers.
9pub const MAX_ENTITY_NAME_LEN: usize = 64;
10
11// Maximum length for field schema identifiers.
12pub const MAX_FIELD_NAME_LEN: usize = 64;
13
14// Maximum number of fields allowed in a derived index.
15pub const MAX_INDEX_FIELDS: usize = 4;
16
17// Maximum length for derived index identifiers.
18pub const MAX_INDEX_NAME_LEN: usize =
19    MAX_ENTITY_NAME_LEN + (MAX_INDEX_FIELDS * (1 + MAX_FIELD_NAME_LEN));
20
21use crate::{build::BuildError, node::NodeError};
22use thiserror::Error as ThisError;
23
24/// Shared schema-building prelude used by validators, macros, and tests.
25pub mod prelude {
26    pub(crate) use crate::build::schema_read;
27    pub use crate::{
28        err,
29        error::ErrorTree,
30        node::*,
31        types::{Cardinality, Primitive},
32        visit::Visitor,
33    };
34    pub use candid::CandidType;
35    pub use serde::{Deserialize, Serialize};
36}
37
38///
39/// Error
40///
41/// Top-level schema error boundary spanning build-time validation and node
42/// lookup/type errors.
43///
44#[derive(Debug, ThisError)]
45pub enum Error {
46    #[error(transparent)]
47    BuildError(#[from] BuildError),
48
49    #[error(transparent)]
50    NodeError(#[from] NodeError),
51}
52
53//
54// TESTS
55//
56
57#[cfg(test)]
58mod tests {
59    use super::{Error, build::BuildError, error::ErrorTree, node::NodeError};
60
61    #[test]
62    fn build_errors_remain_in_build_boundary() {
63        let schema_error = Error::from(BuildError::Validation(ErrorTree::from(
64            "missing schema relation target",
65        )));
66
67        match schema_error {
68            Error::BuildError(BuildError::Validation(tree)) => {
69                assert!(
70                    tree.messages()
71                        .iter()
72                        .any(|message| message == "missing schema relation target"),
73                    "build validation errors must remain wrapped as build-boundary failures",
74                );
75            }
76            Error::NodeError(_) => {
77                panic!("build validation failures must not be remapped into node-boundary errors");
78            }
79        }
80    }
81
82    #[test]
83    fn node_errors_remain_in_node_boundary() {
84        let schema_error = Error::from(NodeError::PathNotFound("entity.user_id".to_string()));
85
86        match schema_error {
87            Error::NodeError(NodeError::PathNotFound(path)) => {
88                assert_eq!(path, "entity.user_id");
89            }
90            Error::NodeError(NodeError::IncorrectNodeType(path)) => {
91                panic!("unexpected node error kind after conversion for path {path}");
92            }
93            Error::BuildError(_) => {
94                panic!("node errors must not be remapped into build-boundary failures");
95            }
96        }
97    }
98}