backbone-bucket 0.2.1

Bucket Bounded Context: File Storage Module for Backbone Framework
Documentation
//! Commands for StoredFile aggregate
//!
//! Generated by backbone-schema. Do not edit manually.
//!
//! CQRS Commands represent intent to change state.

use async_trait::async_trait;
use anyhow::Result;
use serde::{Deserialize, Serialize};
use uuid::Uuid;

use crate::domain::entity::StoredFile;
use crate::infrastructure::persistence::StoredFileRepository;
use super::CommandHandler;

// ============================================================================
// COMMAND TRAIT (DEPRECATED)
// ============================================================================

/// Command trait for StoredFile operations
///
/// **DEPRECATED**: Use the generic `CommandHandler<C>` trait from `mod.rs` instead.
/// This trait is kept for backwards compatibility.
#[deprecated(since = "0.2.0", note = "Use CommandHandler<C> trait instead")]
#[async_trait]
pub trait StoredFileCommand: Send + Sync {
    type Output;
    async fn execute(&self) -> Result<Self::Output>;
}

// ============================================================================
// CREATE COMMAND
// ============================================================================

/// Command to create a new stored_file
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CreateStoredFileCommand {
    pub bucket_id: Uuid,
    pub owner_id: Uuid,
    pub path: String,
    pub original_name: String,
    pub size_bytes: i64,
    pub mime_type: String,
    pub checksum: Option<String>,
    pub is_compressed: bool,
    pub original_size: Option<i64>,
    pub compression_algorithm: Option<String>,
    pub is_scanned: bool,
    pub scan_result: Option<serde_json::Value>,
    pub threat_level: Option<ThreatLevel>,
    pub has_thumbnail: bool,
    pub thumbnail_path: Option<String>,
    pub has_video_thumbnail: bool,
    pub has_document_preview: bool,
    pub processing_status: Option<ProcessingStatus>,
    pub content_hash_id: Option<Uuid>,
    pub cdn_url: Option<String>,
    pub cdn_url_expires_at: Option<DateTime<Utc>>,
    pub owner_module: Option<String>,
    pub owner_entity: Option<String>,
    pub owner_entity_id: Option<Uuid>,
    pub field_name: Option<String>,
    pub sort_order: i32,
    pub status: FileStatus,
    pub storage_key: String,
    pub version: i32,
    pub previous_version_id: Option<Uuid>,
    pub download_count: i32,
    pub last_accessed_at: Option<DateTime<Utc>>,
    pub metadata: serde_json::Value,
}

/// Handler for CreateStoredFileCommand
pub struct CreateStoredFileHandler<R: StoredFileRepository> {
    repository: std::sync::Arc<R>,
}

impl<R: StoredFileRepository> CreateStoredFileHandler<R> {
    pub fn new(repository: std::sync::Arc<R>) -> Self {
        Self { repository }
    }
}

#[async_trait]
impl<R: StoredFileRepository + 'static> CommandHandler<CreateStoredFileCommand> for CreateStoredFileHandler<R> {
    type Output = StoredFile;

    async fn handle(&self, cmd: CreateStoredFileCommand) -> Result<Self::Output> {
        let entity = StoredFile::builder()
            .id(Uuid::new_v4().to_string())
            .bucket_id(cmd.bucket_id)
            .owner_id(cmd.owner_id)
            .path(cmd.path)
            .original_name(cmd.original_name)
            .size_bytes(cmd.size_bytes)
            .mime_type(cmd.mime_type)
            .checksum(cmd.checksum)
            .is_compressed(cmd.is_compressed)
            .original_size(cmd.original_size)
            .compression_algorithm(cmd.compression_algorithm)
            .is_scanned(cmd.is_scanned)
            .scan_result(cmd.scan_result)
            .threat_level(cmd.threat_level)
            .has_thumbnail(cmd.has_thumbnail)
            .thumbnail_path(cmd.thumbnail_path)
            .has_video_thumbnail(cmd.has_video_thumbnail)
            .has_document_preview(cmd.has_document_preview)
            .processing_status(cmd.processing_status)
            .content_hash_id(cmd.content_hash_id)
            .cdn_url(cmd.cdn_url)
            .cdn_url_expires_at(cmd.cdn_url_expires_at)
            .owner_module(cmd.owner_module)
            .owner_entity(cmd.owner_entity)
            .owner_entity_id(cmd.owner_entity_id)
            .field_name(cmd.field_name)
            .sort_order(cmd.sort_order)
            .status(cmd.status)
            .storage_key(cmd.storage_key)
            .version(cmd.version)
            .previous_version_id(cmd.previous_version_id)
            .download_count(cmd.download_count)
            .last_accessed_at(cmd.last_accessed_at)
            .metadata(cmd.metadata)
            .build()?;

        self.repository.save(&entity).await
    }
}

// ============================================================================
// UPDATE COMMAND
// ============================================================================

