Skip to main content

icydb_schema/
lib.rs

1pub mod build;
2pub mod error;
3pub mod node;
4pub mod types;
5mod validate;
6mod 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    };
33    pub(crate) use crate::{
34        node::{MacroNode, ValidateNode, VisitableNode},
35        visit::Visitor,
36    };
37    pub use candid::CandidType;
38    pub use serde::{Deserialize, Serialize};
39}
40
41///
42/// Error
43///
44/// Top-level schema error boundary spanning build-time validation and node
45/// lookup/type errors.
46///
47#[derive(Debug, ThisError)]
48pub enum Error {
49    #[error(transparent)]
50    BuildError(#[from] BuildError),
51
52    #[error(transparent)]
53    NodeError(#[from] NodeError),
54}
55
56//
57// TESTS
58//
59
60#[cfg(test)]
61mod tests {
62    use super::{Error, build::BuildError, error::ErrorTree, node::NodeError};
63
64    #[test]
65    fn build_errors_remain_in_build_boundary() {
66        let schema_error = Error::from(BuildError::Validation(ErrorTree::from(
67            "missing schema relation target",
68        )));
69
70        match schema_error {
71            Error::BuildError(BuildError::Validation(tree)) => {
72                assert!(
73                    tree.messages()
74                        .iter()
75                        .any(|message| message == "missing schema relation target"),
76                    "build validation errors must remain wrapped as build-boundary failures",
77                );
78            }
79            Error::NodeError(_) => {
80                panic!("build validation failures must not be remapped into node-boundary errors");
81            }
82        }
83    }
84
85    #[test]
86    fn node_errors_remain_in_node_boundary() {
87        let schema_error = Error::from(NodeError::PathNotFound("entity.user_id".to_string()));
88
89        match schema_error {
90            Error::NodeError(NodeError::PathNotFound(path)) => {
91                assert_eq!(path, "entity.user_id");
92            }
93            Error::NodeError(NodeError::IncorrectNodeType(path)) => {
94                panic!("unexpected node error kind after conversion for path {path}");
95            }
96            Error::BuildError(_) => {
97                panic!("node errors must not be remapped into build-boundary failures");
98            }
99        }
100    }
101}