This commit is contained in:
2025-05-03 05:52:59 +04:00
parent 3e49f48f60
commit bae1fb93cb
5 changed files with 527 additions and 49 deletions

View File

@@ -61,13 +61,25 @@ impl KvsStore {
let factory = Factory::new()?;
let mut db_req = factory.open(db_name, Some(1))?;
db_req.on_upgrade_needed(|event| {
let db = event.database()?;
if !db.object_store_names().includes(&JsValue::from_str(store_name)) {
db.create_object_store(store_name, None)?;
// Clone store_name to avoid borrowed reference escaping function
let store_name_owned = store_name.to_string();
db_req.on_upgrade_needed(move |event| {
let db = event.database().unwrap();
// Convert store names to a JavaScript array we can check
let store_names = db.store_names();
let js_array = js_sys::Array::new();
for (i, name) in store_names.iter().enumerate() {
js_array.set(i as u32, JsValue::from_str(name));
}
Ok(())
})?;
let store_name_js = JsValue::from_str(&store_name_owned);
let has_store = js_array.includes(&store_name_js, 0);
if !has_store {
let params = idb::ObjectStoreParams::new();
db.create_object_store(&store_name_owned, params).unwrap();
}
});
let db = Arc::new(db_req.await?);
@@ -112,9 +124,11 @@ impl KvsStore {
let store = tx.object_store(&self.store_name)?;
let serialized = serde_json::to_string(value)?;
store.put_with_key(&JsValue::from_str(&serialized), &key.into())?;
JsFuture::from(tx.done()).await?;
let request = store.put(&JsValue::from_str(&serialized), Some(&key.into()))?;
// Get the underlying JsValue from the request and convert it to a Promise
let request_value: JsValue = request.into();
let promise = Promise::from(request_value);
JsFuture::from(promise).await?;
Ok(())
}
@@ -148,18 +162,21 @@ impl KvsStore {
#[cfg(target_arch = "wasm32")]
pub async fn get<K, V>(&self, key: K) -> Result<V>
where
K: ToString + Into<JsValue>,
K: ToString + Into<JsValue> + Clone,
V: DeserializeOwned,
{
let tx = self.db.transaction(&[&self.store_name], TransactionMode::ReadOnly)?;
let store = tx.object_store(&self.store_name)?;
let request = store.get(&key.into())?;
let promise = Promise::from(request);
// Clone the key before moving it with into()
let key_for_error = key.clone();
let request = store.get(key.into())?;
let request_value: JsValue = request.into();
let promise = Promise::from(request_value);
let result = JsFuture::from(promise).await?;
if result.is_undefined() {
return Err(KvsError::KeyNotFound(key.to_string()));
return Err(KvsError::KeyNotFound(key_for_error.to_string()));
}
let value_str = result.as_string().ok_or_else(|| {
@@ -197,24 +214,30 @@ impl KvsStore {
#[cfg(target_arch = "wasm32")]
pub async fn delete<K>(&self, key: K) -> Result<()>
where
K: ToString + Into<JsValue>,
K: ToString + Into<JsValue> + Clone,
{
let tx = self.db.transaction(&[&self.store_name], TransactionMode::ReadWrite)?;
let store = tx.object_store(&self.store_name)?;
// Clone the key before moving it
let key_for_check = key.clone();
let key_for_error = key.clone();
// First check if the key exists
let request = store.count_with_key(&key.into())?;
let promise = Promise::from(request);
let request = store.count(Some(idb::Query::Key(key_for_check.into())))?;
let request_value: JsValue = request.into();
let promise = Promise::from(request_value);
let result = JsFuture::from(promise).await?;
let count = result.as_f64().unwrap_or(0.0);
if count <= 0.0 {
return Err(KvsError::KeyNotFound(key.to_string()));
return Err(KvsError::KeyNotFound(key_for_error.to_string()));
}
store.delete(&key.into())?;
JsFuture::from(tx.done()).await?;
let delete_request = store.delete(key.into())?;
let delete_request_value: JsValue = delete_request.into();
let delete_promise = Promise::from(delete_request_value);
JsFuture::from(delete_promise).await?;
Ok(())
}
@@ -241,13 +264,14 @@ impl KvsStore {
#[cfg(target_arch = "wasm32")]
pub async fn contains<K>(&self, key: K) -> Result<bool>
where
K: ToString + Into<JsValue>,
K: ToString + Into<JsValue> + Clone,
{
let tx = self.db.transaction(&[&self.store_name], TransactionMode::ReadOnly)?;
let store = tx.object_store(&self.store_name)?;
let request = store.count_with_key(&key.into())?;
let promise = Promise::from(request);
let request = store.count(Some(idb::Query::Key(key.into())))?;
let request_value: JsValue = request.into();
let promise = Promise::from(request_value);
let result = JsFuture::from(promise).await?;
let count = result.as_f64().unwrap_or(0.0);
@@ -271,8 +295,9 @@ impl KvsStore {
let tx = self.db.transaction(&[&self.store_name], TransactionMode::ReadOnly)?;
let store = tx.object_store(&self.store_name)?;
let request = store.get_all_keys(None)?;
let promise = Promise::from(request);
let request = store.get_all_keys(None, None)?;
let request_value: JsValue = request.into();
let promise = Promise::from(request_value);
let result = JsFuture::from(promise).await?;
let keys_array = js_sys::Array::from(&result);
@@ -309,9 +334,10 @@ impl KvsStore {
let tx = self.db.transaction(&[&self.store_name], TransactionMode::ReadWrite)?;
let store = tx.object_store(&self.store_name)?;
store.clear()?;
JsFuture::from(tx.done()).await?;
let request = store.clear()?;
let request_value: JsValue = request.into();
let promise = Promise::from(request_value);
JsFuture::from(promise).await?;
Ok(())
}
}