icydb_core/traits/
mod.rs

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