diff --git a/web/src/api.rs b/web/src/api.rs index 8b3ca4e..9a01279 100644 --- a/web/src/api.rs +++ b/web/src/api.rs @@ -100,13 +100,13 @@ const APP_STATE_KEY: &'static str = "app-state"; impl LocalStore { pub fn new() -> Self { Self { - store: DBFactory::new("app-state", Some(1)), + store: DBFactory::default(), //old_store: js_lib::get_storage(), } } pub async fn store_app_state(&self, state: &AppState) { - self.migrate_local_store().await; + //self.migrate_local_store().await; let state = match to_value(state) { Ok(state) => state, Err(err) => { @@ -116,9 +116,9 @@ impl LocalStore { }; let key = to_value(APP_STATE_KEY).expect("Failed to serialize key"); self.store - .rw_transaction(|trx| async move { + .rw_transaction(&[js_lib::STATE_STORE_NAME], |trx| async move { let object_store = trx - .object_store(js_lib::STORE_NAME) + .object_store(js_lib::STATE_STORE_NAME) .expect("Failed to get object store"); object_store .put_kv( @@ -141,10 +141,10 @@ impl LocalStore { debug!("Loading state from local store"); let recipes = parse_recipes(&self.get_recipes().await).expect("Failed to parse recipes"); self.store - .ro_transaction(|trx| async move { + .ro_transaction(&[js_lib::STATE_STORE_NAME], |trx| async move { let key = to_value(APP_STATE_KEY).expect("Failed to serialize key"); let object_store = trx - .object_store(js_lib::STORE_NAME) + .object_store(js_lib::STATE_STORE_NAME) .expect("Failed to get object store"); let mut app_state: AppState = match object_store.get(&key).await.expect("Failed to read from") { @@ -185,10 +185,10 @@ impl LocalStore { /// Gets user data from local storage. pub async fn get_user_data(&self) -> Option { self.store - .ro_transaction(|trx| async move { + .ro_transaction(&[js_lib::STATE_STORE_NAME], |trx| async move { let key = to_value("user_data").expect("Failed to serialize key"); let object_store = trx - .object_store(js_lib::STORE_NAME) + .object_store(js_lib::STATE_STORE_NAME) .expect("Failed to get object store"); let user_data: UserData = match object_store .get(&key) @@ -215,9 +215,9 @@ impl LocalStore { if let Some(data) = data { let data = data.clone(); self.store - .rw_transaction(|trx| async move { + .rw_transaction(&[js_lib::STATE_STORE_NAME], |trx| async move { let object_store = trx - .object_store(js_lib::STORE_NAME) + .object_store(js_lib::STATE_STORE_NAME) .expect("Failed to get object store"); object_store .put_kv( @@ -239,9 +239,9 @@ impl LocalStore { // .expect("Failed to set user_data"); } else { self.store - .rw_transaction(|trx| async move { + .rw_transaction(&[js_lib::STATE_STORE_NAME], |trx| async move { let object_store = trx - .object_store(js_lib::STORE_NAME) + .object_store(js_lib::STATE_STORE_NAME) .expect("Failed to get object store"); object_store .delete(&key) @@ -258,12 +258,12 @@ impl LocalStore { } } - async fn get_storage_keys(&self) -> Vec { + async fn get_recipe_keys(&self) -> impl Iterator { self.store - .ro_transaction(|trx| async move { + .ro_transaction(&[js_lib::RECIPE_STORE_NAME], |trx| async move { let mut keys = Vec::new(); let object_store = trx - .object_store(js_lib::STORE_NAME) + .object_store(js_lib::RECIPE_STORE_NAME) .expect("Failed to get object store"); let key_vec = object_store .get_all_keys(None) @@ -277,39 +277,7 @@ impl LocalStore { Ok(keys) }) .await - .expect("Failed to get storage keys") - } - - async fn migrate_local_store(&self) { - // FIXME(zaphar): Migration from local storage to indexed db - for k in self.get_storage_keys().await.into_iter().filter(|k| { - k.starts_with("categor") || k == "inventory" || k.starts_with("plan") || k == "staples" - }) { - // Deleting old local store key - let key = to_value(&k).expect("Failed to serialize key"); - self.store - .rw_transaction(|trx| async move { - let object_store = trx - .object_store(js_lib::STORE_NAME) - .expect("Failed to get object store"); - object_store - .delete(&key) - .await - .expect("Failed to delete user_data"); - Ok(()) - }) - .await - .expect("Failed to delete user_data"); - //debug!("Deleting old local store key {}", k); - //self.store.delete(&k).expect("Failed to delete storage key"); - } - } - - async fn get_recipe_keys(&self) -> impl Iterator { - self.get_storage_keys() - .await - .into_iter() - .filter(|k| k.starts_with("recipe:")) + .expect("Failed to get storage keys").into_iter() } /// Gets all the recipes from local storage. @@ -319,9 +287,9 @@ impl LocalStore { let key = to_value(&recipe_key).expect("Failed to serialize key"); let entry = self .store - .ro_transaction(|trx| async move { + .ro_transaction(&[js_lib::RECIPE_STORE_NAME], |trx| async move { let object_store = trx - .object_store(js_lib::STORE_NAME) + .object_store(js_lib::RECIPE_STORE_NAME) .expect("Failed to get object store"); let entry: Option = match object_store .get(&key) @@ -348,9 +316,9 @@ impl LocalStore { pub async fn get_recipe_entry(&self, id: &str) -> Option { let key = to_value(&recipe_key(id)).expect("Failed to serialize key"); self.store - .ro_transaction(|trx| async move { + .ro_transaction(&[js_lib::RECIPE_STORE_NAME], |trx| async move { let object_store = trx - .object_store(js_lib::STORE_NAME) + .object_store(js_lib::RECIPE_STORE_NAME) .expect("Failed to get object store"); let entry: Option = match object_store .get(&key) @@ -378,9 +346,9 @@ impl LocalStore { for recipe_key in self.get_recipe_keys().await { let key = to_value(&recipe_key).expect("Failed to serialize key"); self.store - .rw_transaction(|trx| async move { + .rw_transaction(&[js_lib::STATE_STORE_NAME], |trx| async move { let object_store = trx - .object_store(js_lib::STORE_NAME) + .object_store(js_lib::STATE_STORE_NAME) .expect("Failed to get object store"); object_store .delete(&key) @@ -398,9 +366,9 @@ impl LocalStore { let entry = entry.clone(); let key = to_value(&recipe_key(entry.recipe_id())).expect("Failed to serialize recipe key"); - self.store.rw_transaction(|trx| async move { + self.store.rw_transaction(&[js_lib::RECIPE_STORE_NAME], |trx| async move { let object_store = trx - .object_store(js_lib::STORE_NAME) + .object_store(js_lib::RECIPE_STORE_NAME) .expect("Failed to get object store"); object_store .put_kv( @@ -419,9 +387,9 @@ impl LocalStore { pub async fn set_recipe_entry(&self, entry: &RecipeEntry) { let entry = entry.clone(); let key = to_value(&recipe_key(entry.recipe_id())).expect("Failed to serialize recipe key"); - self.store.rw_transaction(|trx| async move { + self.store.rw_transaction(&[js_lib::RECIPE_STORE_NAME], |trx| async move { let object_store = trx - .object_store(js_lib::STORE_NAME) + .object_store(js_lib::RECIPE_STORE_NAME) .expect("Failed to get object store"); object_store .put_kv( @@ -445,9 +413,9 @@ impl LocalStore { pub async fn delete_recipe_entry(&self, recipe_id: &str) { let key = to_value(recipe_id).expect("Failed to serialize key"); self.store - .rw_transaction(|trx| async move { + .rw_transaction(&[js_lib::RECIPE_STORE_NAME], |trx| async move { let object_store = trx - .object_store(js_lib::STORE_NAME) + .object_store(js_lib::RECIPE_STORE_NAME) .expect("Failed to get object store"); object_store .delete(&key) diff --git a/web/src/js_lib.rs b/web/src/js_lib.rs index 3ac6a3c..817d462 100644 --- a/web/src/js_lib.rs +++ b/web/src/js_lib.rs @@ -25,7 +25,9 @@ pub fn get_storage() -> web_sys::Storage { .expect("No storage available") } -pub const STORE_NAME: &'static str = "state-store"; +pub const STATE_STORE_NAME: &'static str = "state-store"; +pub const RECIPE_STORE_NAME: &'static str = "recipe-store"; +pub const DB_VERSION: u32 = 1; #[derive(Clone, Debug)] pub struct DBFactory<'name> { @@ -33,11 +35,13 @@ pub struct DBFactory<'name> { version: Option, } -impl<'name> DBFactory<'name> { - pub fn new(name: &'name str, version: Option) -> Self { - Self { name, version } +impl Default for DBFactory<'static> { + fn default() -> Self { + DBFactory { name: STATE_STORE_NAME, version: Some(DB_VERSION) } } +} +impl<'name> DBFactory<'name> { pub async fn get_indexed_db(&self) -> Result> { let factory = Factory::::get().context("opening IndexedDB")?; let db = factory.open(self.name, self.version.unwrap_or(0), |evt| async move { @@ -47,32 +51,34 @@ impl<'name> DBFactory<'name> { // NOTE(jwall): This needs to be somewhat clever in handling version upgrades. if db.version() == 1 { // We use out of line keys for this object store - db.build_object_store(STORE_NAME).create()?; + db.build_object_store(STATE_STORE_NAME).create()?; + db.build_object_store(RECIPE_STORE_NAME).create()?; + // TODO(jwall): Do we need indexes? } Ok(()) }).await.context(format!("Opening or creating the database {}", self.name))?; Ok(db) } - pub async fn rw_transaction(&self, transaction: Fun) -> indexed_db::Result + pub async fn rw_transaction(&self, stores: &[&str], transaction: Fun) -> indexed_db::Result where Fun: 'static + FnOnce(Transaction) -> RetFut, RetFut: 'static + Future>, Ret: 'static, { self.get_indexed_db().await.expect("Failed to open database") - .transaction(&[STORE_NAME]).rw() + .transaction(stores).rw() .run(transaction).await } - pub async fn ro_transaction(&self, transaction: Fun) -> indexed_db::Result + pub async fn ro_transaction(&self, stores: &[&str], transaction: Fun) -> indexed_db::Result where Fun: 'static + FnOnce(Transaction) -> RetFut, RetFut: 'static + Future>, Ret: 'static, { self.get_indexed_db().await.expect("Failed to open database") - .transaction(&[STORE_NAME]) + .transaction(stores) .run(transaction).await } }