Skip to main content

icydb_schema/node/
schema.rs

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