icydb_schema/node/
schema.rs

1use crate::{Error, prelude::*};
2use std::{any::Any, collections::BTreeMap};
3
4///
5/// SchemaNode
6///
7
8#[remain::sorted]
9#[derive(Clone, Debug, Serialize)]
10pub enum SchemaNode {
11    Canister(Canister),
12    Entity(Entity),
13    Enum(Enum),
14    List(List),
15    Map(Map),
16    Newtype(Newtype),
17    Record(Record),
18    Sanitizer(Sanitizer),
19    Set(Set),
20    Store(Store),
21    Tuple(Tuple),
22    Validator(Validator),
23}
24
25impl SchemaNode {
26    #[must_use]
27    pub fn get_type(&self) -> Option<Box<dyn TypeNode>> {
28        match self {
29            Self::Entity(n) => Some(Box::new(n.clone())),
30            Self::Enum(n) => Some(Box::new(n.clone())),
31            Self::List(n) => Some(Box::new(n.clone())),
32            Self::Map(n) => Some(Box::new(n.clone())),
33            Self::Newtype(n) => Some(Box::new(n.clone())),
34            Self::Record(n) => Some(Box::new(n.clone())),
35            Self::Set(n) => Some(Box::new(n.clone())),
36            Self::Tuple(n) => Some(Box::new(n.clone())),
37            _ => None,
38        }
39    }
40}
41
42impl SchemaNode {
43    const fn def(&self) -> &Def {
44        match self {
45            Self::Canister(n) => &n.def,
46            Self::Entity(n) => &n.def,
47            Self::Enum(n) => &n.def,
48            Self::List(n) => &n.def,
49            Self::Map(n) => &n.def,
50            Self::Newtype(n) => &n.def,
51            Self::Record(n) => &n.def,
52            Self::Sanitizer(n) => &n.def,
53            Self::Set(n) => &n.def,
54            Self::Store(n) => &n.def,
55            Self::Tuple(n) => &n.def,
56            Self::Validator(n) => &n.def,
57        }
58    }
59}
60
61impl MacroNode for SchemaNode {
62    fn as_any(&self) -> &dyn Any {
63        match self {
64            Self::Canister(n) => n.as_any(),
65            Self::Entity(n) => n.as_any(),
66            Self::Enum(n) => n.as_any(),
67            Self::List(n) => n.as_any(),
68            Self::Map(n) => n.as_any(),
69            Self::Newtype(n) => n.as_any(),
70            Self::Record(n) => n.as_any(),
71            Self::Sanitizer(n) => n.as_any(),
72            Self::Set(n) => n.as_any(),
73            Self::Store(n) => n.as_any(),
74            Self::Tuple(n) => n.as_any(),
75            Self::Validator(n) => n.as_any(),
76        }
77    }
78}
79
80impl ValidateNode for SchemaNode {}
81
82impl VisitableNode for SchemaNode {
83    fn drive<V: Visitor>(&self, v: &mut V) {
84        match self {
85            Self::Canister(n) => n.accept(v),
86            Self::Entity(n) => n.accept(v),
87            Self::Enum(n) => n.accept(v),
88            Self::List(n) => n.accept(v),
89            Self::Map(n) => n.accept(v),
90            Self::Newtype(n) => n.accept(v),
91            Self::Record(n) => n.accept(v),
92            Self::Sanitizer(n) => n.accept(v),
93            Self::Set(n) => n.accept(v),
94            Self::Store(n) => n.accept(v),
95            Self::Tuple(n) => n.accept(v),
96            Self::Validator(n) => n.accept(v),
97        }
98    }
99}
100
101///
102/// Schema
103///
104
105#[derive(Clone, Debug, Serialize)]
106pub struct Schema {
107    pub nodes: BTreeMap<String, SchemaNode>,
108    pub hash: &'static str,
109    pub timestamp: u64,
110}
111
112impl Schema {
113    #[must_use]
114    pub fn new() -> Self {
115        Self {
116            nodes: BTreeMap::new(),
117            hash: "",
118            timestamp: canic::utils::time::now_secs(),
119        }
120    }
121
122    // insert_node
123    pub fn insert_node(&mut self, node: SchemaNode) {
124        self.nodes.insert(node.def().path(), node);
125    }
126
127    // get_node
128    #[must_use]
129    pub fn get_node<'a>(&'a self, path: &str) -> Option<&'a SchemaNode> {
130        self.nodes.get(path)
131    }
132
133    // try_get_node
134    pub fn try_get_node<'a>(&'a self, path: &str) -> Result<&'a SchemaNode, Error> {
135        let node = self
136            .get_node(path)
137            .ok_or_else(|| NodeError::PathNotFound(path.to_string()))?;
138
139        Ok(node)
140    }
141
142    // cast_node
143    pub fn cast_node<'a, T: 'static>(&'a self, path: &str) -> Result<&'a T, Error> {
144        let node = self.try_get_node(path)?;
145
146        node.as_any()
147            .downcast_ref::<T>()
148            .ok_or_else(|| NodeError::IncorrectNodeType(path.to_string()).into())
149    }
150
151    // check_node_as
152    pub fn check_node_as<T: 'static>(&self, path: &str) -> Result<(), Error> {
153        self.cast_node::<T>(path).map(|_| ())
154    }
155
156    // get_nodes
157    pub fn get_nodes<T: 'static>(&self) -> impl Iterator<Item = (&str, &T)> {
158        self.nodes
159            .iter()
160            .filter_map(|(key, node)| node.as_any().downcast_ref::<T>().map(|n| (key.as_str(), n)))
161    }
162
163    // get_node_values
164    pub fn get_node_values<T: 'static>(&'_ self) -> impl Iterator<Item = &'_ T> + '_ {
165        self.nodes
166            .values()
167            .filter_map(|node| node.as_any().downcast_ref::<T>())
168    }
169
170    // filter_nodes
171    // Generic method to filter key, and nodes of any type with a predicate
172    pub fn filter_nodes<'a, T: 'static>(
173        &'a self,
174        predicate: impl Fn(&T) -> bool + 'a,
175    ) -> impl Iterator<Item = (&'a str, &'a T)> + 'a {
176        self.nodes.iter().filter_map(move |(key, node)| {
177            node.as_any()
178                .downcast_ref::<T>()
179                .filter(|target| predicate(target))
180                .map(|target| (key.as_str(), target))
181        })
182    }
183}
184
185impl Default for Schema {
186    fn default() -> Self {
187        Self::new()
188    }
189}
190
191impl ValidateNode for Schema {}
192
193impl VisitableNode for Schema {
194    fn drive<V: Visitor>(&self, v: &mut V) {
195        for node in self.nodes.values() {
196            node.accept(v);
197        }
198    }
199}