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::*, types::Unit, value::ValueEnum, 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/// UnitKey
71/// Marker trait for unit-valued primary keys used by singleton entities.
72///
73
74pub trait UnitKey: Copy + Into<Key> + unit_key::Sealed {}
75
76impl UnitKey for () {}
77impl UnitKey for Unit {}
78
79///
80/// StoreKind
81///
82
83pub trait StoreKind: Kind {
84    type Canister: CanisterKind;
85}
86
87mod unit_key {
88    use crate::types::Unit;
89
90    // Seal UnitKey so only unit-equivalent key types can implement it.
91    pub trait Sealed {}
92
93    impl Sealed for () {}
94    impl Sealed for Unit {}
95}
96
97/// ------------------------
98/// TYPE TRAITS
99/// ------------------------
100
101///
102/// TypeKind
103/// any data type
104///
105
106pub trait TypeKind:
107    Kind
108    + View
109    + Clone
110    + Default
111    + Serialize
112    + DeserializeOwned
113    + Sanitize
114    + Validate
115    + Visitable
116    + PartialEq
117{
118}
119
120impl<T> TypeKind for T where
121    T: Kind
122        + View
123        + Clone
124        + Default
125        + DeserializeOwned
126        + PartialEq
127        + Serialize
128        + Sanitize
129        + Validate
130        + Visitable
131{
132}
133
134/// ------------------------
135/// OTHER TRAITS
136/// ------------------------
137
138///
139/// FieldValues
140///
141
142pub trait FieldValues {
143    fn get_value(&self, field: &str) -> Option<Value>;
144}
145
146///
147/// FieldValue
148///
149/// Conversion boundary for values used in query predicates.
150///
151/// `FieldValue` represents any value that can appear on the *right-hand side*
152/// of a predicate (e.g. `field == value`, `field IN values`). Implementations
153/// convert Rust values into owned [`Value`] instances that are stored inside
154/// query plans and executed later.
155///
156
157pub trait FieldValue {
158    fn to_value(&self) -> Value {
159        Value::Unsupported
160    }
161}
162
163///
164/// EnumValue
165/// Explicit conversion boundary for domain enums used in query values.
166///
167
168pub trait EnumValue {
169    /// Convert this enum into a strict [`ValueEnum`] with its canonical path.
170    fn to_value_enum(&self) -> ValueEnum;
171}
172
173impl FieldValue for &str {
174    fn to_value(&self) -> Value {
175        Value::Text((*self).to_string())
176    }
177}
178
179impl FieldValue for String {
180    fn to_value(&self) -> Value {
181        Value::Text(self.clone())
182    }
183}
184
185impl<T> FieldValue for &'_ T
186where
187    T: FieldValue + Copy,
188{
189    fn to_value(&self) -> Value {
190        (*self).to_value()
191    }
192}
193
194impl<T: FieldValue> FieldValue for Option<T> {
195    fn to_value(&self) -> Value {
196        match self {
197            Some(v) => v.to_value(),
198            None => Value::None,
199        }
200    }
201}
202
203impl<T: FieldValue> FieldValue for Vec<T> {
204    fn to_value(&self) -> Value {
205        Value::List(self.iter().map(FieldValue::to_value).collect())
206    }
207}
208
209impl<T: FieldValue> FieldValue for Box<T> {
210    fn to_value(&self) -> Value {
211        (**self).to_value()
212    }
213}
214
215// impl_field_value
216#[macro_export]
217macro_rules! impl_field_value {
218    ( $( $type:ty => $variant:ident ),* $(,)? ) => {
219        $(
220            impl FieldValue for $type {
221                fn to_value(&self) -> Value {
222                    Value::$variant((*self).into())
223                }
224            }
225        )*
226    };
227}
228
229impl_field_value!(
230    i8 => Int,
231    i16 => Int,
232    i32 => Int,
233    i64 => Int,
234    u8 => Uint,
235    u16 => Uint,
236    u32 => Uint,
237    u64 => Uint,
238    bool => Bool,
239);
240
241///
242/// Inner
243/// for Newtypes to get the innermost value
244///
245/// DO NOT REMOVE - its been added and removed twice already, NumCast
246/// is a pain to use and won't work for half our types
247///
248
249pub trait Inner<T> {
250    fn inner(&self) -> &T;
251    fn into_inner(self) -> T;
252}
253
254// impl_inner
255#[macro_export]
256macro_rules! impl_inner {
257    ($($type:ty),*) => {
258        $(
259            impl Inner<$type> for $type {
260                fn inner(&self) -> &$type {
261                    &self
262                }
263                fn into_inner(self) -> $type {
264                    self
265                }
266            }
267        )*
268    };
269}
270
271impl_inner!(
272    bool, f32, f64, i8, i16, i32, i64, i128, String, u8, u16, u32, u64, u128
273);
274
275///
276/// Path
277///
278/// any node created via a macro has a Path
279/// ie. design::game::rarity::Rarity
280///
281
282pub trait Path {
283    const PATH: &'static str;
284}
285
286///
287/// Sanitizer
288/// transforms a value into a sanitized version
289///
290
291pub trait Sanitizer<T> {
292    /// Apply in-place sanitization.
293    ///
294    /// - `Ok(())` means success (possibly with issues recorded by the caller)
295    /// - `Err(String)` means a fatal sanitization failure
296    fn sanitize(&self, value: &mut T) -> Result<(), String>;
297}
298
299///
300/// Validator
301/// allows a node to validate different types of primitives
302/// ?Sized so we can operate on str
303///
304
305pub trait Validator<T: ?Sized> {
306    fn validate(&self, value: &T, ctx: &mut dyn VisitorContext);
307}