use std::sync::Arc;
#[cfg(feature = "v01-compat")]
use std::ops::Deref;
use actix_storage::{dev::Store, Result as StorageResult, StorageError};
use sled::Tree;
use crate::{SledConfig, SledError};
#[derive(Debug)]
pub struct SledStore {
db: sled::Db,
}
impl SledStore {
pub fn new() -> Result<Self, SledError> {
Ok(Self {
db: SledConfig::default().open()?,
})
}
pub fn from_db(db: sled::Db) -> Self {
Self { db }
}
#[cfg(not(feature = "v01-compat"))]
fn get_tree(&self, scope: Arc<[u8]>) -> StorageResult<Tree> {
self.db.open_tree(scope).map_err(StorageError::custom)
}
#[cfg(feature = "v01-compat")]
fn get_tree(&self, scope: Arc<[u8]>) -> StorageResult<Tree> {
if scope.as_ref() == &actix_storage::GLOBAL_SCOPE {
Ok(self.db.deref().clone())
} else {
self.db.open_tree(scope).map_err(StorageError::custom)
}
}
}
#[async_trait::async_trait]
impl Store for SledStore {
async fn set(&self, scope: Arc<[u8]>, key: Arc<[u8]>, value: Arc<[u8]>) -> StorageResult<()> {
match self.get_tree(scope)?.insert(key, value.as_ref()) {
Ok(_) => Ok(()),
Err(err) => Err(StorageError::custom(err)),
}
}
async fn get(&self, scope: Arc<[u8]>, key: Arc<[u8]>) -> StorageResult<Option<Arc<[u8]>>> {
Ok(self
.get_tree(scope)?
.get(key)
.map_err(StorageError::custom)?
.map(|val| val.as_ref().into()))
}
async fn delete(&self, scope: Arc<[u8]>, key: Arc<[u8]>) -> StorageResult<()> {
match self.get_tree(scope)?.remove(key) {
Ok(_) => Ok(()),
Err(err) => Err(StorageError::custom(err)),
}
}
async fn contains_key(&self, scope: Arc<[u8]>, key: Arc<[u8]>) -> StorageResult<bool> {
match self.get_tree(scope)?.contains_key(key) {
Ok(res) => Ok(res),
Err(err) => Err(StorageError::custom(err)),
}
}
}
#[cfg(test)]
mod test {
use super::*;
use actix_storage::tests::*;
use std::time::Duration;
async fn open_database() -> sled::Db {
let mut tries: u8 = 0;
loop {
tries += 1;
let db = SledConfig::default().temporary(true).open();
match db {
Ok(db) => return db,
Err(err) => {
if tries > 10 {
panic!("{}", err)
};
}
}
actix::clock::delay_for(Duration::from_millis(500)).await;
}
}
#[test]
fn test_sled_basic_store() {
test_store(Box::pin(async {
SledStore::from_db(open_database().await)
}));
}
#[test]
fn test_sled_basic_formats() {
impl Clone for SledStore {
fn clone(&self) -> Self {
Self {
db: self.db.clone(),
}
}
}
test_all_formats(Box::pin(async {
SledStore::from_db(open_database().await)
}));
}
}