From 783aa5fd32344611f173539ee5fd294fab3606c7 Mon Sep 17 00:00:00 2001 From: giuseppe-g-gelardi Date: Sun, 1 Dec 2024 20:42:14 -0500 Subject: [PATCH] update cargo.toml for development other wise async is pain. prepare to setup for separate crates to reduce confusion --- Cargo.toml | 3 ++- src/cargobase/database.rs | 46 +++++++++++++++++++++++++++++++++ src/cargobase/mod.rs | 7 +++-- src/cargobase/util.rs | 54 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 107 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index c82834f..53950ee 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,7 +18,8 @@ tracing-subscriber = "0.3" tracing-test = "0.2.5" [features] -default = ["sync"] +default = ["sync", "async"] # for development +# default = ["sync"] sync = [] # synchronous features only async = ["tokio"] # asynchronous features only full = ["sync", "async"] # all features diff --git a/src/cargobase/database.rs b/src/cargobase/database.rs index 4d45ff4..b6f8dd0 100644 --- a/src/cargobase/database.rs +++ b/src/cargobase/database.rs @@ -41,6 +41,36 @@ impl Database { } } + #[cfg(feature = "async")] + pub async fn new_async(name: &str) -> Self { + let name = name.to_string(); + let file_name = format!("{name}.json"); + + if tokio::fs::metadata(&file_name).await.is_ok() { + tracing::info!("Database already exists: {name}, loading database"); + + // Load the database from the file + match Database::load_from_file_async(&file_name).await { + Ok(db) => return db, + Err(e) => { + tracing::error!("Failed to load database from file: {file_name}, error: {e}"); + } + } + } else { + tracing::info!("Creating new database: {file_name}"); + // Create an empty JSON file for the new database + if let Err(e) = tokio::fs::write(&file_name, "{}").await { + tracing::error!("Failed to create database file: {e}"); + } + } + + Database { + name, + file_name, + tables: Vec::new(), + } + } + pub fn drop_database(&self) -> Result<(), DatabaseError> { if std::fs::remove_file(&self.file_name).is_err() { tracing::error!( @@ -188,6 +218,9 @@ mod tests { use crate::cargobase::setup_temp_db; use crate::{Columns, Table}; + #[cfg(feature = "async")] + use crate::cargobase::setup_temp_db_async; + #[derive(Serialize, Deserialize, Debug, PartialEq, Clone, Default)] struct TestData { id: String, @@ -206,6 +239,19 @@ mod tests { assert_eq!(db.tables.len(), 1); // the setup_temp_db function adds a table } + #[cfg(feature = "async")] + #[tokio::test] + async fn test_database_new_async() { + let db = setup_temp_db_async().await; + + let db_name = &db.name.to_string(); + let fnn = format!("{db_name}.json"); + + assert_eq!(db.name, db_name.to_string()); + assert_eq!(db.file_name, fnn); + assert_eq!(db.tables.len(), 1); // the setup_temp_db function adds a table + } + #[test] fn test_drop_database() { let db = setup_temp_db(); diff --git a/src/cargobase/mod.rs b/src/cargobase/mod.rs index eeb1d03..edf3740 100644 --- a/src/cargobase/mod.rs +++ b/src/cargobase/mod.rs @@ -1,17 +1,20 @@ pub mod columns; pub mod database; +pub mod errors; pub mod query; pub mod row; pub mod table; pub mod util; -pub mod errors; pub mod view; pub use columns::{Column, Columns}; pub use database::Database; +pub use errors::errors::DatabaseError; pub use query::Query; pub use row::Row; pub use table::Table; pub use util::setup_temp_db; -pub use errors::errors::DatabaseError; pub use view::View; + +#[cfg(feature = "async")] +pub use util::setup_temp_db_async; diff --git a/src/cargobase/util.rs b/src/cargobase/util.rs index 6e72da6..2bb63f2 100644 --- a/src/cargobase/util.rs +++ b/src/cargobase/util.rs @@ -3,6 +3,9 @@ use tempfile::NamedTempFile; use super::{Columns, Database, Table}; +// #[cfg(feature = "async")] +// use tokio::fs; + #[derive(Serialize, Deserialize, Debug, PartialEq, Clone, Default)] struct TestData { id: String, @@ -24,6 +27,25 @@ pub fn setup_temp_db() -> Database { db } +#[cfg(feature = "async")] +pub async fn setup_temp_db_async() -> Database { + let temp_file = NamedTempFile::new().expect("Failed to create a temporary file"); + let db_path = temp_file.path().to_str().unwrap().to_string(); + + // Initialize the test database + let mut db = Database::new_async(&db_path).await; + let test_columns = Columns::from_struct::(true); + + let mut table = Table::new("TestTable".to_string(), test_columns); + db.add_table(&mut table).unwrap(); + + db.save_to_file_async() + .await + .expect("Failed to save database"); + + db +} + #[cfg(test)] mod tests { use super::*; @@ -53,4 +75,36 @@ mod tests { db_path ); } + + #[cfg(feature = "async")] + #[tokio::test] + async fn test_setup_temp_db_async() { + let db = setup_temp_db_async().await; + assert_eq!(db.tables.len(), 1); + assert_eq!(db.tables[0].name, "TestTable"); + } + + #[cfg(feature = "async")] + #[tokio::test] + async fn test_temp_file_cleanup_async() { + // Create a temporary database + let temp_file = tempfile::Builder::new() + .prefix("test_db") + .suffix(".json") + .tempfile() + .expect("Failed to create a temporary file"); + + let db_path = temp_file.path().to_str().unwrap().to_string(); + + // Drop the file explicitly by dropping the `NamedTempFile` instance + drop(temp_file); + + // Verify that the temporary file is removed + let file_exists = fs::metadata(&db_path).is_ok(); + assert!( + !file_exists, + "Temporary file `{}` should have been removed after being dropped", + db_path + ); + } }