From 0067d77a19e71fcd8007c241f4fa13856dc5ed4b Mon Sep 17 00:00:00 2001 From: giuseppe-g-gelardi Date: Wed, 18 Dec 2024 15:46:40 -0500 Subject: [PATCH 1/2] start separate database operations -- io, util, queries, etc --- Cargo.toml | 3 - src/{database.rs => database/core.rs} | 140 +------------------------- src/database/io.rs | 74 ++++++++++++++ src/database/mod.rs | 18 ++++ src/database/query.rs | 119 ++++++++++++++++++++++ src/database/utils.rs | 44 ++++++++ src/lib.rs | 7 +- src/table.rs | 5 + 8 files changed, 266 insertions(+), 144 deletions(-) rename src/{database.rs => database/core.rs} (71%) create mode 100644 src/database/io.rs create mode 100644 src/database/mod.rs create mode 100644 src/database/query.rs create mode 100644 src/database/utils.rs diff --git a/Cargo.toml b/Cargo.toml index 805de29..9c9a6cd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,6 +29,3 @@ tracing-test = "0.2.5" [lib] path = "src/lib.rs" -# [[bin]] -# name = "cargobase" -# path = "main.rs" diff --git a/src/database.rs b/src/database/core.rs similarity index 71% rename from src/database.rs rename to src/database/core.rs index bf75c05..e043839 100644 --- a/src/database.rs +++ b/src/database/core.rs @@ -1,17 +1,7 @@ use std::collections::HashMap; -use std::path::{Path, PathBuf}; - -use serde::{Deserialize, Serialize}; use tracing; -use crate::{query::Operation, DatabaseError, Query, Table, View}; - -#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)] -pub struct Database { - pub(crate) name: String, - pub(crate) file_name: PathBuf, - pub(crate) tables: HashMap, -} +use crate::{Database, DatabaseError, Table, View}; impl Database { pub async fn new(name: &str) -> Self { @@ -90,88 +80,6 @@ impl Database { } } - pub(crate) async fn save_to_file(&self) -> Result<(), tokio::io::Error> { - let json_data = serde_json::to_string_pretty(&self)?; - tokio::fs::write(&self.file_name, json_data).await?; - tracing::info!("Database saved to file: {:?}", self.file_name); - Ok(()) - } - - pub(crate) async fn load_from_file>( - file_name: P, - ) -> Result { - let json_data = tokio::fs::read_to_string(file_name.as_ref()).await?; - let db: Database = serde_json::from_str(&json_data)?; - tracing::info!( - "Database loaded from file: {:?}", - file_name.as_ref().display() - ); - Ok(db) - } - - pub(crate) fn get_table_mut(&mut self, table_name: &str) -> Option<&mut Table> { - tracing::debug!("looking for table: {}", table_name); - let table = self.tables.get_mut(table_name); - - if let Some(_) = table { - tracing::debug!("table found: {}", table_name); - } else { - tracing::error!("table not found: {}", table_name); - } - - table - } - - pub fn add_row(&mut self) -> Query { - Query { - db_file_name: self.file_name.clone(), - table_name: None, - operation: Operation::Create, - update_data: None, - row_data: None, - } - } - - pub fn get_rows(&self) -> Query { - Query { - db_file_name: self.file_name.clone(), - table_name: None, - operation: Operation::Read, - update_data: None, - row_data: None, - } - } - - pub fn get_single(&self) -> Query { - Query { - db_file_name: self.file_name.clone(), - table_name: None, - operation: Operation::Read, - update_data: None, - row_data: None, - } - } - - pub fn delete_single(&self) -> Query { - Query { - db_file_name: self.file_name.clone(), - table_name: None, - operation: Operation::Delete, - update_data: None, - row_data: None, - } - } - - pub fn update_row(&self) -> Query { - Query { - db_file_name: self.file_name.clone(), - table_name: None, - operation: Operation::Update, - update_data: None, - row_data: None, - } - } - pub fn view(&self) { let view = View::new(self); view.all_tables(); @@ -230,6 +138,7 @@ impl Database { #[cfg(test)] mod tests { + use serde::{Deserialize, Serialize}; use serde_json::json; use tracing_test::traced_test; @@ -330,51 +239,6 @@ mod tests { assert_eq!(db.tables.len(), 1); } - #[tokio::test] - async fn test_save_to_file() { - use tempfile::NamedTempFile; - - let temp_file = NamedTempFile::new().expect("Failed to create a temporary file"); - let db_path = temp_file.path().to_path_buf(); - // let db_path = temp_file.path().to_str().unwrap().to_string(); - - let db = Database { - name: "test_db".to_string(), - file_name: db_path.clone(), - tables: HashMap::new(), - }; - - db.save_to_file().await.expect("Failed to save database"); - let loaded_db = Database::load_from_file(&db_path) - .await - .expect("Failed to load database"); - assert_eq!(db, loaded_db); - } - - #[tokio::test] - async fn test_load_from_file() { - use tempfile::NamedTempFile; - - let temp_file = NamedTempFile::new().expect("Failed to create a temporary file"); - let db_path = temp_file.path().to_path_buf(); - // let db_path = temp_file.path().to_str().unwrap().to_string(); - - let db = Database { - name: "test_db".to_string(), - file_name: db_path.clone(), - // file_name: db_path.to_string(), - tables: HashMap::new(), - }; - - db.save_to_file().await.expect("Failed to save database"); - - let loaded_db = Database::load_from_file(&db_path) - .await - .expect("Failed to load database"); - - assert_eq!(db, loaded_db); - } - #[tokio::test] async fn test_rename_table_success() { let mut db = setup_temp_db().await; diff --git a/src/database/io.rs b/src/database/io.rs new file mode 100644 index 0000000..4e936e8 --- /dev/null +++ b/src/database/io.rs @@ -0,0 +1,74 @@ +use std::path::Path; + +use crate::Database; + +impl Database { + pub(crate) async fn save_to_file(&self) -> Result<(), tokio::io::Error> { + let json_data = serde_json::to_string_pretty(&self)?; + tokio::fs::write(&self.file_name, json_data).await?; + tracing::info!("Database saved to file: {:?}", self.file_name); + Ok(()) + } + + pub(crate) async fn load_from_file>( + file_name: P, + ) -> Result { + let json_data = tokio::fs::read_to_string(file_name.as_ref()).await?; + let db: Database = serde_json::from_str(&json_data)?; + tracing::info!( + "Database loaded from file: {:?}", + file_name.as_ref().display() + ); + Ok(db) + } +} + +#[cfg(test)] + +mod tests { + + use super::*; + use std::collections::HashMap; + + #[tokio::test] + async fn test_save_to_file() { + use tempfile::NamedTempFile; + + let temp_file = NamedTempFile::new().expect("Failed to create a temporary file"); + let db_path = temp_file.path().to_path_buf(); + + let db = Database { + name: "test_db".to_string(), + file_name: db_path.clone(), + tables: HashMap::new(), + }; + + db.save_to_file().await.expect("Failed to save database"); + let loaded_db = Database::load_from_file(&db_path) + .await + .expect("Failed to load database"); + assert_eq!(db, loaded_db); + } + + #[tokio::test] + async fn test_load_from_file() { + use tempfile::NamedTempFile; + + let temp_file = NamedTempFile::new().expect("Failed to create a temporary file"); + let db_path = temp_file.path().to_path_buf(); + + let db = Database { + name: "test_db".to_string(), + file_name: db_path.clone(), + tables: HashMap::new(), + }; + + db.save_to_file().await.expect("Failed to save database"); + + let loaded_db = Database::load_from_file(&db_path) + .await + .expect("Failed to load database"); + + assert_eq!(db, loaded_db); + } +} diff --git a/src/database/mod.rs b/src/database/mod.rs new file mode 100644 index 0000000..204c719 --- /dev/null +++ b/src/database/mod.rs @@ -0,0 +1,18 @@ +pub mod core; +pub mod io; +pub mod query; +pub mod utils; + +use crate::Table; + +use std::collections::HashMap; +use std::path::PathBuf; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)] +pub struct Database { + pub(crate) name: String, + pub(crate) file_name: PathBuf, + pub(crate) tables: HashMap, +} + diff --git a/src/database/query.rs b/src/database/query.rs new file mode 100644 index 0000000..b1036cb --- /dev/null +++ b/src/database/query.rs @@ -0,0 +1,119 @@ +use crate::{Database, Operation, Query}; + +impl Database { + pub fn add_row(&mut self) -> Query { + Query { + db_file_name: self.file_name.clone(), + table_name: None, + operation: Operation::Create, + update_data: None, + row_data: None, + } + } + + pub fn get_rows(&self) -> Query { + Query { + db_file_name: self.file_name.clone(), + table_name: None, + operation: Operation::Read, + update_data: None, + row_data: None, + } + } + + pub fn get_single(&self) -> Query { + Query { + db_file_name: self.file_name.clone(), + table_name: None, + operation: Operation::Read, + update_data: None, + row_data: None, + } + } + + pub fn delete_single(&self) -> Query { + Query { + db_file_name: self.file_name.clone(), + table_name: None, + operation: Operation::Delete, + update_data: None, + row_data: None, + } + } + + pub fn update_row(&self) -> Query { + Query { + db_file_name: self.file_name.clone(), + table_name: None, + operation: Operation::Update, + update_data: None, + row_data: None, + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use std::collections::HashMap; + + #[tokio::test] + async fn test_add_row() { + let mut db = Database { + name: "test_db".to_string(), + file_name: "test_db.json".into(), + tables: HashMap::new(), + }; + + let query = db.add_row(); + assert_eq!(query.operation, Operation::Create); + } + + #[tokio::test] + async fn test_get_rows() { + let db = Database { + name: "test_db".to_string(), + file_name: "test_db.json".into(), + tables: HashMap::new(), + }; + + let query = db.get_rows(); + assert_eq!(query.operation, Operation::Read); + } + + #[tokio::test] + async fn test_get_single() { + let db = Database { + name: "test_db".to_string(), + file_name: "test_db.json".into(), + tables: HashMap::new(), + }; + + let query = db.get_single(); + assert_eq!(query.operation, Operation::Read); + } + + #[tokio::test] + async fn test_delete_single() { + let db = Database { + name: "test_db".to_string(), + file_name: "test_db.json".into(), + tables: HashMap::new(), + }; + + let query = db.delete_single(); + assert_eq!(query.operation, Operation::Delete); + } + + #[tokio::test] + async fn test_update_row() { + let db = Database { + name: "test_db".to_string(), + file_name: "test_db.json".into(), + tables: HashMap::new(), + }; + + let query = db.update_row(); + assert_eq!(query.operation, Operation::Update); + } +} diff --git a/src/database/utils.rs b/src/database/utils.rs new file mode 100644 index 0000000..e2b18de --- /dev/null +++ b/src/database/utils.rs @@ -0,0 +1,44 @@ +use crate::{Database, Table}; + +impl Database { + pub(crate) fn get_table_mut(&mut self, table_name: &str) -> Option<&mut Table> { + tracing::debug!("looking for table: {}", table_name); + let table = self.tables.get_mut(table_name); + + if let Some(_) = table { + tracing::debug!("table found: {}", table_name); + } else { + tracing::error!("table not found: {}", table_name); + } + + table + } +} + +#[cfg(test)] + +mod tests { + + use crate::{setup_temp_db, Table}; + use serde::{Deserialize, Serialize}; + + #[derive(Serialize, Deserialize, Debug, PartialEq, Clone, Default)] + struct TestData { + id: String, + name: String, + } + + #[tokio::test] + async fn test_get_table_mut() { + let mut db = setup_temp_db().await; + let test_columns = crate::Columns::from_struct::(true); + + let mut table = Table::new("test_table_mut".to_string(), test_columns.clone()); + db.add_table(&mut table) + .await + .expect("failed to add test_table_mut"); + + let table = db.get_table_mut("test_table_mut"); + assert!(table.is_some()); + } +} diff --git a/src/lib.rs b/src/lib.rs index efa0f46..2789330 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,3 @@ -pub mod database; pub mod query; pub mod table; pub mod util; @@ -8,12 +7,14 @@ pub mod columns; pub mod errors; pub mod row; +pub mod database; +pub use database::Database; + pub use columns::{Column, Columns}; pub use errors::DatabaseError; pub use row::Row; -pub use database::Database; -pub use query::Query; +pub use query::{Operation, Query}; pub use table::Table; pub use util::setup_temp_db; pub use view::View; diff --git a/src/table.rs b/src/table.rs index be14685..2ac3c30 100644 --- a/src/table.rs +++ b/src/table.rs @@ -48,6 +48,11 @@ impl Table { Ok(()) } + /* + * update this.... + * automatucally convert to Value + * let _ = serde_json::to_value(&data).unwrap(); + */ fn add_multiple_rows(&mut self, rows: &[Value]) -> Result<(), String> { for row in rows { self.add_single_row(row.clone())?; From 6c1f65d8d2976bf0f85a12509e7d6bff4aa1d2f5 Mon Sep 17 00:00:00 2001 From: giuseppe-g-gelardi Date: Wed, 18 Dec 2024 15:54:24 -0500 Subject: [PATCH 2/2] separate operations logic and components --- src/{ => database_components}/columns.rs | 0 src/database_components/mod.rs | 7 +++++++ src/{ => database_components}/row.rs | 0 src/{ => database_components}/table.rs | 0 src/{database => database_operations}/core.rs | 0 src/{database => database_operations}/io.rs | 0 src/{database => database_operations}/mod.rs | 0 src/{database => database_operations}/query.rs | 0 src/{database => database_operations}/utils.rs | 0 src/lib.rs | 13 +++++-------- 10 files changed, 12 insertions(+), 8 deletions(-) rename src/{ => database_components}/columns.rs (100%) create mode 100644 src/database_components/mod.rs rename src/{ => database_components}/row.rs (100%) rename src/{ => database_components}/table.rs (100%) rename src/{database => database_operations}/core.rs (100%) rename src/{database => database_operations}/io.rs (100%) rename src/{database => database_operations}/mod.rs (100%) rename src/{database => database_operations}/query.rs (100%) rename src/{database => database_operations}/utils.rs (100%) diff --git a/src/columns.rs b/src/database_components/columns.rs similarity index 100% rename from src/columns.rs rename to src/database_components/columns.rs diff --git a/src/database_components/mod.rs b/src/database_components/mod.rs new file mode 100644 index 0000000..0ad8a4b --- /dev/null +++ b/src/database_components/mod.rs @@ -0,0 +1,7 @@ +pub mod columns; +pub mod row; +pub mod table; + +pub use columns::{Column, Columns}; +pub use row::Row; +pub use table::Table; diff --git a/src/row.rs b/src/database_components/row.rs similarity index 100% rename from src/row.rs rename to src/database_components/row.rs diff --git a/src/table.rs b/src/database_components/table.rs similarity index 100% rename from src/table.rs rename to src/database_components/table.rs diff --git a/src/database/core.rs b/src/database_operations/core.rs similarity index 100% rename from src/database/core.rs rename to src/database_operations/core.rs diff --git a/src/database/io.rs b/src/database_operations/io.rs similarity index 100% rename from src/database/io.rs rename to src/database_operations/io.rs diff --git a/src/database/mod.rs b/src/database_operations/mod.rs similarity index 100% rename from src/database/mod.rs rename to src/database_operations/mod.rs diff --git a/src/database/query.rs b/src/database_operations/query.rs similarity index 100% rename from src/database/query.rs rename to src/database_operations/query.rs diff --git a/src/database/utils.rs b/src/database_operations/utils.rs similarity index 100% rename from src/database/utils.rs rename to src/database_operations/utils.rs diff --git a/src/lib.rs b/src/lib.rs index 2789330..e9e32da 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,20 +1,17 @@ pub mod query; -pub mod table; pub mod util; pub mod view; -pub mod columns; pub mod errors; -pub mod row; -pub mod database; -pub use database::Database; +pub mod database_components; +pub use database_components::{Column, Columns, Row, Table}; + +pub mod database_operations; +pub use database_operations::Database; -pub use columns::{Column, Columns}; pub use errors::DatabaseError; -pub use row::Row; pub use query::{Operation, Query}; -pub use table::Table; pub use util::setup_temp_db; pub use view::View;