safe_en/
lib.rs

1#![deny(missing_docs)]
2#![deny(rustdoc::missing_doc_code_examples)]
3#![cfg_attr(docsrs, feature(doc_cfg))]
4#![doc(html_root_url = "https://docs.rs/safe_en/1.8.0")]
5//!# SafeEn
6//!Local database solution with clean and strict data integrity.
7//!
8//!## Usage
9//!
10//! ```
11//! use safe_en::{
12//!     table::{TableRow, TypeDefs},
13//!     Database,
14//! };
15//! let mut db = Database::new();
16//! db.create_table(
17//!     "users",
18//!     vec![
19//!         TableRow::new("id", TypeDefs::I64),
20//!         TableRow::new("email", TypeDefs::String),
21//!     ],
22//! )
23//! .unwrap();
24//!
25//!
26//! let id = 1_i64;;
27//! let email = "ahmet@mail.com";
28//!
29//! db.table("users").unwrap().insert(vec![id.into(), email.into()]).unwrap();
30//! ```
31//! You can find more examples [here](https://github.com/behemehal/SafeEn/tree/main/examples)
32
33/// Formatter for tables and types
34use core::fmt;
35/// FileSystem utilities for saving and loading database
36use std::{fs::File, io::Write};
37/// Database types
38use table::{Table, TableRow, TypeDefs};
39/// Database table
40pub mod table;
41/// Database utils
42pub mod utils;
43
44/// Integrity error
45#[derive(Debug, Clone)]
46pub struct LoadError;
47
48impl fmt::Display for LoadError {
49    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
50        write!(f, "Failed to load db from file")
51    }
52}
53
54/// Database struct
55pub struct Database {
56    /// Database name
57    name: String,
58    /// Database size
59    size: usize,
60    /// Database tables
61    tables: Vec<table::Table>,
62}
63
64impl Database {
65    /// Creates a new database
66    pub fn new() -> Self {
67        Database {
68            tables: Vec::new(),
69            name: "".to_string(),
70            size: 0,
71        }
72    }
73
74    /// Loads a database from a file
75    /// ## Errors
76    /// Returns a `LoadError` if integrity checks fail
77    /// ## Parameters
78    /// * `path` - The path to the file
79    /// ## Example
80    /// ```
81    /// use safe_en::Database;
82    /// let db = Database::load("db.sfn");
83    /// ```
84    pub fn load(path: &str) -> Result<Self, LoadError> {
85        let mut db = Database::new();
86        match db.load_file(path) {
87            Ok(_) => Ok(db),
88            Err(_) => Err(LoadError),
89        }
90    }
91
92    ///Sets name of the database
93    /// ## Parameters
94    /// * `name` - The name of the database
95    /// ## Example
96    /// ```
97    /// use safe_en::Database;
98    /// let mut db = Database::new();
99    /// db.set_name("users");
100    /// ```
101    pub fn set_name(&mut self, name: &str) {
102        self.name = name.to_string();
103    }
104
105    ///Returns name of the database
106    /// ## Example
107    /// ```
108    /// use safe_en::Database;
109    /// let mut db = Database::new();
110    /// db.set_name("users");
111    /// assert_eq!(db.get_name(), "users");
112    /// ```
113    pub fn get_name(&self) -> String {
114        self.name.clone()
115    }
116
117    #[deprecated(since = "1.5.3")]
118    ///Returns size of the database
119    pub fn get_size(&self) -> usize {
120        self.size
121    }
122
123    ///Returns number of tables in the database
124    /// ## Example
125    /// ```
126    /// use safe_en::{Database, table::{TableRow, TypeDefs}};
127    /// let mut db = Database::new();
128    /// db.create_table("users", vec![
129    ///    TableRow::new("id", TypeDefs::I64),
130    ///   TableRow::new("email", TypeDefs::String),
131    /// ]).unwrap();
132    /// assert_eq!(db.get_table_count(), 1);
133    /// ```
134    pub fn get_table_count(&self) -> usize {
135        self.tables.len()
136    }
137
138    /// Get query
139    /// ## Parameters
140    /// * `table` - The name of the table
141    /// ## Returns
142    /// * [`Option<&mut Table>`]
143    /// ## Example
144    /// ```
145    /// use safe_en::{Database, table::{TableRow, TypeDefs}};
146    /// let mut db = Database::new();
147    /// db.create_table("users", vec![
148    ///   TableRow::new("id", TypeDefs::I64),
149    ///  TableRow::new("email", TypeDefs::String),
150    /// ]).unwrap();
151    /// assert_eq!(db.table("users").unwrap().get_name(), "users");
152    /// ```
153    pub fn table(&mut self, table_name: &str) -> Option<&mut Table> {
154        self.tables.iter_mut().find(|x| x.name == table_name)
155    }
156
157    /// Get query returns table directly
158    /// ## Parameters
159    /// * `table` - The name of the table
160    /// ## Returns
161    /// * [`&mut Table`]
162    /// ## Panics
163    /// If table not found
164    /// ## Example
165    /// ```
166    /// use safe_en::{Database, table::{TableRow, TypeDefs}};
167    /// let mut db = Database::new();
168    /// db.create_table("users", vec![
169    ///   TableRow::new("id", TypeDefs::I64),
170    ///  TableRow::new("email", TypeDefs::String),
171    /// ]).unwrap();
172    /// assert_eq!(db.table_unwrap("users").get_name(), "users");
173    /// ```
174    pub fn table_unwrap(&mut self, table_name: &str) -> &mut Table {
175        self.tables
176            .iter_mut()
177            .find(|x| x.name == table_name)
178            .unwrap()
179    }
180
181    /// Removes table
182    /// ## Parameters
183    /// * `name` - Table name
184    /// ## Returns
185    /// * [`Ok(())`]
186    /// * [`Err(())`] If a table with same name already exists
187    /// ## Example
188    /// ```
189    /// use safe_en::{
190    ///    table::{TableRow, TypeDefs},
191    ///   Database,
192    /// };
193    /// let mut db = Database::new();
194    /// 
195    /// db.create_table("users", vec![
196    ///   TableRow::new("id", TypeDefs::I64),
197    ///   TableRow::new("email", TypeDefs::String),
198    /// ]).unwrap();
199    /// 
200    /// db.remove_table("users").unwrap();
201    /// ```
202    pub fn remove_table(&mut self, table_name: &str) -> Result<(), ()> {
203        match self.tables.iter().position(|x| x.get_name() == table_name) {
204            Some(e) => {
205                self.tables.remove(e);
206                Ok(())
207            }
208            None => Err(()),
209        }
210    }
211
212    /// Creates table
213    /// ## Parameters
214    /// * `name` - Table name
215    /// * `rows` - Table rows
216    /// ## Returns
217    /// * [`Ok(())`]
218    /// * [`Err(())`] If a table with same name already exists
219    /// ## Example
220    /// ```
221    /// use safe_en::{
222    ///    table::{TableRow, TypeDefs},
223    ///   Database,
224    /// };
225    /// let mut db = Database::new();
226    /// db.create_table(
227    ///    "users",
228    ///    vec![
229    ///      TableRow::new("id", TypeDefs::I64),
230    ///      TableRow::new("email", TypeDefs::String),
231    ///    ]).unwrap();
232    /// ```
233    pub fn create_table(&mut self, table_name: &str, rows: Vec<TableRow>) -> Result<(), ()> {
234        let table = table::Table {
235            name: table_name.to_owned(),
236            headers: rows,
237            columns: vec![],
238        };
239        if self.tables.iter().find(|x| x.name == table_name).is_some() {
240            return Err(());
241        } else {
242            self.tables.push(table);
243            Ok(())
244        }
245    }
246
247    /// Load database from file
248    /// ## Parameters
249    /// * `path` - The path to the file
250    /// ## Example
251    /// ```
252    /// use safe_en::Database;
253    /// let db = Database::load("db.sfn");
254    /// ```
255    fn load_file(&mut self, path: &str) -> Result<(), LoadError> {
256        let mut file = match File::open(path) {
257            Ok(it) => it,
258            Err(_) => return Err(LoadError),
259        };
260        let db_name: String = utils::read_data(&mut file, TypeDefs::String).get();
261        let table_len: u64 = utils::read_data(&mut file, TypeDefs::U64).get();
262        self.set_name(&db_name);
263        for _ in 0..table_len {
264            let table_name: String = utils::read_data(&mut file, TypeDefs::String).get();
265            let table_headers_len: u64 = utils::read_data(&mut file, TypeDefs::U64).get();
266
267            let mut table_rows: Vec<TableRow> = Vec::new();
268
269            for _ in 0..table_headers_len {
270                let table_header: String = utils::read_data(&mut file, TypeDefs::String).get();
271                let base_header_type: i8 = utils::read_one(&mut file);
272                let second_header_type: i8 = utils::read_one(&mut file);
273                let row = TableRow::new(
274                    &table_header,
275                    TypeDefs::from_base_and_second_layer(
276                        base_header_type as u8,
277                        second_header_type as u8,
278                    ),
279                );
280                table_rows.push(row);
281            }
282
283            //Create table from collected rows
284            match self.create_table(&table_name, table_rows.clone()) {
285                Ok(it) => it,
286                Err(_) => return Err(LoadError),
287            };
288
289            let table_rows_len: u64 = utils::read_data(&mut file, TypeDefs::U64).get();
290
291            for _ in 0..table_rows_len {
292                let mut tables = vec![];
293                for table_row in &table_rows {
294                    let row_value = utils::read_data(&mut file, table_row.rtype.clone());
295                    tables.push(row_value);
296                }
297                match self.table(&table_name) {
298                    Some(it) => match it.insert(tables.clone()) {
299                        Ok(_) => (),
300                        Err(_) => return Err(LoadError),
301                    },
302                    None => return Err(LoadError),
303                }
304            }
305        }
306        Ok(())
307    }
308
309    /// Saves database to file
310    /// ## Parameters
311    /// * `path` - The path to the file
312    /// ## Example
313    /// ```
314    /// use safe_en::Database;
315    /// let mut db = Database::new();
316    /// db.save("db.sfn");
317    /// ```
318    pub fn save(&self, path: &str) {
319        let mut bytes = vec![];
320
321        utils::extend_bytes_from_raw_type(&mut bytes, &utils::type_to_bytes(self.name.clone()));
322        utils::extend_bytes_from_raw_type(
323            &mut bytes,
324            &utils::type_to_bytes(self.tables.len() as u64),
325        );
326
327        for table in self.tables.iter() {
328            utils::extend_bytes_from_raw_type(
329                &mut bytes,
330                &utils::type_to_bytes(table.name.clone()),
331            );
332            utils::extend_bytes_from_raw_type(
333                &mut bytes,
334                &utils::type_to_bytes(table.headers.len() as u64),
335            );
336
337            for header in table.headers.iter() {
338                utils::extend_bytes_from_raw_type(
339                    &mut bytes,
340                    &utils::type_to_bytes(header.key.clone()),
341                );
342                bytes.extend(header.rtype.get_base_and_second_layer());
343            }
344
345            utils::extend_bytes_from_raw_type(
346                &mut bytes,
347                &utils::type_to_bytes(table.columns.len() as u64),
348            );
349
350            for row in table.columns.iter() {
351                for _data in row.iter() {
352                    let data = utils::type_to_bytes(_data.clone().get_type());
353                    utils::extend_bytes_from_raw_type(&mut bytes, &data);
354                }
355            }
356        }
357
358        let mut file = match File::create(path) {
359            Ok(it) => it,
360            Err(_) => return,
361        };
362
363        match file.write_all(&bytes) {
364            Ok(it) => it,
365            Err(_) => return,
366        };
367    }
368}