clia_rustorm_dao/
dao.rs

1use crate::{
2    error::DaoError,
3    FromValue,
4    ToValue,
5    Value,
6};
7use serde::{
8    ser::{
9        Serialize,
10        Serializer,
11    },
12    Deserialize,
13    Deserializer,
14};
15use std::collections::BTreeMap;
16
17#[derive(Debug, PartialEq, Clone, Default)]
18pub struct Dao(pub BTreeMap<String, Value>);
19
20impl Dao {
21    pub fn new() -> Self { Dao::default() }
22
23    pub fn insert<K, V>(&mut self, k: K, v: V)
24    where
25        K: ToString,
26        V: ToValue,
27    {
28        self.0.insert(k.to_string(), v.to_value());
29    }
30
31    pub fn insert_value<K>(&mut self, k: K, value: &Value)
32    where
33        K: ToString,
34    {
35        self.0.insert(k.to_string(), value.clone());
36    }
37
38    pub fn get<'a, T>(&'a self, s: &str) -> Result<T, DaoError>
39    where
40        T: FromValue,
41    {
42        let value: Option<&'a Value> = self.0.get(s);
43        match value {
44            Some(v) => FromValue::from_value(v).map_err(DaoError::ConvertError),
45            None => Err(DaoError::NoSuchValueError(s.into())),
46        }
47    }
48
49    pub fn get_opt<'a, T>(&'a self, s: &str) -> Result<Option<T>, DaoError>
50    where
51        T: FromValue,
52    {
53        let value: Option<&'a Value> = self.0.get(s);
54        match value {
55            Some(v) => {
56                match v {
57                    Value::Nil => Ok(None),
58                    _ => {
59                        Ok(Some(
60                            FromValue::from_value(v).map_err(DaoError::ConvertError)?,
61                        ))
62                    }
63                }
64            }
65            None => Ok(None),
66        }
67    }
68
69    pub fn get_value(&self, s: &str) -> Option<&Value> { self.0.get(s) }
70
71    pub fn remove(&mut self, s: &str) -> Option<Value> { self.0.remove(s) }
72}
73
74impl<'a> Serialize for Dao {
75    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
76    where
77        S: Serializer,
78    {
79        self.0.serialize(serializer)
80    }
81}
82
83impl<'de> Deserialize<'de> for Dao {
84    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
85    where
86        D: Deserializer<'de>,
87    {
88        BTreeMap::deserialize(deserializer).map(Dao)
89    }
90}
91
92pub trait FromDao {
93    /// convert dao to an instance of the corresponding struct of the model
94    /// taking into considerating the renamed columns
95    fn from_dao(dao: &Dao) -> Self;
96}
97
98pub trait ToDao {
99    /// convert from an instance of the struct to a dao representation
100    /// to be saved into the database
101    fn to_dao(&self) -> Dao;
102}
103
104#[cfg(test)]
105mod tests {
106    use super::*;
107    use serde_json;
108    use uuid::Uuid;
109
110    #[test]
111    fn insert_double() {
112        let mut dao = Dao::new();
113        dao.insert("life", 42.0f64);
114        let life: Result<f64, DaoError> = dao.get("life");
115        assert_eq!(life.unwrap(), 42.0f64);
116    }
117
118    #[test]
119    fn insert_float() {
120        let mut dao = Dao::new();
121        dao.insert("life", 42.0f32);
122        let life: Result<f64, DaoError> = dao.get("life");
123        assert_eq!(life.unwrap(), 42.0f64);
124    }
125
126    #[test]
127    fn uuid() {
128        let mut dao = Dao::new();
129        let uuid = Uuid::new_v4();
130        dao.insert("user_id", uuid);
131    }
132
133    #[test]
134    fn serialize_json() {
135        let mut dao = Dao::new();
136        dao.insert("life", 42);
137        dao.insert("lemons", "lemonade");
138        let json = serde_json::to_string(&dao).unwrap();
139        let expected = r#"{"lemons":{"Text":"lemonade"},"life":{"Int":42}}"#;
140        assert_eq!(json, expected);
141    }
142
143    #[test]
144    fn test_get_opt() {
145        let mut dao = Dao::new();
146        dao.insert("life", 42);
147        let life: Result<Option<i32>, _> = dao.get("life");
148        assert!(life.is_ok());
149        let life = life.unwrap();
150        assert!(life.is_some());
151        assert_eq!(life.unwrap(), 42);
152    }
153
154    #[test]
155    fn referenced() {
156        let mut dao = Dao::new();
157        let v = 42;
158        let s = "lemonade";
159        dao.insert("life", &v);
160        dao.insert("lemons", s);
161        let life: Result<Option<i32>, _> = dao.get("life");
162        assert!(life.is_ok());
163        let life = life.unwrap();
164        assert!(life.is_some());
165        assert_eq!(life.unwrap(), 42);
166    }
167}