Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/key removal #60

Merged
merged 4 commits into from
Sep 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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)
}
}
Loading