mirror of
https://github.com/zaphar/kitchen.git
synced 2025-07-22 19:40:14 -04:00
refactor: have two object stores
This commit is contained in:
parent
f75652befa
commit
84cc2a2713
@ -100,13 +100,13 @@ const APP_STATE_KEY: &'static str = "app-state";
|
|||||||
impl LocalStore {
|
impl LocalStore {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
store: DBFactory::new("app-state", Some(1)),
|
store: DBFactory::default(),
|
||||||
//old_store: js_lib::get_storage(),
|
//old_store: js_lib::get_storage(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn store_app_state(&self, state: &AppState) {
|
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) {
|
let state = match to_value(state) {
|
||||||
Ok(state) => state,
|
Ok(state) => state,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
@ -116,9 +116,9 @@ impl LocalStore {
|
|||||||
};
|
};
|
||||||
let key = to_value(APP_STATE_KEY).expect("Failed to serialize key");
|
let key = to_value(APP_STATE_KEY).expect("Failed to serialize key");
|
||||||
self.store
|
self.store
|
||||||
.rw_transaction(|trx| async move {
|
.rw_transaction(&[js_lib::STATE_STORE_NAME], |trx| async move {
|
||||||
let object_store = trx
|
let object_store = trx
|
||||||
.object_store(js_lib::STORE_NAME)
|
.object_store(js_lib::STATE_STORE_NAME)
|
||||||
.expect("Failed to get object store");
|
.expect("Failed to get object store");
|
||||||
object_store
|
object_store
|
||||||
.put_kv(
|
.put_kv(
|
||||||
@ -141,10 +141,10 @@ impl LocalStore {
|
|||||||
debug!("Loading state from local store");
|
debug!("Loading state from local store");
|
||||||
let recipes = parse_recipes(&self.get_recipes().await).expect("Failed to parse recipes");
|
let recipes = parse_recipes(&self.get_recipes().await).expect("Failed to parse recipes");
|
||||||
self.store
|
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 key = to_value(APP_STATE_KEY).expect("Failed to serialize key");
|
||||||
let object_store = trx
|
let object_store = trx
|
||||||
.object_store(js_lib::STORE_NAME)
|
.object_store(js_lib::STATE_STORE_NAME)
|
||||||
.expect("Failed to get object store");
|
.expect("Failed to get object store");
|
||||||
let mut app_state: AppState =
|
let mut app_state: AppState =
|
||||||
match object_store.get(&key).await.expect("Failed to read from") {
|
match object_store.get(&key).await.expect("Failed to read from") {
|
||||||
@ -185,10 +185,10 @@ impl LocalStore {
|
|||||||
/// Gets user data from local storage.
|
/// Gets user data from local storage.
|
||||||
pub async fn get_user_data(&self) -> Option<UserData> {
|
pub async fn get_user_data(&self) -> Option<UserData> {
|
||||||
self.store
|
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 key = to_value("user_data").expect("Failed to serialize key");
|
||||||
let object_store = trx
|
let object_store = trx
|
||||||
.object_store(js_lib::STORE_NAME)
|
.object_store(js_lib::STATE_STORE_NAME)
|
||||||
.expect("Failed to get object store");
|
.expect("Failed to get object store");
|
||||||
let user_data: UserData = match object_store
|
let user_data: UserData = match object_store
|
||||||
.get(&key)
|
.get(&key)
|
||||||
@ -215,9 +215,9 @@ impl LocalStore {
|
|||||||
if let Some(data) = data {
|
if let Some(data) = data {
|
||||||
let data = data.clone();
|
let data = data.clone();
|
||||||
self.store
|
self.store
|
||||||
.rw_transaction(|trx| async move {
|
.rw_transaction(&[js_lib::STATE_STORE_NAME], |trx| async move {
|
||||||
let object_store = trx
|
let object_store = trx
|
||||||
.object_store(js_lib::STORE_NAME)
|
.object_store(js_lib::STATE_STORE_NAME)
|
||||||
.expect("Failed to get object store");
|
.expect("Failed to get object store");
|
||||||
object_store
|
object_store
|
||||||
.put_kv(
|
.put_kv(
|
||||||
@ -239,9 +239,9 @@ impl LocalStore {
|
|||||||
// .expect("Failed to set user_data");
|
// .expect("Failed to set user_data");
|
||||||
} else {
|
} else {
|
||||||
self.store
|
self.store
|
||||||
.rw_transaction(|trx| async move {
|
.rw_transaction(&[js_lib::STATE_STORE_NAME], |trx| async move {
|
||||||
let object_store = trx
|
let object_store = trx
|
||||||
.object_store(js_lib::STORE_NAME)
|
.object_store(js_lib::STATE_STORE_NAME)
|
||||||
.expect("Failed to get object store");
|
.expect("Failed to get object store");
|
||||||
object_store
|
object_store
|
||||||
.delete(&key)
|
.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
|
self.store
|
||||||
.ro_transaction(|trx| async move {
|
.ro_transaction(&[js_lib::RECIPE_STORE_NAME], |trx| async move {
|
||||||
let mut keys = Vec::new();
|
let mut keys = Vec::new();
|
||||||
let object_store = trx
|
let object_store = trx
|
||||||
.object_store(js_lib::STORE_NAME)
|
.object_store(js_lib::RECIPE_STORE_NAME)
|
||||||
.expect("Failed to get object store");
|
.expect("Failed to get object store");
|
||||||
let key_vec = object_store
|
let key_vec = object_store
|
||||||
.get_all_keys(None)
|
.get_all_keys(None)
|
||||||
@ -277,39 +277,7 @@ impl LocalStore {
|
|||||||
Ok(keys)
|
Ok(keys)
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
.expect("Failed to get storage keys")
|
.expect("Failed to get storage keys").into_iter()
|
||||||
}
|
|
||||||
|
|
||||||
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:"))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets all the recipes from local storage.
|
/// 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 key = to_value(&recipe_key).expect("Failed to serialize key");
|
||||||
let entry = self
|
let entry = self
|
||||||
.store
|
.store
|
||||||
.ro_transaction(|trx| async move {
|
.ro_transaction(&[js_lib::RECIPE_STORE_NAME], |trx| async move {
|
||||||
let object_store = trx
|
let object_store = trx
|
||||||
.object_store(js_lib::STORE_NAME)
|
.object_store(js_lib::RECIPE_STORE_NAME)
|
||||||
.expect("Failed to get object store");
|
.expect("Failed to get object store");
|
||||||
let entry: Option<RecipeEntry> = match object_store
|
let entry: Option<RecipeEntry> = match object_store
|
||||||
.get(&key)
|
.get(&key)
|
||||||
@ -348,9 +316,9 @@ impl LocalStore {
|
|||||||
pub async fn get_recipe_entry(&self, id: &str) -> Option<RecipeEntry> {
|
pub async fn get_recipe_entry(&self, id: &str) -> Option<RecipeEntry> {
|
||||||
let key = to_value(&recipe_key(id)).expect("Failed to serialize key");
|
let key = to_value(&recipe_key(id)).expect("Failed to serialize key");
|
||||||
self.store
|
self.store
|
||||||
.ro_transaction(|trx| async move {
|
.ro_transaction(&[js_lib::RECIPE_STORE_NAME], |trx| async move {
|
||||||
let object_store = trx
|
let object_store = trx
|
||||||
.object_store(js_lib::STORE_NAME)
|
.object_store(js_lib::RECIPE_STORE_NAME)
|
||||||
.expect("Failed to get object store");
|
.expect("Failed to get object store");
|
||||||
let entry: Option<RecipeEntry> = match object_store
|
let entry: Option<RecipeEntry> = match object_store
|
||||||
.get(&key)
|
.get(&key)
|
||||||
@ -378,9 +346,9 @@ impl LocalStore {
|
|||||||
for recipe_key in self.get_recipe_keys().await {
|
for recipe_key in self.get_recipe_keys().await {
|
||||||
let key = to_value(&recipe_key).expect("Failed to serialize key");
|
let key = to_value(&recipe_key).expect("Failed to serialize key");
|
||||||
self.store
|
self.store
|
||||||
.rw_transaction(|trx| async move {
|
.rw_transaction(&[js_lib::STATE_STORE_NAME], |trx| async move {
|
||||||
let object_store = trx
|
let object_store = trx
|
||||||
.object_store(js_lib::STORE_NAME)
|
.object_store(js_lib::STATE_STORE_NAME)
|
||||||
.expect("Failed to get object store");
|
.expect("Failed to get object store");
|
||||||
object_store
|
object_store
|
||||||
.delete(&key)
|
.delete(&key)
|
||||||
@ -398,9 +366,9 @@ impl LocalStore {
|
|||||||
let entry = entry.clone();
|
let entry = entry.clone();
|
||||||
let key =
|
let key =
|
||||||
to_value(&recipe_key(entry.recipe_id())).expect("Failed to serialize recipe 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
|
let object_store = trx
|
||||||
.object_store(js_lib::STORE_NAME)
|
.object_store(js_lib::RECIPE_STORE_NAME)
|
||||||
.expect("Failed to get object store");
|
.expect("Failed to get object store");
|
||||||
object_store
|
object_store
|
||||||
.put_kv(
|
.put_kv(
|
||||||
@ -419,9 +387,9 @@ impl LocalStore {
|
|||||||
pub async fn set_recipe_entry(&self, entry: &RecipeEntry) {
|
pub async fn set_recipe_entry(&self, entry: &RecipeEntry) {
|
||||||
let entry = entry.clone();
|
let entry = entry.clone();
|
||||||
let key = to_value(&recipe_key(entry.recipe_id())).expect("Failed to serialize recipe key");
|
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
|
let object_store = trx
|
||||||
.object_store(js_lib::STORE_NAME)
|
.object_store(js_lib::RECIPE_STORE_NAME)
|
||||||
.expect("Failed to get object store");
|
.expect("Failed to get object store");
|
||||||
object_store
|
object_store
|
||||||
.put_kv(
|
.put_kv(
|
||||||
@ -445,9 +413,9 @@ impl LocalStore {
|
|||||||
pub async fn delete_recipe_entry(&self, recipe_id: &str) {
|
pub async fn delete_recipe_entry(&self, recipe_id: &str) {
|
||||||
let key = to_value(recipe_id).expect("Failed to serialize key");
|
let key = to_value(recipe_id).expect("Failed to serialize key");
|
||||||
self.store
|
self.store
|
||||||
.rw_transaction(|trx| async move {
|
.rw_transaction(&[js_lib::RECIPE_STORE_NAME], |trx| async move {
|
||||||
let object_store = trx
|
let object_store = trx
|
||||||
.object_store(js_lib::STORE_NAME)
|
.object_store(js_lib::RECIPE_STORE_NAME)
|
||||||
.expect("Failed to get object store");
|
.expect("Failed to get object store");
|
||||||
object_store
|
object_store
|
||||||
.delete(&key)
|
.delete(&key)
|
||||||
|
@ -25,7 +25,9 @@ pub fn get_storage() -> web_sys::Storage {
|
|||||||
.expect("No storage available")
|
.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)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct DBFactory<'name> {
|
pub struct DBFactory<'name> {
|
||||||
@ -33,11 +35,13 @@ pub struct DBFactory<'name> {
|
|||||||
version: Option<u32>,
|
version: Option<u32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'name> DBFactory<'name> {
|
impl Default for DBFactory<'static> {
|
||||||
pub fn new(name: &'name str, version: Option<u32>) -> Self {
|
fn default() -> Self {
|
||||||
Self { name, version }
|
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>> {
|
pub async fn get_indexed_db(&self) -> Result<Database<std::io::Error>> {
|
||||||
let factory = Factory::<std::io::Error>::get().context("opening IndexedDB")?;
|
let factory = Factory::<std::io::Error>::get().context("opening IndexedDB")?;
|
||||||
let db = factory.open(self.name, self.version.unwrap_or(0), |evt| async move {
|
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.
|
// NOTE(jwall): This needs to be somewhat clever in handling version upgrades.
|
||||||
if db.version() == 1 {
|
if db.version() == 1 {
|
||||||
// We use out of line keys for this object store
|
// 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(())
|
Ok(())
|
||||||
}).await.context(format!("Opening or creating the database {}", self.name))?;
|
}).await.context(format!("Opening or creating the database {}", self.name))?;
|
||||||
Ok(db)
|
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
|
where
|
||||||
Fun: 'static + FnOnce(Transaction<std::io::Error>) -> RetFut,
|
Fun: 'static + FnOnce(Transaction<std::io::Error>) -> RetFut,
|
||||||
RetFut: 'static + Future<Output = indexed_db::Result<Ret, std::io::Error>>,
|
RetFut: 'static + Future<Output = indexed_db::Result<Ret, std::io::Error>>,
|
||||||
Ret: 'static,
|
Ret: 'static,
|
||||||
{
|
{
|
||||||
self.get_indexed_db().await.expect("Failed to open database")
|
self.get_indexed_db().await.expect("Failed to open database")
|
||||||
.transaction(&[STORE_NAME]).rw()
|
.transaction(stores).rw()
|
||||||
.run(transaction).await
|
.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
|
where
|
||||||
Fun: 'static + FnOnce(Transaction<std::io::Error>) -> RetFut,
|
Fun: 'static + FnOnce(Transaction<std::io::Error>) -> RetFut,
|
||||||
RetFut: 'static + Future<Output = indexed_db::Result<Ret, std::io::Error>>,
|
RetFut: 'static + Future<Output = indexed_db::Result<Ret, std::io::Error>>,
|
||||||
Ret: 'static,
|
Ret: 'static,
|
||||||
{
|
{
|
||||||
self.get_indexed_db().await.expect("Failed to open database")
|
self.get_indexed_db().await.expect("Failed to open database")
|
||||||
.transaction(&[STORE_NAME])
|
.transaction(stores)
|
||||||
.run(transaction).await
|
.run(transaction).await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user