use async_trait::async_trait;
use anyhow::Result;
use serde::{Deserialize, Serialize};
use uuid::Uuid;
use crate::domain::entity::ConversionJob;
use crate::infrastructure::persistence::ConversionJobRepository;
use super::CommandHandler;
#[deprecated(since = "0.2.0", note = "Use CommandHandler<C> trait instead")]
#[async_trait]
pub trait ConversionJobCommand: Send + Sync {
type Output;
async fn execute(&self) -> Result<Self::Output>;
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CreateConversionJobCommand {
pub source_file_id: Uuid,
pub target_format: String,
pub status: ConversionStatus,
pub conversion_options: Option<serde_json::Value>,
pub result_file_id: Option<Uuid>,
pub progress: i32,
pub error_message: Option<String>,
pub started_at: Option<DateTime<Utc>>,
pub completed_at: Option<DateTime<Utc>>,
pub metadata: serde_json::Value,
}
pub struct CreateConversionJobHandler<R: ConversionJobRepository> {
repository: std::sync::Arc<R>,
}
impl<R: ConversionJobRepository> CreateConversionJobHandler<R> {
pub fn new(repository: std::sync::Arc<R>) -> Self {
Self { repository }
}
}
#[async_trait]
impl<R: ConversionJobRepository + 'static> CommandHandler<CreateConversionJobCommand> for CreateConversionJobHandler<R> {
type Output = ConversionJob;
async fn handle(&self, cmd: CreateConversionJobCommand) -> Result<Self::Output> {
let entity = ConversionJob::builder()
.id(Uuid::new_v4().to_string())
.source_file_id(cmd.source_file_id)
.target_format(cmd.target_format)
.status(cmd.status)
.conversion_options(cmd.conversion_options)
.result_file_id(cmd.result_file_id)
.progress(cmd.progress)
.error_message(cmd.error_message)
.started_at(cmd.started_at)
.completed_at(cmd.completed_at)
.metadata(cmd.metadata)
.build()?;
self.repository.save(&entity).await
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UpdateConversionJobCommand {
pub id: String,
pub source_file_id: Option<Uuid>,
pub target_format: Option<String>,
pub status: Option<ConversionStatus>,
pub conversion_options: Option<serde_json::Value>,
pub result_file_id: Option<Uuid>,
pub progress: Option<i32>,
pub error_message: Option<String>,
pub started_at: Option<DateTime<Utc>>,
pub completed_at: Option<DateTime<Utc>>,
pub metadata: Option<serde_json::Value>,
}
pub struct UpdateConversionJobHandler<R: ConversionJobRepository> {
repository: std::sync::Arc<R>,
}
impl<R: ConversionJobRepository> UpdateConversionJobHandler<R> {
pub fn new(repository: std::sync::Arc<R>) -> Self {
Self { repository }
}
}
#[async_trait]
impl<R: ConversionJobRepository + 'static> CommandHandler<UpdateConversionJobCommand> for UpdateConversionJobHandler<R> {
type Output = Option<ConversionJob>;
async fn handle(&self, cmd: UpdateConversionJobCommand) -> 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.source_file_id {
entity.source_file_id = value;
}
if let Some(value) = cmd.target_format {
entity.target_format = value;
}
if let Some(value) = cmd.status {
entity.status = value;
}
entity.conversion_options = cmd.conversion_options;
entity.result_file_id = cmd.result_file_id;
if let Some(value) = cmd.progress {
entity.progress = value;
}
entity.error_message = cmd.error_message;
entity.started_at = cmd.started_at;
entity.completed_at = cmd.completed_at;
if let Some(value) = cmd.metadata {
entity.metadata = value;
}
self.repository.update(&cmd.id, &entity).await
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DeleteConversionJobCommand {
pub id: String,
pub hard_delete: bool,
}
pub struct DeleteConversionJobHandler<R: ConversionJobRepository> {
repository: std::sync::Arc<R>,
}
impl<R: ConversionJobRepository> DeleteConversionJobHandler<R> {
pub fn new(repository: std::sync::Arc<R>) -> Self {
Self { repository }
}
}
#[async_trait]
impl<R: ConversionJobRepository + 'static> CommandHandler<DeleteConversionJobCommand> for DeleteConversionJobHandler<R> {
type Output = bool;
async fn handle(&self, cmd: DeleteConversionJobCommand) -> Result<Self::Output> {
if cmd.hard_delete {
self.repository.delete(&cmd.id).await
} else {
self.repository.soft_delete(&cmd.id).await
}
}
}