use crate::models::model_from_message;
use crate::storage::Error;
use crate::storage::config_store::{ConfigStore, FindOptions};
use pbbson::prost::Message;
use serde::{Deserialize, Serialize};
use std::{fmt::Debug, str::FromStr, sync::Arc};
use tonic::Status;
pub struct ConfigDao<B: Clone + Debug + FromStr + ToString> {
config_store: Arc<dyn ConfigStore<B>>,
}
impl<B: Clone + Debug + FromStr + ToString> ConfigDao<B> {
pub fn new(config_store: Arc<dyn ConfigStore<B>>) -> Self {
Self { config_store }
}
pub fn config_store(&self) -> Arc<dyn ConfigStore<B>> {
self.config_store.clone()
}
pub async fn create<T: Message + Serialize + for<'a> Deserialize<'a> + Clone + Default>(
&self,
bucket: B,
model: &T,
) -> Result<T, Status> {
self.config_store
.create(bucket.clone(), model_from_message(model)?)
.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(&self, bucket: B, id: &str, by_account_id: Option<String>) -> Result<(), Status> {
self.config_store
.delete(bucket.clone(), id, by_account_id)
.await
.map_err(|e| {
log::error!(bucket:?, err:? = e; "Failed deleting record");
e
})?;
Ok(())
}
pub async fn find<T: Message + Serialize + for<'a> Deserialize<'a> + Clone + Default>(
&self,
bucket: B,
id: &str,
) -> Result<T, Status> {
self.config_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 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.config_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,
) -> Result<T, Status> {
self.config_store
.update(bucket.clone(), model_from_message(model)?)
.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()),
}
}