Skip to content

Commit

Permalink
Merge pull request #60 from Occuros/feature/key_removal
Browse files Browse the repository at this point in the history
Feature/key removal
  • Loading branch information
johanhelsing authored Sep 4, 2024
2 parents ee2aa3d + 6594949 commit 79df04c
Show file tree
Hide file tree
Showing 5 changed files with 198 additions and 16 deletions.
47 changes: 46 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,18 @@ use serde::{de::DeserializeOwned, Serialize};
trait StoreImpl {
type GetError;
type SetError;
type RemoveError;

fn set_string(&mut self, key: &str, value: &str) -> Result<(), Self::SetError> {
self.set(key, &value.to_string())
}
fn get<T: DeserializeOwned>(&self, key: &str) -> Result<T, Self::GetError>;
fn set<T: Serialize>(&mut self, key: &str, value: &T) -> Result<(), Self::SetError>;
fn remove(&mut self, key: &str) -> Result<(), Self::RemoveError>;
fn remove_and_get<T: DeserializeOwned>(
&mut self,
key: &str,
) -> Result<Option<T>, Self::RemoveError>;
fn clear(&mut self) -> Result<(), Self::SetError>;
}

Expand All @@ -42,7 +48,7 @@ mod rocksdb_store;
use rocksdb_store::{self as backend};

// todo: Look into unifying these types?
pub use backend::{GetError, SetError};
pub use backend::{GetError, RemoveError, SetError};