/// Command to update an existing stored_file
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UpdateStoredFileCommand {
    pub id: String,
    pub bucket_id: Option<Uuid>,
    pub owner_id: Option<Uuid>,
    pub path: Option<String>,
    pub original_name: Option<String>,
    pub size_bytes: Option<i64>,
    pub mime_type: Option<String>,
    pub checksum: Option<String>,
    pub is_compressed: Option<bool>,
    pub original_size: Option<i64>,
    pub compression_algorithm: Option<String>,
    pub is_scanned: Option<bool>,
    pub scan_result: Option<serde_json::Value>,
    pub threat_level: Option<ThreatLevel>,
    pub has_thumbnail: Option<bool>,
    pub thumbnail_path: Option<String>,
    pub has_video_thumbnail: Option<bool>,
    pub has_document_preview: Option<bool>,
    pub processing_status: Option<ProcessingStatus>,
    pub content_hash_id: Option<Uuid>,
    pub cdn_url: Option<String>,
    pub cdn_url_expires_at: Option<DateTime<Utc>>,
    pub owner_module: Option<String>,
    pub owner_entity: Option<String>,
    pub owner_entity_id: Option<Uuid>,
    pub field_name: Option<String>,
    pub sort_order: Option<i32>,
    pub status: Option<FileStatus>,
    pub storage_key: Option<String>,
    pub version: Option<i32>,
    pub previous_version_id: Option<Uuid>,
    pub download_count: Option<i32>,
    pub last_accessed_at: Option<DateTime<Utc>>,
    pub metadata: Option<serde_json::Value>,
}

/// Handler for UpdateStoredFileCommand
pub struct UpdateStoredFileHandler<R: StoredFileRepository> {
    repository: std::sync::Arc<R>,
}

impl<R: StoredFileRepository> UpdateStoredFileHandler<R> {
    pub fn new(repository: std::sync::Arc<R>) -> Self {
        Self { repository }
    }
}

#[async_trait]
impl<R: StoredFileRepository + 'static> CommandHandler<UpdateStoredFileCommand> for UpdateStoredFileHandler<R> {
    type Output = Option<StoredFile>;

    async fn handle(&self, cmd: UpdateStoredFileCommand) -> Result<Self::Output> {
        let existing = self.repository.find_by_id(&cmd.id).await?;

        let Some(mut entity) = existing else {
            return Ok(None);
        };

        // Apply updates
        if let Some(value) = cmd.bucket_id {
            entity.bucket_id = value;
        }
        if let Some(value) = cmd.owner_id {
            entity.owner_id = value;
        }
        if let Some(value) = cmd.path {
            entity.path = value;
        }
        if let Some(value) = cmd.original_name {
            entity.original_name = value;
        }
        if let Some(value) = cmd.size_bytes {
            entity.size_bytes = value;
        }
        if let Some(value) = cmd.mime_type {
            entity.mime_type = value;
        }
        entity.checksum = cmd.checksum;
        if let Some(value) = cmd.is_compressed {
            entity.is_compressed = value;
        }
        entity.original_size = cmd.original_size;
        entity.compression_algorithm = cmd.compression_algorithm;
        if let Some(value) = cmd.is_scanned {
            entity.is_scanned = value;
        }
        entity.scan_result = cmd.scan_result;
        entity.threat_level = cmd.threat_level;
        if let Some(value) = cmd.has_thumbnail {
            entity.has_thumbnail = value;
        }
        entity.thumbnail_path = cmd.thumbnail_path;
        if let Some(value) = cmd.has_video_thumbnail {
            entity.has_video_thumbnail = value;
        }
        if let Some(value) = cmd.has_document_preview {
            entity.has_document_preview = value;
        }
        entity.processing_status = cmd.processing_status;
        entity.content_hash_id = cmd.content_hash_id;
        entity.cdn_url = cmd.cdn_url;
        entity.cdn_url_expires_at = cmd.cdn_url_expires_at;
        entity.owner_module = cmd.owner_module;
        entity.owner_entity = cmd.owner_entity;
        entity.owner_entity_id = cmd.owner_entity_id;
        entity.field_name = cmd.field_name;
        if let Some(value) = cmd.sort_order {
            entity.sort_order = value;
        }
        if let Some(value) = cmd.status {
            entity.status = value;
        }
        if let Some(value) = cmd.storage_key {
            entity.storage_key = value;
        }
        if let Some(value) = cmd.version {
            entity.version = value;
        }
        entity.previous_version_id = cmd.previous_version_id;
        if let Some(value) = cmd.download_count {
            entity.download_count = value;
        }
        entity.last_accessed_at = cmd.last_accessed_at;
        if let Some(value) = cmd.metadata {
            entity.metadata = value;
        }

        self.repository.update(&cmd.id, &entity).await
    }
}

// ============================================================================
// DELETE COMMAND
// ============================================================================

/// Command to delete a stored_file
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DeleteStoredFileCommand {
    pub id: String,
    pub hard_delete: bool,
}

/// Handler for DeleteStoredFileCommand
pub struct DeleteStoredFileHandler<R: StoredFileRepository> {
    repository: std::sync::Arc<R>,
}

impl<R: StoredFileRepository> DeleteStoredFileHandler<R> {
    pub fn new(repository: std::sync::Arc<R>) -> Self {
        Self { repository }
    }
}

#[async_trait]
impl<R: StoredFileRepository + 'static> CommandHandler<DeleteStoredFileCommand> for DeleteStoredFileHandler<R> {
    type Output = bool;

    async fn handle(&self, cmd: DeleteStoredFileCommand) -> Result<Self::Output> {
        if cmd.hard_delete {
            self.repository.delete(&cmd.id).await
        } else {
            self.repository.soft_delete(&cmd.id).await
        }
    }
}

// ============================================================================
// CUSTOM COMMANDS
// ============================================================================
// <<< CUSTOM COMMANDS START >>>

// <<< CUSTOM COMMANDS START >>>
// Add your custom commands here
// Example:
//
// #[derive(Debug, Clone, Serialize, Deserialize)]
// pub struct ActivateStoredFileCommand {
//     pub id: String,
// }
// <<< CUSTOM COMMANDS END >>>