use crate::models::model_from_message;
use crate::storage::Error;
use crate::storage::session_store::{FindOptions, SessionStore};
use pbbson::prost::Message;
use serde::{Deserialize, Serialize};
use std::{fmt::Debug, str::FromStr};
use std::{sync::Arc, time::Duration};
use tonic::Status;
#[derive(Clone)]
pub struct SessionDao<B: Clone + Debug + FromStr + ToString> {
session_store: Arc<dyn SessionStore<B>>,
}
impl<B: Clone + Debug + FromStr + ToString> SessionDao<B> {
pub fn new(session_store: Arc<dyn SessionStore<B>>) -> Self {
Self { session_store }
}
pub fn adapter(&self) -> Arc<dyn SessionStore<B>> {
self.session_store.clone()
}
pub async fn create<T: Message + Serialize + for<'a> Deserialize<'a> + Clone + Default>(
&self,
bucket: B,
model: &T,
maybe_expires: Option<Duration>,
) -> Result<T, Status> {
self.session_store
.create(bucket.clone(), model_from_message(model)?, maybe_expires)
.await
.map_err(|e| {
log::error!(bucket:?, err:? = e; "Failed creating record");
to_status(e)
})?
.try_into()
.map_err(|e| {
log::error!(bucket:?, err:? = e; "Failed converting created model back into a message");
Status::internal(e.to_string())
})
}
pub async fn delete<T: Message + Serialize + for<'a> Deserialize<'a> + Clone + Default>(
&self,
bucket: B,
id: &str,
) -> Result<(), Status> {
self.session_store.delete(bucket.clone(), id).await.map_err(|e| {
log::error!(bucket:?, id, err:? = e; "Failed deleting record");
to_status(e)
})?;
Ok(())
}
pub async fn find<T: Message + Serialize + for<'a> Deserialize<'a> + Clone + Default>(
&self,
bucket: B,
id: &str,
) -> Result<T, Status> {
self.session_store
.find(bucket.clone(), id)
.await
.map_err(|e| {
log::error!(bucket:?, id, err:? = e; "Failed finding record");
to_status(e)
})?
.try_into()
.map_err(|e| {
log::error!(bucket:?, err:? = e; "Failed converting found model back into a message");
Status::internal(e.to_string())
})
}
pub async fn find_many<T: Message + Serialize + for<'a> Deserialize<'a> + Clone + Default>(
&self,
bucket: B,
options: FindOptions,
) -> Result<Vec<T>, Status> {
let filter = options.filter.clone();
self.session_store
.find_many(bucket.clone(), options)
.await
.map_err(|e| {
log::error!(bucket:?, filter:?, err:? = e; "Failed finding records");
to_status(e)
})?
.into_iter()
.map(|model| {
model.try_into().map_err(|e| {
log::error!(bucket:?, filter:?, err:? = e; "Failed converting found model into a message");
to_status(e.into())
})
})
.collect()
}
pub async fn update<T: Message + Serialize + for<'a> Deserialize<'a> + Clone + Default>(
&self,
bucket: B,
model: &T,
maybe_expires: Option<Duration>,
) -> Result<T, Status> {
self.session_store
.update(bucket.clone(), model_from_message(model)?, maybe_expires)
.await
.map_err(|e| {
log::error!(bucket:?, err:? = e; "Failed updating record");
to_status(e)
})?
.try_into()
.map_err(|e| {
log::error!(bucket:?, err:? = e; "Failed converting updated model back into a message");
Status::internal(e.to_string())
})
}
}
fn to_status(e: Error) -> Status {
match e {
Error::AlreadyExists(e) => Status::already_exists(e.to_string()),
Error::FailedPrecondition(e) => Status::failed_precondition(e.to_string()),
Error::Internal(e) => Status::internal(e.to_string()),
Error::InvalidArgument(e) => Status::invalid_argument(e.to_string()),
Error::MigrationFailed(e) => Status::internal(e.to_string()),
Error::NotFound(e) => Status::not_found(e.to_string()),
Error::Unavailable(e) => Status::unavailable(e.to_string()),
Error::Unimplemented(e) => Status::unimplemented(e.to_string()),
}
}
#[cfg(test)]
mod tests {
use crate::storage::session_store::SessionDao;
use crate::storage::session_store::adapters::memory::{MemorySessionStore, Options};
use std::collections::HashMap;
use std::sync::Arc;
use strum_macros::{AsRefStr, Display, EnumIter, EnumString};
#[test]
fn can_clone() {
#[derive(AsRefStr, Clone, Debug, Display, EnumIter, EnumString)]
enum Bucket {
None,
}
let opts: Options<Bucket> = Options {
app_name: None,
belongs_tos_by_bucket: HashMap::new(),
has_manys_by_bucket: HashMap::new(),
};
let session_store = Arc::new(MemorySessionStore::new(opts));
let session_dao = SessionDao::new(session_store);
let _ = session_dao.clone();
}
}