refactor: have two object stores

This commit is contained in:
Jeremy Wall 2024-07-12 01:15:29 -04:00
parent f75652befa
commit 84cc2a2713
2 changed files with 43 additions and 69 deletions

View File

@ -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<UserData> {
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<String> {
async fn get_recipe_keys(&self) -> impl Iterator<Item = String> {
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<Item = String> {
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<RecipeEntry> = match object_store
.get(&key)
@ -348,9 +316,9 @@ impl LocalStore {
pub async fn get_recipe_entry(&self, id: &str) -> Option<RecipeEntry> {
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<RecipeEntry> = 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)

View File

@ -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<u32>,
}
impl<'name> DBFactory<'name> {
pub fn new(name: &'name str, version: Option<u32>) -> 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<Database<std::io::Error>> {
let factory = Factory::<std::io::Error>::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<Fun, RetFut, Ret>(&self, transaction: Fun) -> indexed_db::Result<Ret, std::io::Error>
pub async fn rw_transaction<Fun, RetFut, Ret>(&self, stores: &[&str], transaction: Fun) -> indexed_db::Result<Ret, std::io::Error>
where
Fun: 'static + FnOnce(Transaction<std::io::Error>) -> RetFut,
RetFut: 'static + Future<Output = indexed_db::Result<Ret, std::io::Error>>,
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<Fun, RetFut, Ret>(&self, transaction: Fun) -> indexed_db::Result<Ret, std::io::Error>
pub async fn ro_transaction<Fun, RetFut, Ret>(&self, stores: &[&str], transaction: Fun) -> indexed_db::Result<Ret, std::io::Error>
where
Fun: 'static + FnOnce(Transaction<std::io::Error>) -> RetFut,
RetFut: 'static + Future<Output = indexed_db::Result<Ret, std::io::Error>>,
Ret: 'static,
{
self.get_indexed_db().await.expect("Failed to open database")
.transaction(&[STORE_NAME])
.transaction(stores)
.run(transaction).await
}
}