use std::sync::Arc;
use super::authorization::{self, ACTION};
use crate::databases::database::{Category, Database, Error as DatabaseError};
use crate::errors::ServiceError;
use crate::models::category::CategoryId;
use crate::models::user::UserId;
pub struct Service {
category_repository: Arc<DbCategoryRepository>,
authorization_service: Arc<authorization::Service>,
}
impl Service {
#[must_use]
pub fn new(category_repository: Arc<DbCategoryRepository>, authorization_service: Arc<authorization::Service>) -> Service {
Service {
category_repository,
authorization_service,
}
}
pub async fn add_category(&self, category_name: &str, maybe_user_id: Option<UserId>) -> Result<i64, ServiceError> {
self.authorization_service
.authorize(ACTION::AddCategory, maybe_user_id)
.await?;
let trimmed_name = category_name.trim();
if trimmed_name.is_empty() {
return Err(ServiceError::CategoryNameEmpty);
}
match self.category_repository.get_by_name(trimmed_name).await {
Ok(_) => Err(ServiceError::CategoryAlreadyExists),
Err(e) => match e {
DatabaseError::CategoryNotFound => match self.category_repository.add(trimmed_name).await {
Ok(id) => Ok(id),
Err(_) => Err(ServiceError::DatabaseError),
},
_ => Err(ServiceError::DatabaseError),
},
}
}
pub async fn delete_category(&self, category_name: &str, maybe_user_id: Option<UserId>) -> Result<(), ServiceError> {
self.authorization_service
.authorize(ACTION::DeleteCategory, maybe_user_id)
.await?;
match self.category_repository.delete(category_name).await {
Ok(()) => Ok(()),
Err(e) => match e {
DatabaseError::CategoryNotFound => Err(ServiceError::CategoryNotFound),
_ => Err(ServiceError::DatabaseError),
},
}
}
pub async fn get_categories(&self, maybe_user_id: Option<UserId>) -> Result<Vec<Category>, ServiceError> {
self.authorization_service
.authorize(ACTION::GetCategories, maybe_user_id)
.await?;
self.category_repository
.get_all()
.await
.map_err(|_| ServiceError::DatabaseError)
}
}
pub struct DbCategoryRepository {
database: Arc<Box<dyn Database>>,
}
impl DbCategoryRepository {
#[must_use]
pub fn new(database: Arc<Box<dyn Database>>) -> Self {
Self { database }
}
pub async fn get_all(&self) -> Result<Vec<Category>, DatabaseError> {
self.database.get_categories().await
}
pub async fn add(&self, category_name: &str) -> Result<CategoryId, DatabaseError> {
self.database.insert_category_and_get_id(category_name).await
}
pub async fn delete(&self, category_name: &str) -> Result<(), DatabaseError> {
self.database.delete_category(category_name).await
}
pub async fn get_by_name(&self, category_name: &str) -> Result<Category, DatabaseError> {
self.database.get_category_from_name(category_name).await
}
pub async fn get_by_id(&self, category_id: &CategoryId) -> Result<Category, DatabaseError> {
self.database.get_category_from_id(*category_id).await
}
}