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}