use async_trait::async_trait;
use anyhow::Result;
use serde::{Deserialize, Serialize};
use uuid::Uuid;
use crate::domain::entity::{FileVersion, FileVersionStatus};
use crate::infrastructure::persistence::FileVersionRepository;
use super::CommandHandler;
#[deprecated(since = "0.2.0", note = "Use CommandHandler<C> trait instead")]
#[async_trait]
pub trait FileVersionCommand: Send + Sync {
type Output;
async fn execute(&self) -> Result<Self::Output>;
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CreateFileVersionCommand {
pub file_id: Uuid,
pub version_number: i32,
pub version_type: VersionType,
pub storage_key: String,
pub storage_backend: String,
pub name: String,
pub mime_type: String,
pub checksum_md5: Option<String>,
pub checksum_sha256: Option<String>,
pub created_by_id: Uuid,
pub change_summary: Option<String>,
pub is_current: bool,
pub restored_from_id: Option<Uuid>,
pub expires_at: Option<DateTime<Utc>>,
pub status: FileVersionStatus,
pub size_bytes: i64,
pub metadata: serde_json::Value,
}
pub struct CreateFileVersionHandler<R: FileVersionRepository> {
repository: std::sync::Arc<R>,
}
impl<R: FileVersionRepository> CreateFileVersionHandler<R> {
pub fn new(repository: std::sync::Arc<R>) -> Self {
Self { repository }
}
}
#[async_trait]
impl<R: FileVersionRepository + 'static> CommandHandler<CreateFileVersionCommand> for CreateFileVersionHandler<R> {
type Output = FileVersion;
async fn handle(&self, cmd: CreateFileVersionCommand) -> Result<Self::Output> {
let entity = FileVersion::builder()
.id(Uuid::new_v4().to_string())
.file_id(cmd.file_id)
.version_number(cmd.version_number)
.version_type(cmd.version_type)
.storage_key(cmd.storage_key)
.storage_backend(cmd.storage_backend)
.name(cmd.name)
.mime_type(cmd.mime_type)
.checksum_md5(cmd.checksum_md5)
.checksum_sha256(cmd.checksum_sha256)
.created_by_id(cmd.created_by_id)
.change_summary(cmd.change_summary)
.is_current(cmd.is_current)
.restored_from_id(cmd.restored_from_id)
.expires_at(cmd.expires_at)
.status(cmd.status)
.size_bytes(cmd.size_bytes)
.metadata(cmd.metadata)
.build()?;
self.repository.save(&entity).await
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UpdateFileVersionCommand {
pub id: String,
pub file_id: Option<Uuid>,
pub version_number: Option<i32>,
pub version_type: Option<VersionType>,
pub storage_key: Option<String>,
pub storage_backend: Option<String>,
pub name: Option<String>,
pub mime_type: Option<String>,
pub checksum_md5: Option<String>,
pub checksum_sha256: Option<String>,
pub created_by_id: Option<Uuid>,
pub change_summary: Option<String>,
pub is_current: Option<bool>,
pub restored_from_id: Option<Uuid>,
pub expires_at: Option<DateTime<Utc>>,
pub status: Option<FileVersionStatus>,
pub size_bytes: Option<i64>,
pub metadata: Option<serde_json::Value>,
}
pub struct UpdateFileVersionHandler<R: FileVersionRepository> {
repository: std::sync::Arc<R>,
}
impl<R: FileVersionRepository> UpdateFileVersionHandler<R> {
pub fn new(repository: std::sync::Arc<R>) -> Self {
Self { repository }
}
}
#[async_trait]
impl<R: FileVersionRepository + 'static> CommandHandler<UpdateFileVersionCommand> for UpdateFileVersionHandler<R> {
type Output = Option<FileVersion>;
async fn handle(&self, cmd: UpdateFileVersionCommand) -> 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.file_id {
entity.file_id = value;
}
if let Some(value) = cmd.version_number {
entity.version_number = value;
}
if let Some(value) = cmd.version_type {
entity.version_type = value;
}
if let Some(value) = cmd.storage_key {
entity.storage_key = value;
}
if let Some(value) = cmd.storage_backend {
entity.storage_backend = value;
}
if let Some(value) = cmd.name {
entity.name = value;
}
if let Some(value) = cmd.mime_type {
entity.mime_type = value;
}
entity.checksum_md5 = cmd.checksum_md5;
entity.checksum_sha256 = cmd.checksum_sha256;
if let Some(value) = cmd.created_by_id {
entity.created_by_id = value;
}
entity.change_summary = cmd.change_summary;
if let Some(value) = cmd.is_current {
entity.is_current = value;
}
entity.restored_from_id = cmd.restored_from_id;
entity.expires_at = cmd.expires_at;
if let Some(value) = cmd.status {
entity.status = value;
}
if let Some(value) = cmd.size_bytes {
entity.size_bytes = value;
}
if let Some(value) = cmd.metadata {
entity.metadata = value;
}
self.repository.update(&cmd.id, &entity).await
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DeleteFileVersionCommand {
pub id: String,
pub hard_delete: bool,
}
pub struct DeleteFileVersionHandler<R: FileVersionRepository> {
repository: std::sync::Arc<R>,
}
impl<R: FileVersionRepository> DeleteFileVersionHandler<R> {
pub fn new(repository: std::sync::Arc<R>) -> Self {
Self { repository }
}
}
#[async_trait]
impl<R: FileVersionRepository + 'static> CommandHandler<DeleteFileVersionCommand> for DeleteFileVersionHandler<R> {
type Output = bool;
async fn handle(&self, cmd: DeleteFileVersionCommand) -> Result<Self::Output> {
if cmd.hard_delete {
self.repository.delete(&cmd.id).await
} else {
self.repository.soft_delete(&cmd.id).await
}
}
}