infusedb/
collection.rs

1// Writen by Alberto Ruiz 2024-03-08
2// The collection module will provide the collection of documents for the InfuseDB
3// The collection will store the documents in memory and provide a simple API to interact with them
4// The Document will be a HashMap<String, DataType>
5//
6use super::data_type::DataType;
7use crate::utils;
8use std::collections::HashMap;
9
10pub type Document = HashMap<String, DataType>;
11
12
13#[macro_export]
14macro_rules! doc {
15  ( $( $key: expr => $value: expr ),* ) => {
16    {
17         use std::collections::HashMap;
18        let mut map = HashMap::new();
19        $(
20            map.insert($key.to_string(), DataType::from($value));
21        )*
22        DataType::Document(map)
23    }
24  };
25}
26
27pub struct Collection {
28    pub name: String,
29    pub(crate) data: DataType,
30    //b_tree: BNode
31}
32
33pub trait _KV {
34    fn new(name: &str) -> Self;
35    fn add(&mut self, key: &str, value: DataType) -> &mut Self;
36    fn rm(&mut self, key: &str);
37    fn count(&self) -> usize;
38    fn list(&self) -> HashMap<String, DataType>;
39    fn get(&mut self, key: &str) -> Option<&DataType>;
40    fn dump(&self) -> String;
41    fn load(data: &str) -> Collection;
42}
43
44// impl KV for Collection {
45impl Collection {
46    pub fn new(name: &str) -> Self {
47        Collection {
48            name: name.to_string(),
49            data: DataType::Document(Document::new()),
50            //b_tree: BNode::new(),
51        }
52    }
53
54    pub fn add(&mut self, key: &str, value: DataType) -> &mut Self {
55        let _ = self.data.set(key, value);
56        return self;
57    }
58
59    pub fn rm(&mut self, key: &str) {
60        let _ = self.data.remove(key);
61    }
62
63    pub fn count(&self) -> usize {
64        self.data.to_document().len()
65    }
66
67    pub fn list(&self) -> HashMap<String, DataType> {
68        return self.data.to_document().clone();
69    }
70
71    pub fn get(&mut self, key: &str) -> Option<&DataType> {
72        return self.data.get(key);
73    }
74
75    pub fn dump(&self) -> String {
76        let mut result = String::new();
77        result.push_str(format!("[{}]\n", self.name).as_str());
78        for (k, v) in self.data.to_document().iter() {
79            let t = match v.get_type() {
80                "id" => "1",
81                "text" => "2",
82                "number" => "3",
83                "boolean" => "4",
84                "array" => "5",
85                "document" => "6",
86                _ => "7",
87            };
88            let line = format!("{} {} {}\n", t, k, v.to_string());
89            result.push_str(line.as_str());
90        }
91        return result;
92    }
93
94    pub fn load(data: &str) -> Collection {
95        let data_text = data.to_string();
96        let parser = data_text.lines();
97        let name = parser.clone().next();
98        if name.is_none() {
99            panic!("invalid data")
100        }
101        let name = name
102            .unwrap()
103            .strip_suffix(']')
104            .unwrap()
105            .strip_prefix('[')
106            .unwrap();
107        let mut result = Collection::new(name);
108        for line in parser.into_iter() {
109            if line.starts_with('[') {
110                continue;
111            }
112            let line_text = line.to_string();
113            let elements = utils::smart_split(line_text);
114            if elements.len() != 3 {
115                continue;
116            }
117            let raw_t = elements[0].clone();
118            let t = raw_t.parse::<u16>();
119            if t.is_err() {
120                println!("Error parsing: {:?}", t.err());
121                continue;
122            }
123            let t = t.unwrap();
124            let k = elements[1].clone();
125            let raw_v = elements[2].clone();
126            let v = DataType::load(t, raw_v);
127            if v.is_none() {
128                println!("Error parsing: unresolved value");
129                continue;
130            }
131            let v = v.unwrap();
132            result.add(k.as_str(), v);
133        }
134
135        return result;
136    }
137}
138
139//TEST
140#[cfg(test)]
141#[test]
142fn test_collection() {
143    let mut collection = Collection::new("users");
144    collection.add(
145        "John",
146        doc!(
147          "name" => "John",
148          "age" => 25,
149          "isMarried" => false,
150          "birthDate" => "1995-01-01"
151        ),
152    );
153    assert!(collection.get("John").is_some());
154}
155
156#[test]
157fn test_dump() {
158    let header = "[prueba]\n";
159    let kv_name = "2 name \"Juan\"";
160    let kv_surname = "2 surname \"Perez\"";
161    let kv_age = "3 age 15";
162
163    let mut collection = Collection::new("prueba");
164    collection.add("name", DataType::from("Juan"));
165    collection.add("surname", DataType::from("Perez"));
166    collection.add("age", DataType::from(15));
167
168    let dump = collection.dump();
169    println!("{}", dump);
170    assert!(dump.starts_with(header));
171    assert!(dump.contains(kv_name));
172    assert!(dump.contains(kv_surname));
173    assert!(dump.contains(kv_age));
174}
175
176#[test]
177fn test_load() {
178    let dump = "[prueba]\n2 name Juan\n2 surname Perez\n3 age 15\n";
179    let c = Collection::load(dump);
180    assert_eq!(c.name, "prueba");
181}