enum Location<'a> {
PlatformDefault(&'a PlatformDefault),
Expand Down Expand Up @@ -125,6 +131,18 @@ impl PkvStore {
pub fn get<T: DeserializeOwned>(&self, key: impl AsRef<str>) -> Result<T, GetError> {
self.inner.get(key.as_ref())
}
/// Remove the value from the store for the given key
/// returns the removed value if one existed
pub fn remove_and_get<T: DeserializeOwned>(
&mut self,
key: impl AsRef<str>,
) -> Result<Option<T>, RemoveError> {
self.inner.remove_and_get(key.as_ref())
}
/// Remove the value from the store for the given key
pub fn remove(&mut self, key: impl AsRef<str>) -> Result<(), RemoveError> {
self.inner.remove(key.as_ref())
}

/// Clear all key values data
/// returns Err(SetError) if clear error
Expand Down Expand Up @@ -237,4 +255,31 @@ mod tests {
store.set("user", &user).unwrap();
assert_eq!(store.get::<User>("user").unwrap(), user);
}

#[test]
fn remove() {
setup();
let mut store = PkvStore::new("BevyPkv", "test_remove");
let user = User {
name: "alice".to_string(),
age: 32,
};
store.set("user", &user).unwrap();
store.remove("user").unwrap();
assert_eq!(store.get::<User>("user").ok(), None);
}

#[test]
fn remove_and_get() {
setup();
let mut store = PkvStore::new("BevyPkv", "test_remove_and_get");
let user = User {
name: "alice".to_string(),
age: 32,
};
store.set("user", &user).unwrap();
let removed_user = store.remove_and_get::<User>("user").unwrap().unwrap();
assert_eq!(user, removed_user);
assert_eq!(store.get::<User>("user").ok(), None);
}
}
29 changes: 29 additions & 0 deletions src/local_storage_store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,18 @@ pub enum SetError {
Clear(wasm_bindgen::JsValue),
}

#[derive(thiserror::Error, Debug)]
pub enum RemoveError {
#[error("No value found for the given key")]
NotFound,
#[error("error deserializing json")]
Json(#[from] serde_json::Error),
#[error("JavaScript error from getItem")]
GetItem(wasm_bindgen::JsValue),
#[error("JavaScript error from clear")]
Clear(wasm_bindgen::JsValue),
}

impl LocalStorageStore {
fn storage(&self) -> web_sys::Storage {
web_sys::window()
Expand Down Expand Up @@ -59,6 +71,7 @@ impl LocalStorageStore {
impl StoreImpl for LocalStorageStore {
type GetError = GetError;
type SetError = SetError;
type RemoveError = RemoveError;

fn set_string(&mut self, key: &str, value: &str) -> Result<(), SetError> {
let json = serde_json::to_string(value)?;
Expand Down Expand Up @@ -99,4 +112,20 @@ impl StoreImpl for LocalStorageStore {
}
Ok(())
}

fn remove(&mut self, key: &str) -> Result<(), Self::RemoveError> {
let storage = self.storage();
let key = self.format_key(key);
storage.remove_item(&key).map_err(RemoveError::Clear)?;
Ok(())
}

fn remove_and_get<T: serde::de::DeserializeOwned>(
&mut self,
key: &str,
) -> Result<Option<T>, Self::RemoveError> {
let previous_value = self.get(key).map_err(|_| RemoveError::NotFound)?;
self.remove(key)?;
Ok(Some(previous_value))
}
}
78 changes: 64 additions & 14 deletions src/redb_store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,26 @@ pub enum GetError {
MessagePack(#[from] rmp_serde::decode::Error),
}

/// Errors that can occur during `PkvStore::`
#[derive(thiserror::Error, Debug)]
pub enum RemoveError {
/// An internal commit error from the `redb` crate
#[error("ReDbCommitError error")]
ReDbCommitError(#[from] redb::CommitError),
/// An internal storage error from the `redb` crate
#[error("ReDbStorageError error")]
ReDbStorageError(#[from] redb::StorageError),
/// An internal transaction error from the `redb` crate
#[error("ReDbTransactionError error")]
ReDbTransactionError(#[from] redb::TransactionError),
/// An internal table error from the `redb` crate
#[error("ReDbTableError error")]
ReDbTableError(#[from] redb::TableError),
/// Error when serializing the value
#[error("MessagePack serialization error")]
MessagePack(#[from] rmp_serde::encode::Error),
}

/// Errors that can occur during `PkvStore::set`
#[derive(thiserror::Error, Debug)]
pub enum SetError {
Expand Down Expand Up @@ -74,20 +94,7 @@ const TABLE: TableDefinition<&str, &[u8]> = TableDefinition::new("redb");
impl StoreImpl for ReDbStore {
type GetError = GetError;
type SetError = SetError;

/// Serialize and store the value
fn set<T: Serialize>(&mut self, key: &str, value: &T) -> Result<(), Self::SetError> {
let mut serializer = rmp_serde::Serializer::new(Vec::new()).with_struct_map();
value.serialize(&mut serializer)?;
let write_txn = self.db.begin_write()?;
{
let mut table = write_txn.open_table(TABLE).unwrap();
table.insert(key, serializer.into_inner().as_slice())?;
}
write_txn.commit()?;

Ok(())
}
type RemoveError = RemoveError;

/// More or less the same as set::<String>, but can take a &str
fn set_string(&mut self, key: &str, value: &str) -> Result<(), Self::SetError> {
Expand All @@ -113,6 +120,49 @@ impl StoreImpl for ReDbStore {
Ok(value)
}

/// Serialize and store the value
fn set<T: Serialize>(&mut self, key: &str, value: &T) -> Result<(), Self::SetError> {
let mut serializer = rmp_serde::Serializer::new(Vec::new()).with_struct_map();
value.serialize(&mut serializer)?;
let write_txn = self.db.begin_write()?;
{
let mut table = write_txn.open_table(TABLE).unwrap();
table.insert(key, serializer.into_inner().as_slice())?;
}
write_txn.commit()?;

Ok(())
}

fn remove_and_get<T: DeserializeOwned>(
&mut self,
key: &str,
) -> Result<Option<T>, Self::RemoveError> {
let value: Option<T>;
let write_txn = self.db.begin_write()?;
{
let mut table = write_txn.open_table(TABLE).unwrap();
value = match table.remove(key)? {
Some(kv) => rmp_serde::from_slice(kv.value()).ok(),
None => None,
};
}
write_txn.commit()?;

Ok(value)
}

fn remove(&mut self, key: &str) -> Result<(), Self::RemoveError> {
let write_txn = self.db.begin_write()?;
{
let mut table = write_txn.open_table(TABLE).unwrap();
table.remove(key)?;
}
write_txn.commit()?;

Ok(())
}

/// Clear all keys and their values
fn clear(&mut self) -> Result<(), Self::SetError> {
let write_txn = self.db.begin_write()?;
Expand Down
31 changes: 30 additions & 1 deletion src/rocksdb_store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ pub enum GetError {
#[error("No value found for the given key")]
NotFound,
}

/// Errors that can occur during `PkvStore::set`
#[derive(thiserror::Error, Debug)]
pub enum SetError {
Expand All @@ -33,6 +32,20 @@ pub enum SetError {
MessagePack(#[from] rmp_serde::encode::Error),
}

/// Errors that can occur during `PkvStore::remove`
#[derive(thiserror::Error, Debug)]
pub enum RemoveError {
/// An internal error from the rocksdb crate
#[error("Rocksdb error")]
Rocksdb(#[from] rocksdb::Error),
/// Error when deserializing the value
#[error("MessagePack deserialization error")]
MessagePack(#[from] rmp_serde::decode::Error),
/// The value for the given key was not found
#[error("No value found for the given key")]
NotFound,
}

impl RocksDBStore {
pub(crate) fn new(location: Location) -> Self {
let mut options = rocksdb::Options::default();
Expand All @@ -49,6 +62,7 @@ impl RocksDBStore {
impl StoreImpl for RocksDBStore {
type GetError = GetError;
type SetError = SetError;
type RemoveError = RemoveError;

/// Serialize and store the value
fn set<T: Serialize>(&mut self, key: &str, value: &T) -> Result<(), Self::SetError> {
Expand Down Expand Up @@ -87,4 +101,19 @@ impl StoreImpl for RocksDBStore {

Ok(())
}

fn remove(&mut self, key: &str) -> Result<(), Self::RemoveError> {
self.db.delete(key)?;
Ok(())
}

fn remove_and_get<T: DeserializeOwned>(
&mut self,
key: &str,
) -> Result<Option<T>, Self::RemoveError> {
let bytes = self.db.get(key)?.ok_or(Self::RemoveError::NotFound)?;
let value = rmp_serde::from_slice(&bytes)?;
self.db.delete(key)?;
Ok(value)
}
}
29 changes: 29 additions & 0 deletions src/sled_store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,20 @@ pub enum SetError {
MessagePack(#[from] rmp_serde::encode::Error),
}

/// Errors that can occur during `PkvStore::remove`
#[derive(thiserror::Error, Debug)]
pub enum RemoveError {
/// An internal error from the sled crate
#[error("Sled error")]
Sled(#[from] sled::Error),
/// Error when deserializing the value
#[error("MessagePack deserialization error")]
MessagePack(#[from] rmp_serde::decode::Error),
/// The value for the given key was not found
#[error("No value found for the given key")]
NotFound,
}

impl SledStore {
pub(crate) fn new(location: Location) -> Self {
let db_path = location.get_path().join("bevy_pkv.sled");
Expand All @@ -44,6 +58,7 @@ impl SledStore {
impl StoreImpl for SledStore {
type GetError = GetError;
type SetError = SetError;
type RemoveError = RemoveError;

/// Serialize and store the value
fn set<T: Serialize>(&mut self, key: &str, value: &T) -> Result<(), Self::SetError> {
Expand Down Expand Up @@ -77,4 +92,18 @@ impl StoreImpl for SledStore {
self.db.flush()?;
Ok(())
}

fn remove(&mut self, key: &str) -> Result<(), Self::RemoveError> {
self.db.remove(key)?;
Ok(())
}

fn remove_and_get<T: DeserializeOwned>(
&mut self,
key: &str,
) -> Result<Option<T>, Self::RemoveError> {
let bytes = self.db.remove(key)?.ok_or(Self::RemoveError::NotFound)?;
let value = rmp_serde::from_slice(&bytes)?;
Ok(value)
}
}

0 comments on commit 79df04c

Please sign in to comment.