use serde::{Serialize, de::DeserializeOwned};
use std::marker::PhantomData;
use std::time::Duration;
use crate::error::{Error, Result};
use crate::store::Store;
use crate::types::ScanOptions;
pub struct TypedStore<'a, T> {
store: &'a Store,
_phantom: PhantomData<T>,
}
impl<'a, T> TypedStore<'a, T>
where
T: Serialize + DeserializeOwned,
{
pub fn new(store: &'a Store) -> Self {
Self {
store,
_phantom: PhantomData,
}
}
pub fn get(&self, key: &str) -> Result<Option<T>> {
match self.store.get(key)? {
Some(bytes) => {
let value: T = serde_json::from_slice(&bytes)
.map_err(|e| Error::Serialization(e.to_string()))?;
Ok(Some(value))
}
None => Ok(None),
}
}
pub fn get_or_err(&self, key: &str) -> Result<T> {
self.get(key)?.ok_or_else(|| Error::NotFound {
key: key.to_string(),
})
}
pub fn set(&self, key: &str, value: &T) -> Result<()> {
let bytes = serde_json::to_vec(value).map_err(|e| Error::Serialization(e.to_string()))?;
self.store.set(key, &bytes)
}
pub fn set_ex(&self, key: &str, value: &T, ttl: Duration) -> Result<()> {
let bytes = serde_json::to_vec(value).map_err(|e| Error::Serialization(e.to_string()))?;
self.store.set_ex(key, &bytes, ttl)
}
pub fn set_nx(&self, key: &str, value: &T) -> Result<bool> {
let bytes = serde_json::to_vec(value).map_err(|e| Error::Serialization(e.to_string()))?;
self.store.set_nx(key, &bytes)
}
pub fn set_nx_ex(&self, key: &str, value: &T, ttl: Duration) -> Result<bool> {
let bytes = serde_json::to_vec(value).map_err(|e| Error::Serialization(e.to_string()))?;
self.store.set_nx_ex(key, &bytes, ttl)
}
pub fn get_many(&self, keys: &[&str]) -> Result<Vec<(String, T)>> {
let kvs = self.store.get_many(keys)?;
let mut results = Vec::with_capacity(kvs.len());
for kv in kvs {
let value: T = serde_json::from_slice(&kv.value)
.map_err(|e| Error::Serialization(e.to_string()))?;
results.push((kv.key, value));
}
Ok(results)
}
pub fn set_many(&self, items: &[(&str, &T)]) -> Result<()> {
let serialized: Vec<(&str, Vec<u8>)> = items
.iter()
.map(|(k, v)| {
let bytes =
serde_json::to_vec(v).map_err(|e| Error::Serialization(e.to_string()))?;
Ok((*k, bytes))
})
.collect::<Result<Vec<_>>>()?;
let refs: Vec<(&str, &[u8])> = serialized.iter().map(|(k, v)| (*k, v.as_slice())).collect();
self.store.set_many(&refs)
}
pub fn scan(&self, options: ScanOptions) -> Result<Vec<(String, T)>> {
let kvs = self.store.scan(options)?;
let mut results = Vec::with_capacity(kvs.len());
for kv in kvs {
let value: T = serde_json::from_slice(&kv.value)
.map_err(|e| Error::Serialization(e.to_string()))?;
results.push((kv.key, value));
}
Ok(results)
}
pub fn get_and_set(&self, key: &str, value: &T) -> Result<Option<T>> {
let bytes = serde_json::to_vec(value).map_err(|e| Error::Serialization(e.to_string()))?;
match self.store.get_and_set(key, &bytes)? {
Some(old_bytes) => {
let old_value: T = serde_json::from_slice(&old_bytes)
.map_err(|e| Error::Serialization(e.to_string()))?;
Ok(Some(old_value))
}
None => Ok(None),
}
}
pub fn get_and_delete(&self, key: &str) -> Result<Option<T>> {
match self.store.get_and_delete(key)? {
Some(bytes) => {
let value: T = serde_json::from_slice(&bytes)
.map_err(|e| Error::Serialization(e.to_string()))?;
Ok(Some(value))
}
None => Ok(None),
}
}
pub fn store(&self) -> &Store {
self.store
}
}
pub trait TypedStoreExt {
fn typed<T: Serialize + DeserializeOwned>(&self) -> TypedStore<'_, T>;
}
impl TypedStoreExt for Store {
fn typed<T: Serialize + DeserializeOwned>(&self) -> TypedStore<'_, T> {
TypedStore::new(self)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_serialization_error_display() {
let err = Error::Serialization("test error".to_string());
assert!(err.to_string().contains("serialization"));
}
}