Skip to main content

backbone_pos/domain/entity/
pos_table.rs

1use chrono::{DateTime, Utc};
2use serde::{Deserialize, Serialize};
3use sqlx::FromRow;
4use uuid::Uuid;
5use super::AuditMetadata;
6
7/// Strongly-typed ID for PosTable
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
9#[serde(transparent)]
10pub struct PosTableId(pub Uuid);
11
12impl PosTableId {
13    pub fn new(id: Uuid) -> Self { Self(id) }
14    pub fn generate() -> Self { Self(Uuid::new_v4()) }
15    pub fn into_inner(self) -> Uuid { self.0 }
16}
17
18impl std::fmt::Display for PosTableId {
19    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
20        write!(f, "{}", self.0)
21    }
22}
23
24impl std::str::FromStr for PosTableId {
25    type Err = uuid::Error;
26    fn from_str(s: &str) -> Result<Self, Self::Err> {
27        Ok(Self(Uuid::parse_str(s)?))
28    }
29}
30
31impl From<Uuid> for PosTableId {
32    fn from(id: Uuid) -> Self { Self(id) }
33}
34
35impl From<PosTableId> for Uuid {
36    fn from(id: PosTableId) -> Self { id.0 }
37}
38
39impl AsRef<Uuid> for PosTableId {
40    fn as_ref(&self) -> &Uuid { &self.0 }
41}
42
43impl std::ops::Deref for PosTableId {
44    type Target = Uuid;
45    fn deref(&self) -> &Self::Target { &self.0 }
46}
47
48#[derive(Debug, Clone, Serialize, Deserialize, FromRow)]
49pub struct PosTable {
50    pub id: Uuid,
51    pub pos_floor_plan_id: Uuid,
52    pub name: Option<String>,
53    pub seats: Option<i32>,
54    pub shape: Option<String>,
55    pub position: Option<serde_json::Value>,
56    #[serde(default)]
57    #[sqlx(json)]
58    pub metadata: AuditMetadata,
59}
60
61impl PosTable {
62    /// Create a builder for PosTable
63    pub fn builder() -> PosTableBuilder {
64        <PosTableBuilder as Default>::default()
65    }
66
67    /// Create a new PosTable with required fields
68    pub fn new(pos_floor_plan_id: Uuid) -> Self {
69        Self {
70            id: Uuid::new_v4(),
71            pos_floor_plan_id,
72            name: None,
73            seats: None,
74            shape: None,
75            position: None,
76            metadata: AuditMetadata::default(),
77        }
78    }
79
80    /// Get the entity's unique identifier
81    pub fn id(&self) -> &Uuid {
82        &self.id
83    }
84
85    /// Get a strongly-typed ID for this entity
86    pub fn typed_id(&self) -> PosTableId {
87        PosTableId(self.id)
88    }
89
90    /// Get when this entity was created
91    pub fn created_at(&self) -> Option<&DateTime<Utc>> {
92        self.metadata.created_at.as_ref()
93    }
94
95    /// Get when this entity was last updated
96    pub fn updated_at(&self) -> Option<&DateTime<Utc>> {
97        self.metadata.updated_at.as_ref()
98    }
99
100    /// Check if this entity is soft deleted
101    pub fn is_deleted(&self) -> bool {
102        self.metadata.deleted_at.is_some()
103    }
104
105    /// Check if this entity is active (not deleted)
106    pub fn is_active(&self) -> bool {
107        self.metadata.deleted_at.is_none()
108    }
109
110    /// Get when this entity was deleted
111    pub fn deleted_at(&self) -> Option<&DateTime<Utc>> {
112        self.metadata.deleted_at.as_ref()
113    }
114
115    /// Get who created this entity
116    pub fn created_by(&self) -> Option<&Uuid> {
117        self.metadata.created_by.as_ref()
118    }
119
120    /// Get who last updated this entity
121    pub fn updated_by(&self) -> Option<&Uuid> {
122        self.metadata.updated_by.as_ref()
123    }
124
125    /// Get who deleted this entity
126    pub fn deleted_by(&self) -> Option<&Uuid> {
127        self.metadata.deleted_by.as_ref()
128    }
129
130
131    // ==========================================================
132    // Fluent Setters (with_* for optional fields)
133    // ==========================================================
134
135    /// Set the name field (chainable)
136    pub fn with_name(mut self, value: String) -> Self {
137        self.name = Some(value);
138        self
139    }
140
141    /// Set the seats field (chainable)
142    pub fn with_seats(mut self, value: i32) -> Self {
143        self.seats = Some(value);
144        self
145    }
146
147    /// Set the shape field (chainable)
148    pub fn with_shape(mut self, value: String) -> Self {
149        self.shape = Some(value);
150        self
151    }
152
153    /// Set the position field (chainable)
154    pub fn with_position(mut self, value: serde_json::Value) -> Self {
155        self.position = Some(value);
156        self
157    }
158
159    // ==========================================================
160    // Partial Update
161    // ==========================================================
162
163    /// Apply partial updates from a map of field name to JSON value
164    pub fn apply_patch(&mut self, fields: std::collections::HashMap<String, serde_json::Value>) {
165        for (key, value) in fields {
166            match key.as_str() {
167                "pos_floor_plan_id" => {
168                    if let Ok(v) = serde_json::from_value(value) { self.pos_floor_plan_id = v; }
169                }
170                "name" => {
171                    if let Ok(v) = serde_json::from_value(value) { self.name = v; }
172                }
173                "seats" => {
174                    if let Ok(v) = serde_json::from_value(value) { self.seats = v; }
175                }
176                "shape" => {
177                    if let Ok(v) = serde_json::from_value(value) { self.shape = v; }
178                }
179                "position" => {
180                    if let Ok(v) = serde_json::from_value(value) { self.position = v; }
181                }
182                _ => {} // ignore unknown fields
183            }
184        }
185    }
186
187    // <<< CUSTOM METHODS START >>>
188    // <<< CUSTOM METHODS END >>>
189}
190
191impl super::Entity for PosTable {
192    type Id = Uuid;
193
194    fn entity_id(&self) -> &Self::Id {
195        &self.id
196    }
197
198    fn entity_type() -> &'static str {
199        "PosTable"
200    }
201}
202
203impl backbone_core::PersistentEntity for PosTable {
204    fn entity_id(&self) -> String {
205        self.id.to_string()
206    }
207    fn set_entity_id(&mut self, id: String) {
208        if let Ok(uuid) = uuid::Uuid::parse_str(&id) {
209            self.id = uuid;
210        }
211    }
212    fn created_at(&self) -> Option<chrono::DateTime<chrono::Utc>> {
213        self.metadata.created_at
214    }
215    fn set_created_at(&mut self, ts: chrono::DateTime<chrono::Utc>) {
216        self.metadata.created_at = Some(ts);
217    }
218    fn updated_at(&self) -> Option<chrono::DateTime<chrono::Utc>> {
219        self.metadata.updated_at
220    }
221    fn set_updated_at(&mut self, ts: chrono::DateTime<chrono::Utc>) {
222        self.metadata.updated_at = Some(ts);
223    }
224    fn deleted_at(&self) -> Option<chrono::DateTime<chrono::Utc>> {
225        self.metadata.deleted_at
226    }
227    fn set_deleted_at(&mut self, ts: Option<chrono::DateTime<chrono::Utc>>) {
228        self.metadata.deleted_at = ts;
229    }
230}
231
232impl backbone_orm::EntityRepoMeta for PosTable {
233    fn column_types() -> std::collections::HashMap<String, String> {
234        let mut m = std::collections::HashMap::new();
235        m.insert("id".to_string(), "uuid".to_string());
236        m.insert("pos_floor_plan_id".to_string(), "uuid".to_string());
237        m
238    }
239    fn search_fields() -> &'static [&'static str] {
240        &[]
241    }
242    fn relations() -> &'static [(&'static str, &'static str, &'static str)] {
243        &[("floorPlan", "pos_floor_plans", "posFloorPlanId")]
244    }
245}
246
247/// Builder for PosTable entity
248///
249/// Provides a fluent API for constructing PosTable instances.
250/// System fields (id, metadata, timestamps) are auto-initialized.
251#[derive(Debug, Clone, Default)]
252pub struct PosTableBuilder {
253    pos_floor_plan_id: Option<Uuid>,
254    name: Option<String>,
255    seats: Option<i32>,
256    shape: Option<String>,
257    position: Option<serde_json::Value>,
258}
259
260impl PosTableBuilder {
261    /// Set the pos_floor_plan_id field (required)
262    pub fn pos_floor_plan_id(mut self, value: Uuid) -> Self {
263        self.pos_floor_plan_id = Some(value);
264        self
265    }
266
267    /// Set the name field (optional)
268    pub fn name(mut self, value: String) -> Self {
269        self.name = Some(value);
270        self
271    }
272
273    /// Set the seats field (optional)
274    pub fn seats(mut self, value: i32) -> Self {
275        self.seats = Some(value);
276        self
277    }
278
279    /// Set the shape field (optional)
280    pub fn shape(mut self, value: String) -> Self {
281        self.shape = Some(value);
282        self
283    }
284
285    /// Set the position field (optional)
286    pub fn position(mut self, value: serde_json::Value) -> Self {
287        self.position = Some(value);
288        self
289    }
290
291    /// Build the PosTable entity
292    ///
293    /// Returns Err if any required field without a default is missing.
294    pub fn build(self) -> Result<PosTable, String> {
295        let pos_floor_plan_id = self.pos_floor_plan_id.ok_or_else(|| "pos_floor_plan_id is required".to_string())?;
296
297        Ok(PosTable {
298            id: Uuid::new_v4(),
299            pos_floor_plan_id,
300            name: self.name,
301            seats: self.seats,
302            shape: self.shape,
303            position: self.position,
304            metadata: AuditMetadata::default(),
305        })
306    }
307}