Add create or existing

This commit is contained in:
Tony
2024-10-05 16:21:27 +08:00
parent 7faf8c31e0
commit dc5be009b7
9 changed files with 193 additions and 21 deletions
+47 -9
View File
@@ -57,17 +57,15 @@ enum AutoSave {
Bool(bool),
}
#[tauri::command]
async fn create_store<R: Runtime>(
fn builder<R: Runtime>(
app: AppHandle<R>,
store_state: State<'_, StoreState>,
path: PathBuf,
auto_save: Option<AutoSave>,
serialize_fn_name: Option<String>,
deserialize_fn_name: Option<String>,
) -> Result<ResourceId> {
let mut builder = app.store_builder(path.clone());
) -> Result<StoreBuilder<R>> {
let mut builder = app.store_builder(path);
if let Some(auto_save) = auto_save {
match auto_save {
AutoSave::DebounceDuration(duration) => {
@@ -95,11 +93,51 @@ async fn create_store<R: Runtime>(
.ok_or_else(|| crate::Error::DeserializeFunctionNotFound(deserialize_fn_name))?;
builder = builder.deserialize(*deserialize_fn);
}
Ok(builder)
}
#[tauri::command]
async fn create_store<R: Runtime>(
app: AppHandle<R>,
store_state: State<'_, StoreState>,
path: PathBuf,
auto_save: Option<AutoSave>,
serialize_fn_name: Option<String>,
deserialize_fn_name: Option<String>,
) -> Result<ResourceId> {
let builder = builder(
app,
store_state,
path,
auto_save,
serialize_fn_name,
deserialize_fn_name,
)?;
let (_, rid) = builder.build_inner()?;
Ok(rid)
}
#[tauri::command]
async fn create_or_existing_store<R: Runtime>(
app: AppHandle<R>,
store_state: State<'_, StoreState>,
path: PathBuf,
auto_save: Option<AutoSave>,
serialize_fn_name: Option<String>,
deserialize_fn_name: Option<String>,
) -> Result<ResourceId> {
let builder = builder(
app,
store_state,
path,
auto_save,
serialize_fn_name,
deserialize_fn_name,
)?;
let (_, rid) = builder.build_or_existing_inner();
Ok(rid)
}
#[tauri::command]
async fn get_store<R: Runtime>(
app: AppHandle<R>,
@@ -107,7 +145,7 @@ async fn get_store<R: Runtime>(
path: PathBuf,
) -> Result<Option<ResourceId>> {
let stores = store_state.stores.lock().unwrap();
Ok(stores.get(&resolve_store_path(app, path)).copied())
Ok(stores.get(&resolve_store_path(&app, path)).copied())
}
#[tauri::command]
@@ -217,8 +255,7 @@ pub trait StoreExt<R: Runtime> {
impl<R: Runtime, T: Manager<R>> StoreExt<R> for T {
fn store(&self, path: impl AsRef<Path>) -> Arc<Store<R>> {
self.get_store(&path)
.unwrap_or_else(|| self.create_store(&path).unwrap())
StoreBuilder::new(self.app_handle(), path).build_or_existing()
}
fn create_store(&self, path: impl AsRef<Path>) -> Result<Arc<Store<R>>> {
@@ -233,7 +270,7 @@ impl<R: Runtime, T: Manager<R>> StoreExt<R> for T {
let collection = self.state::<StoreState>();
let stores = collection.stores.lock().unwrap();
stores
.get(path.as_ref())
.get(&resolve_store_path(self.app_handle(), path.as_ref()))
.and_then(|rid| self.resources_table().get(*rid).ok())
}
}
@@ -351,6 +388,7 @@ impl<R: Runtime> Builder<R> {
create_store,
get_store,
close_store,
create_or_existing_store,
set,
get,
has,
+60 -8
View File
@@ -24,10 +24,16 @@ pub type SerializeFn =
pub type DeserializeFn =
fn(&[u8]) -> Result<HashMap<String, JsonValue>, Box<dyn std::error::Error + Send + Sync>>;
pub(crate) fn resolve_store_path<R: Runtime>(app: AppHandle<R>, path: impl AsRef<Path>) -> PathBuf {
app.path()
.resolve(path, BaseDirectory::AppData)
.expect("failed to resolve app dir")
pub(crate) fn resolve_store_path<R: Runtime>(
app: &AppHandle<R>,
path: impl AsRef<Path>,
) -> PathBuf {
dunce::simplified(
&app.path()
.resolve(path, BaseDirectory::AppData)
.expect("failed to resolve app dir"),
)
.to_path_buf()
}
/// Builds a [`Store`]
@@ -55,14 +61,13 @@ impl<R: Runtime> StoreBuilder<R> {
/// ```
pub fn new<M: Manager<R>, P: AsRef<Path>>(manager: &M, path: P) -> Self {
let app = manager.app_handle().clone();
let path = resolve_store_path(app.clone(), path);
let path = resolve_store_path(&app, path);
let state = app.state::<StoreState>();
let serialize_fn = state.default_serialize;
let deserialize_fn = state.default_deserialize;
Self {
app,
// Since Store.path is only exposed to the user in emit calls we may as well simplify it here already.
path: dunce::simplified(&path).to_path_buf(),
path,
defaults: None,
serialize_fn,
deserialize_fn,
@@ -212,7 +217,38 @@ impl<R: Runtime> StoreBuilder<R> {
Ok((store, rid))
}
/// Builds the [`Store`].
pub(crate) fn build_or_existing_inner(mut self) -> (Arc<Store<R>>, ResourceId) {
let state = self.app.state::<StoreState>();
let mut stores = state.stores.lock().unwrap();
if let Some(rid) = stores.get(&self.path) {
(self.app.resources_table().get(*rid).unwrap(), *rid)
} else {
let mut store_inner = StoreInner::new(
self.app.clone(),
self.path.clone(),
self.defaults.take(),
self.serialize_fn,
self.deserialize_fn,
);
if self.load_on_build {
let _ = store_inner.load();
}
let store = Store {
auto_save: self.auto_save,
auto_save_debounce_sender: Arc::new(Mutex::new(None)),
store: Arc::new(Mutex::new(store_inner)),
};
let store = Arc::new(store);
let rid = self.app.resources_table().add_arc(store.clone());
stores.insert(self.path, rid);
(store, rid)
}
}
/// Builds the [`Store`], also see [`build_or_existing`](Self::build_or_existing).
///
/// This loads the store from disk and put the store in the app's resource table,
/// to remove it from the resource table, call [`Store::close_store`]
@@ -235,6 +271,22 @@ impl<R: Runtime> StoreBuilder<R> {
let (store, _) = self.build_inner()?;
Ok(store)
}
/// Get the existing store with the same path or builds a new [`Store`], also see [`build`](Self::build).
///
/// # Examples
/// ```
/// tauri::Builder::default()
/// .plugin(tauri_plugin_store::Builder::default().build())
/// .setup(|app| {
/// let store = tauri_plugin_store::StoreBuilder::new(app, "store.json").build_or_existing();
/// Ok(())
/// });
/// ```
pub fn build_or_existing(self) -> Arc<Store<R>> {
let (store, _) = self.build_or_existing_inner();
store
}
}
pub(crate) enum AutoSaveMessage {