Skip to main content

icydb_core/traits/
mod.rs

1#[macro_use]
2mod macros;
3mod view;
4mod visitor;
5
6pub use view::*;
7pub use visitor::*;
8
9// db traits
10pub use crate::db::traits::FromKey;
11
12// re-exports of other traits
13// for the standard traits::X pattern
14pub use canic_cdk::structures::storable::Storable;
15pub use num_traits::{FromPrimitive as NumFromPrimitive, NumCast, ToPrimitive as NumToPrimitive};
16pub use serde::{Deserialize, Serialize, de::DeserializeOwned};
17pub use std::{
18    cmp::{Eq, Ordering, PartialEq},
19    convert::{AsRef, From, Into},
20    default::Default,
21    fmt::{Debug, Display},
22    hash::Hash,
23    iter::IntoIterator,
24    ops::{Add, AddAssign, Deref, DerefMut, Mul, MulAssign, Sub, SubAssign},
25    str::FromStr,
26};
27
28use crate::{prelude::*, visitor::VisitorContext};
29
30/// ------------------------
31/// KIND TRAITS
32/// the Schema uses the term "Node" but when they're built it's "Kind"
33/// ------------------------
34
35///
36/// Kind
37///
38
39pub trait Kind: Path + 'static {}
40
41impl<T> Kind for T where T: Path + 'static {}
42
43///
44/// CanisterKind
45///
46
47pub trait CanisterKind: Kind {}
48
49///
50/// EntityKind
51///
52
53pub trait EntityKind: Kind + TypeKind + FieldValues {
54    type PrimaryKey: Copy + Into<Key>;
55    type Store: StoreKind;
56    type Canister: CanisterKind; // Self::Store::Canister shortcut
57
58    const ENTITY_NAME: &'static str;
59    const PRIMARY_KEY: &'static str;
60    const FIELDS: &'static [&'static str];
61    const INDEXES: &'static [&'static IndexModel];
62    const MODEL: &'static crate::model::entity::EntityModel;
63
64    fn key(&self) -> Key;
65    fn primary_key(&self) -> Self::PrimaryKey;
66    fn set_primary_key(&mut self, key: Self::PrimaryKey);
67}
68
69///
70/// StoreKind
71///
72
73pub trait StoreKind: Kind {
74    type Canister: CanisterKind;
75}
76
77/// ------------------------
78/// TYPE TRAITS
79/// ------------------------
80
81///
82/// TypeKind
83/// any data type
84///
85
86pub trait TypeKind:
87    Kind
88    + View
89    + Clone
90    + Default
91    + Serialize
92    + DeserializeOwned
93    + Sanitize
94    + Validate
95    + Visitable
96    + PartialEq
97{
98}
99
100impl<T> TypeKind for T where
101    T: Kind
102        + View
103        + Clone
104        + Default
105        + DeserializeOwned
106        + PartialEq
107        + Serialize
108        + Sanitize
109        + Validate
110        + Visitable
111{
112}
113
114/// ------------------------
115/// OTHER TRAITS
116/// ------------------------
117
118///
119/// FieldValues
120///
121
122pub trait FieldValues {
123    fn get_value(&self, field: &str) -> Option<Value>;
124}
125
126///
127/// FieldValue
128///
129/// Conversion boundary for values used in query predicates.
130///
131/// `FieldValue` represents any value that can appear on the *right-hand side*
132/// of a predicate (e.g. `field == value`, `field IN values`). Implementations
133/// convert Rust values into owned [`Value`] instances that are stored inside
134/// query plans and executed later.
135///
136
137pub trait FieldValue {
138    fn to_value(&self) -> Value {
139        Value::Unsupported
140    }
141}
142
143impl FieldValue for &str {
144    fn to_value(&self) -> Value {
145        Value::Text((*self).to_string())
146    }
147}
148
149impl FieldValue for String {
150    fn to_value(&self) -> Value {
151        Value::Text(self.clone())
152    }
153}
154
155impl<T> FieldValue for &'_ T
156where
157    T: FieldValue + Copy,
158{
159    fn to_value(&self) -> Value {
160        (*self).to_value()
161    }
162}
163
164impl<T: FieldValue> FieldValue for Option<T> {
165    fn to_value(&self) -> Value {
166        match self {
167            Some(v) => v.to_value(),
168            None => Value::None,
169        }
170    }
171}
172
173impl<T: FieldValue> FieldValue for Vec<T> {
174    fn to_value(&self) -> Value {
175        Value::List(self.iter().map(FieldValue::to_value).collect())
176    }
177}
178
179impl<T: FieldValue> FieldValue for Box<T> {
180    fn to_value(&self) -> Value {
181        (**self).to_value()
182    }
183}
184
185// impl_field_value
186#[macro_export]
187macro_rules! impl_field_value {
188    ( $( $type:ty => $variant:ident ),* $(,)? ) => {
189        $(
190            impl FieldValue for $type {
191                fn to_value(&self) -> Value {
192                    Value::$variant((*self).into())
193                }
194            }
195        )*
196    };
197}
198
199impl_field_value!(
200    i8 => Int,
201    i16 => Int,
202    i32 => Int,
203    i64 => Int,
204    u8 => Uint,
205    u16 => Uint,
206    u32 => Uint,
207    u64 => Uint,
208    bool => Bool,
209);
210
211///
212/// Inner
213/// for Newtypes to get the innermost value
214///
215/// DO NOT REMOVE - its been added and removed twice already, NumCast
216/// is a pain to use and won't work for half our types
217///
218
219pub trait Inner<T> {
220    fn inner(&self) -> &T;
221    fn into_inner(self) -> T;
222}
223
224// impl_inner
225#[macro_export]
226macro_rules! impl_inner {
227    ($($type:ty),*) => {
228        $(
229            impl Inner<$type> for $type {
230                fn inner(&self) -> &$type {
231                    &self
232                }
233                fn into_inner(self) -> $type {
234                    self
235                }
236            }
237        )*
238    };
239}
240
241impl_inner!(
242    bool, f32, f64, i8, i16, i32, i64, i128, String, u8, u16, u32, u64, u128
243);
244
245///
246/// Path
247///
248/// any node created via a macro has a Path
249/// ie. design::game::rarity::Rarity
250///
251
252pub trait Path {
253    const PATH: &'static str;
254}
255
256///
257/// Sanitizer
258/// transforms a value into a sanitized version
259///
260
261pub trait Sanitizer<T> {
262    /// Apply in-place sanitization.
263    ///
264    /// - `Ok(())` means success (possibly with issues recorded by the caller)
265    /// - `Err(String)` means a fatal sanitization failure
266    fn sanitize(&self, value: &mut T) -> Result<(), String>;
267}
268
269///
270/// Validator
271/// allows a node to validate different types of primitives
272/// ?Sized so we can operate on str
273///
274
275pub trait Validator<T: ?Sized> {
276    fn validate(&self, value: &T, ctx: &mut dyn VisitorContext);
277}