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}