diff --git a/src/database.rs b/src/database.rs index 1594701..ca095af 100644 --- a/src/database.rs +++ b/src/database.rs @@ -148,6 +148,14 @@ impl<'a> Database<'a> { &self.metadata } + /// Compact the database. + /// + /// Similar to [redb::Database::compact()](https://docs.rs/redb/latest/redb/struct.Database.html#method.compact). + pub fn compact(&mut self) -> Result { + self.instance.redb_database_mut()?.compact()?; + Ok(true) + } + /// Returns true if the database is upgrading from the given version selector. /// /// - If the database is the old version, not matching the selector the function will return `false. diff --git a/src/database_instance.rs b/src/database_instance.rs index c0c219f..306f067 100644 --- a/src/database_instance.rs +++ b/src/database_instance.rs @@ -39,6 +39,10 @@ impl DatabaseInstance { pub(crate) fn redb_database(&self) -> Result<&redb::Database> { self.kind.redb_database() } + + pub(crate) fn redb_database_mut(&mut self) -> Result<&mut redb::Database> { + self.kind.redb_database_mut() + } } enum DatabaseInstanceKind { @@ -59,4 +63,11 @@ impl DatabaseInstanceKind { DatabaseInstanceKind::OnDisk { redb_database, .. } => Ok(redb_database), } } + + pub(crate) fn redb_database_mut(&mut self) -> Result<&mut redb::Database> { + match self { + DatabaseInstanceKind::InMemory { redb_database } => Ok(redb_database), + DatabaseInstanceKind::OnDisk { redb_database, .. } => Ok(redb_database), + } + } } diff --git a/src/lib.rs b/src/lib.rs index 9d295f5..6eb57d5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -23,6 +23,7 @@ //! - [`create`](crate::Builder::create) - Create a database in a file. //! - [`open`](crate::Builder::open) - Open a database. //! - [`Database`] - Database instance. +//! - [`compact`](crate::Database::compact) - Compact the database. //! - [`rw_transaction`](crate::Database::rw_transaction) - Create a read-write transaction. //! - [`insert`](crate::transaction::RwTransaction::insert) - Insert a item, fail if the item already exists. //! - [`upsert`](crate::transaction::RwTransaction::upsert) - Upsert a item, update if the item already exists. diff --git a/tests/compact.rs b/tests/compact.rs new file mode 100644 index 0000000..3110396 --- /dev/null +++ b/tests/compact.rs @@ -0,0 +1,48 @@ +use native_db::*; +use native_model::{native_model, Model}; +use serde::{Deserialize, Serialize}; +use shortcut_assert_fs::TmpFs; + +#[derive(Serialize, Deserialize, Eq, PartialEq, Debug, Clone)] +#[native_model(id = 1, version = 1)] +#[native_db] +struct Item { + #[primary_key] + id: u32, + name: String, +} + +#[test] +fn test_compact() { + let tf = TmpFs::new().unwrap(); + let db_path = tf.path("test"); + + let mut models = Models::new(); + models.define::().unwrap(); + let mut db = Builder::new().create(&models, db_path.clone()).unwrap(); + + // Insert 1000 items + let rw = db.rw_transaction().unwrap(); + for i in 0..999 { + rw.insert(Item { + id: i, + name: format!("test_{}", i), + }) + .unwrap(); + } + rw.commit().unwrap(); + + // Check the size of the database + let metadata = std::fs::metadata(db_path.clone()).unwrap(); + let file_size = metadata.len(); + assert_eq!(file_size, 1589248); + dbg!(file_size); + + let out = db.compact().unwrap(); + assert!(out); + + // Check the size of the compacted database + let metadata = std::fs::metadata(db_path.clone()).unwrap(); + let file_size = metadata.len(); + assert_eq!(file_size, 700416); +}