infusedb/
data_type.rs

1use std::usize;
2
3// Written by Alberto Ruiz 2024-03-08
4// The data type module will provide the data types for the InfuseDB
5// this will be store several types of data, like text, numbers, dates, arrays and documents
6//
7// The data type will be used to store the data in the documents
8use super::collection::Document;
9use uuid::Uuid;
10
11pub enum FindOp {
12    Eq,
13    NotEq,
14    Gt,
15    Lt,
16}
17
18#[derive(PartialEq, Debug)]
19pub enum DataType {
20    Id(Uuid),
21    Text(String),
22    Number(f32),
23    Boolean(bool),
24    Array(Vec<DataType>),
25    Document(Document),
26}
27
28#[macro_export]
29macro_rules! d {
30    // Para arrays/vecs, aplica el macro recursivamente a cada elemento
31    ([$( $elem:tt ),* $(,)?]) => {
32        $crate::DataType::Array(vec![$( $crate::DataType::from($elem) ),*])
33    };
34
35    // Para expresiones simples, asume que hay un From<T> para DataType
36    ($val:expr) => {
37        $crate::DataType::from($val)
38    };
39}
40
41impl DataType {
42    pub fn get_type(&self) -> &str {
43        match self {
44            DataType::Id(_) => "id",
45            DataType::Text(_) => "text",
46            DataType::Number(_) => "number",
47            DataType::Boolean(_) => "boolean",
48            DataType::Array(_) => "array",
49            DataType::Document(_) => "document",
50        }
51    }
52
53    pub fn get(&self, index: &str) -> Option<&DataType> {
54        match self {
55            DataType::Array(v) => {
56                let n = index.parse::<usize>().ok()?;
57                v.get(n)
58            }
59            DataType::Document(d) => d.get(index),
60            _ => None,
61        }
62    }
63
64    pub fn get_mut(&mut self, index: &str) -> Option<&mut DataType> {
65        match self {
66            DataType::Array(v) => {
67                let n = index.parse::<usize>().ok()?;
68                v.get_mut(n)
69            }
70            DataType::Document(d) => d.get_mut(index),
71            _ => None,
72        }
73    }
74
75    pub fn find(&self, sub_key: &str, op: FindOp, value: DataType) -> Option<DataType> {
76        let mut result: Vec<DataType> = Vec::new();
77        match self {
78            DataType::Array(v) => {
79                for item in v {
80                    let sub_item = item.get(sub_key);
81                    if sub_item.is_none() {
82                        continue;
83                    }
84                    let sub_item = sub_item.unwrap();
85                    let items_are_number = matches!(value, DataType::Number(_))
86                        && matches!(*sub_item, DataType::Number(_));
87                    let matched = match op {
88                        FindOp::Eq => *sub_item == value,
89                        FindOp::NotEq => *sub_item != value,
90                        FindOp::Gt => items_are_number && sub_item.to_number() > value.to_number(),
91                        FindOp::Lt => items_are_number && sub_item.to_number() < value.to_number(),
92                    };
93                    if matched {
94                        result.push(item.clone());
95                    }
96                }
97                return Some(DataType::Array(result));
98            }
99
100            _ => None,
101        }
102    }
103
104    pub fn set(&mut self, index: &str, dt: DataType) -> Result<DataType, &'static str> {
105        match self {
106            DataType::Array(vec) => {
107                if let Ok(index) = index.parse::<usize>() {
108                    while index >= vec.len() {
109                        vec.push(DataType::Text("".to_string()));
110                    }
111                    vec[index] = dt;
112                    Ok(self.clone())
113                } else {
114                    Err("Invalid index")
115                }
116            }
117            DataType::Document(doc) => {
118                doc.insert(index.to_string(), dt);
119                Ok(self.clone())
120            }
121            _ => Err("Not supported"),
122        }
123    }
124    pub fn remove(&mut self, index: &str) -> Result<DataType, &'static str> {
125        match self {
126            DataType::Array(vec) => {
127                if let Ok(index) = index.parse::<usize>() {
128                    vec.remove(index);
129                    Ok(self.clone())
130                } else {
131                    Err("Invalid index")
132                }
133            }
134            DataType::Document(doc) => {
135                doc.remove(index);
136                Ok(self.clone())
137            }
138            _ => Err("Not supported"),
139        }
140    }
141
142    //add into
143    pub fn to_id(&self) -> Uuid {
144        match self {
145            DataType::Id(id) => *id,
146            _ => panic!("Not an ID"),
147        }
148    }
149    pub fn to_text(&self) -> &String {
150        match self {
151            DataType::Text(text) => text,
152            _ => panic!("Not a Text"),
153        }
154    }
155    pub fn to_number(&self) -> f32 {
156        match self {
157            DataType::Number(number) => *number,
158            _ => panic!("Not a Number"),
159        }
160    }
161    pub fn to_boolean(&self) -> bool {
162        match self {
163            DataType::Boolean(boolean) => *boolean,
164            _ => panic!("Not a Boolean"),
165        }
166    }
167    pub fn to_array(&self) -> &Vec<DataType> {
168        match self {
169            DataType::Array(array) => array,
170            _ => panic!("Not an Array"),
171        }
172    }
173    pub fn to_document(&self) -> &Document {
174        match self {
175            DataType::Document(document) => document,
176            _ => panic!("Not a Document"),
177        }
178    }
179
180    pub fn infer_type(raw: &str) -> u16 {
181        let raw = raw.trim();
182        if Uuid::parse_str(raw).is_ok() {
183            1
184        } else if raw.parse::<f32>().is_ok() {
185            3
186        } else if raw.to_lowercase().as_str() == "true" || raw.to_lowercase().as_str() == "false" {
187            4
188        } else if raw.starts_with('[') && raw.ends_with(']') {
189            5
190        } else if raw.starts_with('{') && raw.ends_with('}') {
191            6
192        } else {
193            2
194        }
195    }
196
197    pub fn load(t: u16, raw: String) -> Option<Self> {
198        let raw = raw.trim().to_string();
199        match t {
200            1 => {
201                let id = Uuid::parse_str(raw.as_str());
202                if id.is_err() {
203                    return None;
204                }
205                Some(DataType::Id(id.unwrap()))
206            }
207            2 => Some(DataType::Text(raw.trim_matches('"').to_string())),
208            3 => {
209                let n = raw.parse::<f32>();
210                if n.is_err() {
211                    return None;
212                }
213                Some(DataType::Number(n.unwrap()))
214            }
215            4 => match raw.to_lowercase().as_str() {
216                "true" => Some(DataType::Boolean(true)),
217                "false" => Some(DataType::Boolean(false)),
218                _ => None,
219            },
220            5 => {
221                let mut new_vec = Vec::new();
222                let raw = raw.strip_suffix(']').unwrap().strip_prefix('[').unwrap();
223                let mut open_array = false;
224                let mut open_string = false;
225                let mut open_bracket = 0;
226
227                let mut sub_raw = String::new();
228                for chr in raw.chars() {
229                    if chr == ',' && !open_array && !open_string && open_bracket == 0 {
230                        let t = Self::infer_type(&sub_raw);
231                        let r = Self::load(t, sub_raw.clone());
232                        if r.is_some() {
233                            new_vec.push(r.unwrap());
234                            sub_raw = String::new();
235                            continue;
236                        }
237                    }
238                    if chr == '[' && !open_array {
239                        open_array = true;
240                    }
241                    if chr == ']' && open_array {
242                        open_array = false;
243                    }
244                    if chr == '{' {
245                        open_bracket += 1;
246                    }
247                    if chr == '}' {
248                        open_bracket -= 1;
249                    }
250                    if chr == '"' {
251                        open_string = !open_string
252                    }
253                    sub_raw.push(chr);
254                }
255                if !sub_raw.is_empty() {
256                    let t = Self::infer_type(&sub_raw);
257                    let r = Self::load(t, sub_raw.clone());
258                    if r.is_some() {
259                        new_vec.push(r.unwrap());
260                    }
261                }
262
263                Some(DataType::Array(new_vec))
264            }
265            6 => {
266                let mut d = Document::new();
267                let raw = raw.strip_suffix('}').unwrap().strip_prefix('{').unwrap();
268                let mut key = String::new();
269                let mut key_done = false;
270                let mut open_array = 0;
271                let mut open_string = false;
272                let mut open_bracket = 0;
273                let mut value = String::new();
274                for chr in raw.chars() {
275                    if chr == ':' && !key_done {
276                        key_done = true;
277                        continue;
278                    }
279                    if key_done {
280                        if chr == ',' && open_array == 0 && !open_string && open_bracket == 0 {
281                            let t = Self::infer_type(&value);
282                            let r = Self::load(t, value.clone());
283                            if r.is_some() {
284                                d.insert(key.trim().to_string(), r.unwrap());
285                                key = String::new();
286                                value = String::new();
287                                key_done = false;
288                                continue;
289                            }
290                        }
291
292                        if chr == '[' {
293                            open_array += 1;
294                        }
295                        if chr == ']' {
296                            open_array -= 1;
297                        }
298                        if chr == '{' {
299                            open_bracket += 1;
300                        }
301                        if chr == '}' {
302                            open_bracket -= 1
303                        }
304                        if chr == '"' {
305                            open_string = !open_string
306                        }
307
308                        value.push(chr);
309                    } else {
310                        key.push(chr);
311                    }
312                }
313                if !key.is_empty() && !value.is_empty() {
314                    let t = Self::infer_type(&value);
315                    let r = Self::load(t, value.clone());
316                    if r.is_some() {
317                        d.insert(key.trim().to_string(), r.unwrap());
318                    }
319                }
320                Some(DataType::Document(d))
321            }
322            _ => None,
323        }
324    }
325}
326
327impl ToString for DataType {
328    fn to_string(&self) -> String {
329        match self {
330            DataType::Id(id) => id.to_string(),
331            DataType::Text(text) => format!("\"{}\"", text.to_string()),
332            DataType::Number(number) => number.to_string(),
333            DataType::Boolean(boolean) => boolean.to_string(),
334            DataType::Array(array) => {
335                let mut result = String::new();
336                result.push('[');
337                for value in array {
338                    result.push_str(&value.to_string());
339                    result.push_str(", ");
340                }
341                let mut result = result.strip_suffix(", ").unwrap_or(&result).to_string();
342                result.push(']');
343                result
344            }
345            DataType::Document(document) => {
346                let mut result = String::new();
347                result.push('{');
348                for (key, value) in document {
349                    result.push_str(&key);
350                    result.push_str(": ");
351                    result.push_str(&value.to_string());
352                    result.push_str(", ");
353                }
354                result.pop();
355                result.pop();
356                result.push('}');
357
358                result
359            }
360        }
361    }
362}
363
364impl From<Uuid> for DataType {
365    fn from(value: Uuid) -> Self {
366        DataType::Id(value)
367    }
368}
369
370impl From<String> for DataType {
371    fn from(value: String) -> Self {
372        DataType::Text(value)
373    }
374}
375
376impl From<&str> for DataType {
377    fn from(value: &str) -> Self {
378        DataType::Text(value.to_string())
379    }
380}
381
382impl From<f32> for DataType {
383    fn from(value: f32) -> Self {
384        DataType::Number(value)
385    }
386}
387
388impl From<i32> for DataType {
389    fn from(value: i32) -> Self {
390        DataType::Number(value as f32)
391    }
392}
393
394impl From<bool> for DataType {
395    fn from(value: bool) -> Self {
396        DataType::Boolean(value)
397    }
398}
399
400impl From<Vec<DataType>> for DataType {
401    fn from(value: Vec<DataType>) -> Self {
402        DataType::Array(value)
403    }
404}
405
406impl From<Document> for DataType {
407    fn from(value: Document) -> Self {
408        DataType::Document(value)
409    }
410}
411
412//impl clone
413impl Clone for DataType {
414    fn clone(&self) -> Self {
415        match self {
416            DataType::Id(id) => DataType::Id(*id),
417            DataType::Text(text) => DataType::Text(text.clone()),
418            DataType::Number(number) => DataType::Number(*number),
419            DataType::Boolean(boolean) => DataType::Boolean(*boolean),
420            DataType::Array(array) => DataType::Array(array.clone()),
421            DataType::Document(document) => DataType::Document(document.clone()),
422        }
423    }
424}
425
426#[cfg(test)]
427mod tests {
428    use super::DataType;
429
430    #[test]
431    fn test_macro() {
432        let dd = d!("Hello");
433        let expected = DataType::from("Hello");
434        assert!(dd == expected);
435        let dd = d!(10);
436        let expected = DataType::from(10);
437        assert!(dd == expected);
438        let dd = d!(["hello", 10]);
439        let expected = DataType::from(vec![d!("hello"), d!(10)]);
440        assert!(dd == expected);
441    }
442}