icydb_schema/node/
schema.rs

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