diff --git a/src/database.rs b/src/database.rs index 9b86001..b5298c6 100644 --- a/src/database.rs +++ b/src/database.rs @@ -150,12 +150,24 @@ impl<'a> Database<'a> { /// 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. + /// - If the database is not upgrading, the function will return always `false`. + /// + /// Generally used with the method [refresh](crate::transaction::RwTransaction::refresh), + /// to refresh the data for the given model. + /// + /// Check [release notes](https://github.com/vincent-herlemont/native_db/releases) to know when to use this method. + /// /// # Example /// ```rust,ignore /// if db.upgrading_from_version("<0.8.0") { /// // Do something that runs only when the database is upgrading from version <0.8.0. /// // If the database is already at version 0.8.0, the function will return false and /// // the code will not be executed. + /// let rw = db.rw_transaction().unwrap(); + /// rw.refresh::().unwrap(); + /// rw.refresh::().unwrap(); + /// rw.commit().unwrap(); /// } /// ``` pub fn upgrading_from_version(&self, selector: &str) -> Result { diff --git a/src/transaction/internal/rw_transaction.rs b/src/transaction/internal/rw_transaction.rs index a0b21de..fbe72ba 100644 --- a/src/transaction/internal/rw_transaction.rs +++ b/src/transaction/internal/rw_transaction.rs @@ -288,4 +288,13 @@ impl<'db> InternalRwTransaction<'db> { Ok(()) } + + pub fn refresh(&self) -> Result<()> { + for data in self.concrete_primary_drain(T::native_db_model())? { + let (decoded_item, _) = native_model::decode::(data.0).unwrap(); + let decoded_item = decoded_item.native_db_input()?; + self.concrete_insert(T::native_db_model(), decoded_item)?; + } + Ok(()) + } } diff --git a/src/transaction/rw_transaction.rs b/src/transaction/rw_transaction.rs index e4bdd99..59a526a 100644 --- a/src/transaction/rw_transaction.rs +++ b/src/transaction/rw_transaction.rs @@ -368,4 +368,11 @@ impl<'db, 'txn> RwTransaction<'db> { pub fn migrate(&self) -> Result<()> { self.internal.migrate::() } + + /// Refresh the data for the given model. Is used generally when during an database upgrade, + /// using the method [crate::Database::upgrading_from_version] (more details/example). Check release notes to know + /// when to use this method. + pub fn refresh(&self) -> Result<()> { + self.internal.refresh::() + } } diff --git a/tests/refresh.rs b/tests/refresh.rs new file mode 100644 index 0000000..0a4b6cc --- /dev/null +++ b/tests/refresh.rs @@ -0,0 +1,94 @@ +use native_db::*; +use native_model::{native_model, Model}; +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Eq, PartialEq, Clone, Debug)] +#[native_model(id = 1, version = 1)] +#[native_db] +struct Item1 { + #[primary_key] + id: u32, + #[secondary_key(unique)] + name: String, +} + +#[derive(Serialize, Deserialize, Eq, PartialEq, Clone, Debug)] +#[native_model(id = 2, version = 1)] +#[native_db] +struct Item2 { + #[primary_key] + id: u32, + #[secondary_key(optional)] + id2: Option, + #[secondary_key] + name: String, +} + +#[test] +fn test_refresh() { + use std::path::PathBuf; + println!("test_refresh"); + #[cfg(any(target_os = "android", target_os = "ios"))] + let database_path = { dinghy_test::test_project_path().join("tests/data/db_0_7_1") }; + + #[cfg(not(any(target_os = "android", target_os = "ios")))] + let database_path = { + let root_project_path = env!("CARGO_MANIFEST_DIR"); + PathBuf::from(format!("{}/tests/data/db_0_7_1", root_project_path)) + }; + + use shortcut_assert_fs::TmpFs; + let tmp = TmpFs::new().unwrap(); + + // Copy the legacy database to the temporary directory. + let tmp_database_path = tmp.path("db_0_7_1"); + std::fs::copy(&database_path, &tmp_database_path).unwrap(); + + // Open the legacy database with the upgrade feature. This must succeed. + let mut models = Models::new(); + models.define::().unwrap(); + models.define::().unwrap(); + let db = Builder::new().open(&models, &tmp_database_path).unwrap(); + // TODO: during open, the database must be upgraded to the latest version. + + tmp.display_dir_entries(); + let stats = db.redb_stats().unwrap(); + dbg!(&stats); + assert_eq!(stats.primary_tables.len(), 2); + assert_eq!(stats.primary_tables[0].name, "1_1_id"); + assert_eq!(stats.primary_tables[0].n_entries, Some(1)); + assert_eq!(stats.primary_tables[1].name, "2_1_id"); + assert_eq!(stats.primary_tables[1].n_entries, Some(1000)); + assert_eq!(stats.secondary_tables.len(), 3); + assert_eq!(stats.secondary_tables[0].name, "1_1_name"); + assert_eq!(stats.secondary_tables[0].n_entries, Some(1)); + assert_eq!(stats.secondary_tables[1].name, "2_1_id2"); + assert_eq!(stats.secondary_tables[1].n_entries, Some(500)); + assert_eq!(stats.secondary_tables[2].name, "2_1_name"); + assert_eq!(stats.secondary_tables[2].n_entries, Some(1000)); + + // Is not usefull but it's generaly used with the method upgrading_from_version. + if db.upgrading_from_version("<0.8.0").unwrap() { + // Refresh the database + let rw = db.rw_transaction().unwrap(); + rw.refresh::().unwrap(); + rw.refresh::().unwrap(); + rw.commit().unwrap(); + } else { + assert!(false); + } + + let stats = db.redb_stats().unwrap(); + assert_eq!(stats.primary_tables.len(), 2); + assert_eq!(stats.primary_tables[0].name, "1_1_id"); + assert_eq!(stats.primary_tables[0].n_entries, Some(1)); + assert_eq!(stats.primary_tables[1].name, "2_1_id"); + assert_eq!(stats.primary_tables[1].n_entries, Some(1000)); + assert_eq!(stats.secondary_tables.len(), 3); + assert_eq!(stats.secondary_tables[0].name, "1_1_name"); + assert_eq!(stats.secondary_tables[0].n_entries, Some(1)); + assert_eq!(stats.secondary_tables[1].name, "2_1_id2"); + assert_eq!(stats.secondary_tables[1].n_entries, Some(500)); + assert_eq!(stats.secondary_tables[2].name, "2_1_name"); + assert_eq!(stats.secondary_tables[2].n_entries, Some(1000)); +}