use async_trait::async_trait;
use anyhow::Result;
use serde::{Deserialize, Serialize};
use uuid::Uuid;
use crate::domain::entity::ContentHash;
use crate::infrastructure::persistence::ContentHashRepository;
use super::CommandHandler;
#[deprecated(since = "0.2.0", note = "Use CommandHandler<C> trait instead")]
#[async_trait]
pub trait ContentHashCommand: Send + Sync {
type Output;
async fn execute(&self) -> Result<Self::Output>;
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CreateContentHashCommand {
pub hash: String,
pub size_bytes: i64,
pub storage_key: String,
pub storage_backend: StorageBackend,
pub reference_count: i32,
pub first_uploaded_at: DateTime<Utc>,
pub last_referenced_at: DateTime<Utc>,
pub fingerprint: Option<String>,
pub metadata: serde_json::Value,
}
pub struct CreateContentHashHandler<R: ContentHashRepository> {
repository: std::sync::Arc<R>,
}
impl<R: ContentHashRepository> CreateContentHashHandler<R> {
pub fn new(repository: std::sync::Arc<R>) -> Self {
Self { repository }
}
}
#[async_trait]
impl<R: ContentHashRepository + 'static> CommandHandler<CreateContentHashCommand> for CreateContentHashHandler<R> {
type Output = ContentHash;
async fn handle(&self, cmd: CreateContentHashCommand) -> Result<Self::Output> {
let entity = ContentHash::builder()
.id(Uuid::new_v4().to_string())
.hash(cmd.hash)
.size_bytes(cmd.size_bytes)
.storage_key(cmd.storage_key)
.storage_backend(cmd.storage_backend)
.reference_count(cmd.reference_count)
.first_uploaded_at(cmd.first_uploaded_at)
.last_referenced_at(cmd.last_referenced_at)
.fingerprint(cmd.fingerprint)
.metadata(cmd.metadata)
.build()?;
self.repository.save(&entity).await
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UpdateContentHashCommand {
pub id: String,
pub hash: Option<String>,
pub size_bytes: Option<i64>,
pub storage_key: Option<String>,
pub storage_backend: Option<StorageBackend>,
pub reference_count: Option<i32>,
pub first_uploaded_at: Option<DateTime<Utc>>,
pub last_referenced_at: Option<DateTime<Utc>>,
pub fingerprint: Option<String>,
pub metadata: Option<serde_json::Value>,
}
pub struct UpdateContentHashHandler<R: ContentHashRepository> {
repository: std::sync::Arc<R>,
}
impl<R: ContentHashRepository> UpdateContentHashHandler<R> {
pub fn new(repository: std::sync::Arc<R>) -> Self {
Self { repository }
}
}
#[async_trait]
impl<R: ContentHashRepository + 'static> CommandHandler<UpdateContentHashCommand> for UpdateContentHashHandler<R> {
type Output = Option<ContentHash>;
async fn handle(&self, cmd: UpdateContentHashCommand) -> 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.hash {
entity.hash = value;
}
if let Some(value) = cmd.size_bytes {
entity.size_bytes = 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.reference_count {
entity.reference_count = value;
}
if let Some(value) = cmd.first_uploaded_at {
entity.first_uploaded_at = value;
}
if let Some(value) = cmd.last_referenced_at {
entity.last_referenced_at = value;
}
entity.fingerprint = cmd.fingerprint;
if let Some(value) = cmd.metadata {
entity.metadata = value;
}
self.repository.update(&cmd.id, &entity).await
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DeleteContentHashCommand {
pub id: String,
pub hard_delete: bool,
}
pub struct DeleteContentHashHandler<R: ContentHashRepository> {
repository: std::sync::Arc<R>,
}
impl<R: ContentHashRepository> DeleteContentHashHandler<R> {
pub fn new(repository: std::sync::Arc<R>) -> Self {
Self { repository }
}
}
#[async_trait]
impl<R: ContentHashRepository + 'static> CommandHandler<DeleteContentHashCommand> for DeleteContentHashHandler<R> {
type Output = bool;
async fn handle(&self, cmd: DeleteContentHashCommand) -> Result<Self::Output> {
if cmd.hard_delete {
self.repository.delete(&cmd.id).await
} else {
self.repository.soft_delete(&cmd.id).await
}
}
}