backbone-mail 0.2.32

Odoo mail core port — message/notification/followers/activity/alias/sms queue (schema: messaging)
//! Metadata value object
//!
//! Generated by metaphor-schema. Do not edit manually.
//!
//! This is a DDD Value Object - immutable, no identity, equality by attributes.
//!
//! Composition of: Timestamps + Actors
//!
//! Fields:
//!   - created_at: DateTime<Utc> - When the record was created
//!   - updated_at: DateTime<Utc> - When the record was last updated
//!   - deleted_at: Option<DateTime<Utc>> - When the record was soft deleted
//!   - created_by: Option<Uuid> - ID of user who created the record
//!   - updated_by: Option<Uuid> - ID of user who last updated the record
//!   - deleted_by: Option<Uuid> - ID of user who soft deleted the record

use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use uuid::Uuid;
#[cfg(feature = "openapi")]
use utoipa::ToSchema;

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "openapi", derive(ToSchema))]
pub struct Metadata {
    /// When the record was created
    pub created_at: DateTime<Utc>,
    /// When the record was last updated
    pub updated_at: DateTime<Utc>,
    /// When the record was soft deleted (if applicable)
    #[serde(skip_serializing_if = "Option::is_none")]
    pub deleted_at: Option<DateTime<Utc>>,
    /// ID of user who created the record
    #[serde(skip_serializing_if = "Option::is_none")]
    pub created_by: Option<Uuid>,
    /// ID of user who last updated the record
    #[serde(skip_serializing_if = "Option::is_none")]
    pub updated_by: Option<Uuid>,
    /// ID of user who soft deleted the record
    #[serde(skip_serializing_if = "Option::is_none")]
    pub deleted_by: Option<Uuid>,
}

impl Metadata {
    /// Create a new Metadata value object
    pub fn new(
        created_at: DateTime<Utc>,
        updated_at: DateTime<Utc>,
        deleted_at: Option<DateTime<Utc>>,
        created_by: Option<Uuid>,
        updated_by: Option<Uuid>,
        deleted_by: Option<Uuid>,
    ) -> Self {
        Self {
            created_at,
            updated_at,
            deleted_at,
            created_by,
            updated_by,
            deleted_by,
        }
    }

    /// Create metadata for a new record (created now)
    pub fn new_record(created_by: Option<Uuid>) -> Self {
        let now = Utc::now();
        Self {
            created_at: now,
            updated_at: now,
            deleted_at: None,
            created_by,
            updated_by: None,
            deleted_by: None,
        }
    }

    // =================================================================
    // Domain State Transition Methods
    // =================================================================

    /// NOTE: These methods use &mut self for domain state transitions.
    /// While value objects are typically immutable, audit metadata represents
    /// a special case where the metadata tracks the lifecycle state of an entity.
    ///
    /// Mark the record as updated
    ///
    /// Updates the updated_at timestamp and sets the updated_by user.
    /// This is a domain state transition that occurs when an entity is modified.
    pub fn mark_updated(&mut self, updated_by: Option<Uuid>) {
        self.updated_at = Utc::now();
        self.updated_by = updated_by;
    }

    /// Mark the record as soft deleted
    ///
    /// Sets the deleted_at timestamp and deleted_by user.
    /// This is a domain state transition that occurs when an entity is soft deleted.
    pub fn mark_deleted(&mut self, deleted_by: Option<Uuid>) {
        self.deleted_at = Some(Utc::now());
        self.deleted_by = deleted_by;
    }

    /// Check if the record is soft deleted
    pub fn is_deleted(&self) -> bool {
        self.deleted_at.is_some()
    }

    /// Create a builder for Metadata
    pub fn builder() -> MetadataBuilder {
        <MetadataBuilder as Default>::default()
    }

    // =================================================================
    // JSON conversion methods (for JSONB storage)
    // =================================================================

    /// Convert to serde_json::Value for storage
    pub fn to_json_value(&self) -> Result<serde_json::Value, serde_json::Error> {
        serde_json::to_value(self)
    }

    /// Convert from serde_json::Value from storage
    pub fn from_json_value(value: serde_json::Value) -> Result<Self, serde_json::Error> {
        serde_json::from_value(value)
    }
}

/// Builder for Metadata value object
///
/// # Example
/// ```ignore
/// use chrono::Utc;
/// use uuid::Uuid;
///
/// let user_id = Uuid::new_v4();
/// let metadata = Metadata::builder()
///     .created_at(Utc::now())
///     .updated_at(Utc::now())
///     .created_by(Some(user_id))
///     .build();
/// ```
#[derive(Debug, Clone, Default)]
pub struct MetadataBuilder {
    created_at: Option<DateTime<Utc>>,
    updated_at: Option<DateTime<Utc>>,
    deleted_at: Option<DateTime<Utc>>,
    created_by: Option<Uuid>,
    updated_by: Option<Uuid>,
    deleted_by: Option<Uuid>,
}

impl MetadataBuilder {
    /// Set the created_at timestamp
    pub fn created_at(mut self, value: DateTime<Utc>) -> Self {
        self.created_at = Some(value);
        self
    }

    /// Set the updated_at timestamp
    pub fn updated_at(mut self, value: DateTime<Utc>) -> Self {
        self.updated_at = Some(value);
        self
    }

    /// Set the deleted_at timestamp
    pub fn deleted_at(mut self, value: DateTime<Utc>) -> Self {
        self.deleted_at = Some(value);
        self
    }

    /// Set the created_by user ID
    pub fn created_by(mut self, value: Uuid) -> Self {
        self.created_by = Some(value);
        self
    }

    /// Set the updated_by user ID
    pub fn updated_by(mut self, value: Uuid) -> Self {
        self.updated_by = Some(value);
        self
    }

    /// Set the deleted_by user ID
    pub fn deleted_by(mut self, value: Uuid) -> Self {
        self.deleted_by = Some(value);
        self
    }

    // =================================================================
    // Optional field setters (explicit None)
    // =================================================================

    /// Set created_by to None explicitly
    pub fn no_created_by(mut self) -> Self {
        self.created_by = None;
        self
    }

    /// Set updated_by to None explicitly
    pub fn no_updated_by(mut self) -> Self {
        self.updated_by = None;
        self
    }

    /// Set deleted_by to None explicitly
    pub fn no_deleted_by(mut self) -> Self {
        self.deleted_by = None;
        self
    }

    /// Build the Metadata value object
    ///
    /// # Errors
    /// Returns error if required fields (created_at, updated_at) are not set.
    pub fn build(self) -> Result<Metadata, String> {
        let created_at = self.created_at.ok_or_else(|| "created_at is required".to_string())?;
        let updated_at = self.updated_at.ok_or_else(|| "updated_at is required".to_string())?;

        Ok(Metadata {
            created_at,
            updated_at,
            deleted_at: self.deleted_at,
            created_by: self.created_by,
            updated_by: self.updated_by,
            deleted_by: self.deleted_by,
        })
    }

}