use async_trait::async_trait;
use anyhow::Result;
use serde::{Deserialize, Serialize};
use uuid::Uuid;
use crate::domain::entity::FileLock;
use crate::infrastructure::persistence::FileLockRepository;
use super::CommandHandler;
#[deprecated(since = "0.2.0", note = "Use CommandHandler<C> trait instead")]
#[async_trait]
pub trait FileLockCommand: Send + Sync {
type Output;
async fn execute(&self) -> Result<Self::Output>;
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CreateFileLockCommand {
pub file_id: Uuid,
pub user_id: Uuid,
pub locked_at: DateTime<Utc>,
pub expires_at: DateTime<Utc>,
pub refreshed_at: Option<DateTime<Utc>>,
pub status: LockStatus,
pub metadata: serde_json::Value,
}
pub struct CreateFileLockHandler<R: FileLockRepository> {
repository: std::sync::Arc<R>,
}
impl<R: FileLockRepository> CreateFileLockHandler<R> {
pub fn new(repository: std::sync::Arc<R>) -> Self {
Self { repository }
}
}
#[async_trait]
impl<R: FileLockRepository + 'static> CommandHandler<CreateFileLockCommand> for CreateFileLockHandler<R> {
type Output = FileLock;
async fn handle(&self, cmd: CreateFileLockCommand) -> Result<Self::Output> {
let entity = FileLock::builder()
.id(Uuid::new_v4().to_string())
.file_id(cmd.file_id)
.user_id(cmd.user_id)
.locked_at(cmd.locked_at)
.expires_at(cmd.expires_at)
.refreshed_at(cmd.refreshed_at)
.status(cmd.status)
.metadata(cmd.metadata)
.build()?;
self.repository.save(&entity).await
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UpdateFileLockCommand {
pub id: String,
pub file_id: Option<Uuid>,
pub user_id: Option<Uuid>,
pub locked_at: Option<DateTime<Utc>>,
pub expires_at: Option<DateTime<Utc>>,
pub refreshed_at: Option<DateTime<Utc>>,
pub status: Option<LockStatus>,
pub metadata: Option<serde_json::Value>,
}
pub struct UpdateFileLockHandler<R: FileLockRepository> {
repository: std::sync::Arc<R>,
}
impl<R: FileLockRepository> UpdateFileLockHandler<R> {
pub fn new(repository: std::sync::Arc<R>) -> Self {
Self { repository }
}
}
#[async_trait]
impl<R: FileLockRepository + 'static> CommandHandler<UpdateFileLockCommand> for UpdateFileLockHandler<R> {
type Output = Option<FileLock>;
async fn handle(&self, cmd: UpdateFileLockCommand) -> 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.user_id {
entity.user_id = value;
}
if let Some(value) = cmd.locked_at {
entity.locked_at = value;
}
if let Some(value) = cmd.expires_at {
entity.expires_at = value;
}
entity.refreshed_at = cmd.refreshed_at;
if let Some(value) = cmd.status {
entity.status = value;
}
if let Some(value) = cmd.metadata {
entity.metadata = value;
}
self.repository.update(&cmd.id, &entity).await
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DeleteFileLockCommand {
pub id: String,
pub hard_delete: bool,
}
pub struct DeleteFileLockHandler<R: FileLockRepository> {
repository: std::sync::Arc<R>,
}
impl<R: FileLockRepository> DeleteFileLockHandler<R> {
pub fn new(repository: std::sync::Arc<R>) -> Self {
Self { repository }
}
}
#[async_trait]
impl<R: FileLockRepository + 'static> CommandHandler<DeleteFileLockCommand> for DeleteFileLockHandler<R> {
type Output = bool;
async fn handle(&self, cmd: DeleteFileLockCommand) -> Result<Self::Output> {
if cmd.hard_delete {
self.repository.delete(&cmd.id).await
} else {
self.repository.soft_delete(&cmd.id).await
}
}
}