Skip to main content

backbone_bucket/domain/value_objects/
metadata.rs

1//! Metadata value object
2//!
3//! Generated by metaphor-schema. Do not edit manually.
4//!
5//! This is a DDD Value Object - immutable, no identity, equality by attributes.
6//!
7//! Composition of: Timestamps + Actors
8//!
9//! Fields:
10//!   - created_at: DateTime<Utc> - When the record was created
11//!   - updated_at: DateTime<Utc> - When the record was last updated
12//!   - deleted_at: Option<DateTime<Utc>> - When the record was soft deleted
13//!   - created_by: Option<Uuid> - ID of user who created the record
14//!   - updated_by: Option<Uuid> - ID of user who last updated the record
15//!   - deleted_by: Option<Uuid> - ID of user who soft deleted the record
16
17use chrono::{DateTime, Utc};
18use serde::{Deserialize, Serialize};
19use uuid::Uuid;
20#[cfg(feature = "openapi")]
21use utoipa::ToSchema;
22
23#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
24#[cfg_attr(feature = "openapi", derive(ToSchema))]
25pub struct Metadata {
26    /// When the record was created
27    pub created_at: DateTime<Utc>,
28    /// When the record was last updated
29    pub updated_at: DateTime<Utc>,
30    /// When the record was soft deleted (if applicable)
31    #[serde(skip_serializing_if = "Option::is_none")]
32    pub deleted_at: Option<DateTime<Utc>>,
33    /// ID of user who created the record
34    #[serde(skip_serializing_if = "Option::is_none")]
35    pub created_by: Option<Uuid>,
36    /// ID of user who last updated the record
37    #[serde(skip_serializing_if = "Option::is_none")]
38    pub updated_by: Option<Uuid>,
39    /// ID of user who soft deleted the record
40    #[serde(skip_serializing_if = "Option::is_none")]
41    pub deleted_by: Option<Uuid>,
42}
43
44impl Metadata {
45    /// Create a new Metadata value object
46    pub fn new(
47        created_at: DateTime<Utc>,
48        updated_at: DateTime<Utc>,
49        deleted_at: Option<DateTime<Utc>>,
50        created_by: Option<Uuid>,
51        updated_by: Option<Uuid>,
52        deleted_by: Option<Uuid>,
53    ) -> Self {
54        Self {
55            created_at,
56            updated_at,
57            deleted_at,
58            created_by,
59            updated_by,
60            deleted_by,
61        }
62    }
63
64    /// Create metadata for a new record (created now)
65    pub fn new_record(created_by: Option<Uuid>) -> Self {
66        let now = Utc::now();
67        Self {
68            created_at: now,
69            updated_at: now,
70            deleted_at: None,
71            created_by,
72            updated_by: None,
73            deleted_by: None,
74        }
75    }
76
77    // =================================================================
78    // Domain State Transition Methods
79    // =================================================================
80
81    /// NOTE: These methods use &mut self for domain state transitions.
82    /// While value objects are typically immutable, audit metadata represents
83    /// a special case where the metadata tracks the lifecycle state of an entity.
84    ///
85    /// Mark the record as updated
86    ///
87    /// Updates the updated_at timestamp and sets the updated_by user.
88    /// This is a domain state transition that occurs when an entity is modified.
89    pub fn mark_updated(&mut self, updated_by: Option<Uuid>) {
90        self.updated_at = Utc::now();
91        self.updated_by = updated_by;
92    }
93
94    /// Mark the record as soft deleted
95    ///
96    /// Sets the deleted_at timestamp and deleted_by user.
97    /// This is a domain state transition that occurs when an entity is soft deleted.
98    pub fn mark_deleted(&mut self, deleted_by: Option<Uuid>) {
99        self.deleted_at = Some(Utc::now());
100        self.deleted_by = deleted_by;
101    }
102
103    /// Check if the record is soft deleted
104    pub fn is_deleted(&self) -> bool {
105        self.deleted_at.is_some()
106    }
107
108    /// Create a builder for Metadata
109    pub fn builder() -> MetadataBuilder {
110        <MetadataBuilder as Default>::default()
111    }
112
113    // =================================================================
114    // JSON conversion methods (for JSONB storage)
115    // =================================================================
116
117    /// Convert to serde_json::Value for storage
118    pub fn to_json_value(&self) -> Result<serde_json::Value, serde_json::Error> {
119        serde_json::to_value(self)
120    }
121
122    /// Convert from serde_json::Value from storage
123    pub fn from_json_value(value: serde_json::Value) -> Result<Self, serde_json::Error> {
124        serde_json::from_value(value)
125    }
126}
127
128/// Builder for Metadata value object
129///
130/// # Example
131/// ```ignore
132/// use chrono::Utc;
133/// use uuid::Uuid;
134///
135/// let user_id = Uuid::new_v4();
136/// let metadata = Metadata::builder()
137///     .created_at(Utc::now())
138///     .updated_at(Utc::now())
139///     .created_by(Some(user_id))
140///     .build();
141/// ```
142#[derive(Debug, Clone, Default)]
143pub struct MetadataBuilder {
144    created_at: Option<DateTime<Utc>>,
145    updated_at: Option<DateTime<Utc>>,
146    deleted_at: Option<DateTime<Utc>>,
147    created_by: Option<Uuid>,
148    updated_by: Option<Uuid>,
149    deleted_by: Option<Uuid>,
150}
151
152impl MetadataBuilder {
153    /// Set the created_at timestamp
154    pub fn created_at(mut self, value: DateTime<Utc>) -> Self {
155        self.created_at = Some(value);
156        self
157    }
158
159    /// Set the updated_at timestamp
160    pub fn updated_at(mut self, value: DateTime<Utc>) -> Self {
161        self.updated_at = Some(value);
162        self
163    }
164
165    /// Set the deleted_at timestamp
166    pub fn deleted_at(mut self, value: DateTime<Utc>) -> Self {
167        self.deleted_at = Some(value);
168        self
169    }
170
171    /// Set the created_by user ID
172    pub fn created_by(mut self, value: Uuid) -> Self {
173        self.created_by = Some(value);
174        self
175    }
176
177    /// Set the updated_by user ID
178    pub fn updated_by(mut self, value: Uuid) -> Self {
179        self.updated_by = Some(value);
180        self
181    }
182
183    /// Set the deleted_by user ID
184    pub fn deleted_by(mut self, value: Uuid) -> Self {
185        self.deleted_by = Some(value);
186        self
187    }
188
189    // =================================================================
190    // Optional field setters (explicit None)
191    // =================================================================
192
193    /// Set created_by to None explicitly
194    pub fn no_created_by(mut self) -> Self {
195        self.created_by = None;
196        self
197    }
198
199    /// Set updated_by to None explicitly
200    pub fn no_updated_by(mut self) -> Self {
201        self.updated_by = None;
202        self
203    }
204
205    /// Set deleted_by to None explicitly
206    pub fn no_deleted_by(mut self) -> Self {
207        self.deleted_by = None;
208        self
209    }
210
211    /// Build the Metadata value object
212    ///
213    /// # Errors
214    /// Returns error if required fields (created_at, updated_at) are not set.
215    pub fn build(self) -> Result<Metadata, String> {
216        let created_at = self.created_at.ok_or_else(|| "created_at is required".to_string())?;
217        let updated_at = self.updated_at.ok_or_else(|| "updated_at is required".to_string())?;
218
219        Ok(Metadata {
220            created_at,
221            updated_at,
222            deleted_at: self.deleted_at,
223            created_by: self.created_by,
224            updated_by: self.updated_by,
225            deleted_by: self.deleted_by,
226        })
227    }
228
229}