Skip to content

Commit

Permalink
feat: add refresh method
Browse files Browse the repository at this point in the history
  • Loading branch information
vincent-herlemont committed Aug 18, 2024
1 parent b31f9a3 commit c3007bc
Show file tree
Hide file tree
Showing 4 changed files with 122 additions and 0 deletions.
12 changes: 12 additions & 0 deletions src/database.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::<Item1>().unwrap();
/// rw.refresh::<Item2>().unwrap();
/// rw.commit().unwrap();
/// }
/// ```
pub fn upgrading_from_version(&self, selector: &str) -> Result<bool> {
Expand Down
9 changes: 9 additions & 0 deletions src/transaction/internal/rw_transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -288,4 +288,13 @@ impl<'db> InternalRwTransaction<'db> {

Ok(())
}

pub fn refresh<T: ToInput + Debug>(&self) -> Result<()> {
for data in self.concrete_primary_drain(T::native_db_model())? {
let (decoded_item, _) = native_model::decode::<T>(data.0).unwrap();
let decoded_item = decoded_item.native_db_input()?;
self.concrete_insert(T::native_db_model(), decoded_item)?;
}
Ok(())
}
}
7 changes: 7 additions & 0 deletions src/transaction/rw_transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -368,4 +368,11 @@ impl<'db, 'txn> RwTransaction<'db> {
pub fn migrate<T: ToInput + Debug>(&self) -> Result<()> {
self.internal.migrate::<T>()
}

/// 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<T: ToInput + Debug>(&self) -> Result<()> {
self.internal.refresh::<T>()
}
}
94 changes: 94 additions & 0 deletions tests/refresh.rs
Original file line number Diff line number Diff line change
@@ -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<u32>,
#[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::<Item1>().unwrap();
models.define::<Item2>().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::<Item1>().unwrap();
rw.refresh::<Item2>().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));
}

0 comments on commit c3007bc

Please sign in to comment.