use async_trait::async_trait;
use anyhow::Result;
use serde::{Deserialize, Serialize};
use uuid::Uuid;
use crate::domain::entity::Bucket;
use crate::infrastructure::persistence::BucketRepository;
use super::CommandHandler;
#[deprecated(since = "0.2.0", note = "Use CommandHandler<C> trait instead")]
#[async_trait]
pub trait BucketCommand: Send + Sync {
type Output;
async fn execute(&self) -> Result<Self::Output>;
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CreateBucketCommand {
pub name: String,
pub slug: String,
pub description: Option<String>,
pub owner_id: Uuid,
pub bucket_type: BucketType,
pub status: BucketStatus,
pub storage_backend: StorageBackend,
pub root_path: String,
pub file_count: i32,
pub total_size_bytes: i64,
pub max_file_size: Option<i64>,
pub allowed_mime_types: Vec<String>,
pub auto_delete_after_days: Option<i32>,
pub enable_cdn: bool,
pub enable_versioning: bool,
pub enable_deduplication: bool,
pub metadata: serde_json::Value,
}
pub struct CreateBucketHandler<R: BucketRepository> {
repository: std::sync::Arc<R>,
}
impl<R: BucketRepository> CreateBucketHandler<R> {
pub fn new(repository: std::sync::Arc<R>) -> Self {
Self { repository }
}
}
#[async_trait]
impl<R: BucketRepository + 'static> CommandHandler<CreateBucketCommand> for CreateBucketHandler<R> {
type Output = Bucket;
async fn handle(&self, cmd: CreateBucketCommand) -> Result<Self::Output> {
let entity = Bucket::builder()
.id(Uuid::new_v4().to_string())
.name(cmd.name)
.slug(cmd.slug)
.description(cmd.description)
.owner_id(cmd.owner_id)
.bucket_type(cmd.bucket_type)
.status(cmd.status)
.storage_backend(cmd.storage_backend)
.root_path(cmd.root_path)
.file_count(cmd.file_count)
.total_size_bytes(cmd.total_size_bytes)
.max_file_size(cmd.max_file_size)
.allowed_mime_types(cmd.allowed_mime_types)
.auto_delete_after_days(cmd.auto_delete_after_days)
.enable_cdn(cmd.enable_cdn)
.enable_versioning(cmd.enable_versioning)
.enable_deduplication(cmd.enable_deduplication)
.metadata(cmd.metadata)
.build()?;
self.repository.save(&entity).await
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UpdateBucketCommand {
pub id: String,
pub name: Option<String>,
pub slug: Option<String>,
pub description: Option<String>,
pub owner_id: Option<Uuid>,
pub bucket_type: Option<BucketType>,
pub status: Option<BucketStatus>,
pub storage_backend: Option<StorageBackend>,
pub root_path: Option<String>,
pub file_count: Option<i32>,
pub total_size_bytes: Option<i64>,
pub max_file_size: Option<i64>,
pub allowed_mime_types: Option<Vec<String>>,
pub auto_delete_after_days: Option<i32>,
pub enable_cdn: Option<bool>,
pub enable_versioning: Option<bool>,
pub enable_deduplication: Option<bool>,
pub metadata: Option<serde_json::Value>,
}
pub struct UpdateBucketHandler<R: BucketRepository> {
repository: std::sync::Arc<R>,
}
impl<R: BucketRepository> UpdateBucketHandler<R> {
pub fn new(repository: std::sync::Arc<R>) -> Self {
Self { repository }
}
}
#[async_trait]
impl<R: BucketRepository + 'static> CommandHandler<UpdateBucketCommand> for UpdateBucketHandler<R> {
type Output = Option<Bucket>;
async fn handle(&self, cmd: UpdateBucketCommand) -> Result<Self::Output> {
let existing = self.repository.find_by_id(&cmd.id).await?;
let Some(mut entity) = existing else {
return Ok(None);
};
if let Some(value) = cmd.name {
entity.name = value;
}
if let Some(value) = cmd.slug {
entity.slug = value;
}
entity.description = cmd.description;
if let Some(value) = cmd.owner_id {
entity.owner_id = value;
}
if let Some(value) = cmd.bucket_type {
entity.bucket_type = value;
}
if let Some(value) = cmd.status {
entity.status = value;
}
if let Some(value) = cmd.storage_backend {
entity.storage_backend = value;
}
if let Some(value) = cmd.root_path {
entity.root_path = value;
}
if let Some(value) = cmd.file_count {
entity.file_count = value;
}
if let Some(value) = cmd.total_size_bytes {
entity.total_size_bytes = value;
}
entity.max_file_size = cmd.max_file_size;
if let Some(value) = cmd.allowed_mime_types {
entity.allowed_mime_types = value;
}
entity.auto_delete_after_days = cmd.auto_delete_after_days;
if let Some(value) = cmd.enable_cdn {
entity.enable_cdn = value;
}
if let Some(value) = cmd.enable_versioning {
entity.enable_versioning = value;
}
if let Some(value) = cmd.enable_deduplication {
entity.enable_deduplication = value;
}
if let Some(value) = cmd.metadata {
entity.metadata = value;
}
self.repository.update(&cmd.id, &entity).await
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DeleteBucketCommand {
pub id: String,
pub hard_delete: bool,
}
pub struct DeleteBucketHandler<R: BucketRepository> {
repository: std::sync::Arc<R>,
}
impl<R: BucketRepository> DeleteBucketHandler<R> {
pub fn new(repository: std::sync::Arc<R>) -> Self {
Self { repository }
}
}
#[async_trait]
impl<R: BucketRepository + 'static> CommandHandler<DeleteBucketCommand> for DeleteBucketHandler<R> {
type Output = bool;
async fn handle(&self, cmd: DeleteBucketCommand) -> Result<Self::Output> {
if cmd.hard_delete {
self.repository.delete(&cmd.id).await
} else {
self.repository.soft_delete(&cmd.id).await
}
}
}