backbone_inventory/domain/entity/
package.rs1use chrono::{DateTime, Utc, NaiveDate};
2use serde::{Deserialize, Serialize};
3use sqlx::FromRow;
4use uuid::Uuid;
5use super::AuditMetadata;
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
9#[serde(transparent)]
10pub struct PackageId(pub Uuid);
11
12impl PackageId {
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 PackageId {
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 PackageId {
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 PackageId {
32 fn from(id: Uuid) -> Self { Self(id) }
33}
34
35impl From<PackageId> for Uuid {
36 fn from(id: PackageId) -> Self { id.0 }
37}
38
39impl AsRef<Uuid> for PackageId {
40 fn as_ref(&self) -> &Uuid { &self.0 }
41}
42
43impl std::ops::Deref for PackageId {
44 type Target = Uuid;
45 fn deref(&self) -> &Self::Target { &self.0 }
46}
47
48#[derive(Debug, Clone, Serialize, Deserialize, FromRow)]
49pub struct Package {
50 pub id: Uuid,
51 pub name: String,
52 pub complete_name: String,
53 pub location_id: Option<Uuid>,
54 pub parent_package_id: Option<Uuid>,
55 pub parent_path: String,
56 pub pack_date: Option<NaiveDate>,
57 pub package_type_id: Option<Uuid>,
58 #[serde(default)]
59 #[sqlx(json)]
60 pub metadata: AuditMetadata,
61}
62
63impl Package {
64 pub fn builder() -> PackageBuilder {
66 <PackageBuilder as Default>::default()
67 }
68
69 pub fn new(name: String, complete_name: String, parent_path: String) -> Self {
71 Self {
72 id: Uuid::new_v4(),
73 name,
74 complete_name,
75 location_id: None,
76 parent_package_id: None,
77 parent_path,
78 pack_date: None,
79 package_type_id: None,
80 metadata: AuditMetadata::default(),
81 }
82 }
83
84 pub fn id(&self) -> &Uuid {
86 &self.id
87 }
88
89 pub fn typed_id(&self) -> PackageId {
91 PackageId(self.id)
92 }
93
94 pub fn created_at(&self) -> Option<&DateTime<Utc>> {
96 self.metadata.created_at.as_ref()
97 }
98
99 pub fn updated_at(&self) -> Option<&DateTime<Utc>> {
101 self.metadata.updated_at.as_ref()
102 }
103
104 pub fn is_deleted(&self) -> bool {
106 self.metadata.deleted_at.is_some()
107 }
108
109 pub fn is_active(&self) -> bool {
111 self.metadata.deleted_at.is_none()
112 }
113
114 pub fn deleted_at(&self) -> Option<&DateTime<Utc>> {
116 self.metadata.deleted_at.as_ref()
117 }
118
119 pub fn created_by(&self) -> Option<&Uuid> {
121 self.metadata.created_by.as_ref()
122 }
123
124 pub fn updated_by(&self) -> Option<&Uuid> {
126 self.metadata.updated_by.as_ref()
127 }
128
129 pub fn deleted_by(&self) -> Option<&Uuid> {
131 self.metadata.deleted_by.as_ref()
132 }
133
134
135 pub fn with_location_id(mut self, value: Uuid) -> Self {
141 self.location_id = Some(value);
142 self
143 }
144
145 pub fn with_parent_package_id(mut self, value: Uuid) -> Self {
147 self.parent_package_id = Some(value);
148 self
149 }
150
151 pub fn with_pack_date(mut self, value: NaiveDate) -> Self {
153 self.pack_date = Some(value);
154 self
155 }
156
157 pub fn with_package_type_id(mut self, value: Uuid) -> Self {
159 self.package_type_id = Some(value);
160 self
161 }
162
163 pub fn apply_patch(&mut self, fields: std::collections::HashMap<String, serde_json::Value>) {
169 for (key, value) in fields {
170 match key.as_str() {
171 "name" => {
172 if let Ok(v) = serde_json::from_value(value) { self.name = v; }
173 }
174 "complete_name" => {
175 if let Ok(v) = serde_json::from_value(value) { self.complete_name = v; }
176 }
177 "location_id" => {
178 if let Ok(v) = serde_json::from_value(value) { self.location_id = v; }
179 }
180 "parent_package_id" => {
181 if let Ok(v) = serde_json::from_value(value) { self.parent_package_id = v; }
182 }
183 "parent_path" => {
184 if let Ok(v) = serde_json::from_value(value) { self.parent_path = v; }
185 }
186 "pack_date" => {
187 if let Ok(v) = serde_json::from_value(value) { self.pack_date = v; }
188 }
189 "package_type_id" => {
190 if let Ok(v) = serde_json::from_value(value) { self.package_type_id = v; }
191 }
192 _ => {} }
194 }
195 }
196
197 }
200
201impl super::Entity for Package {
202 type Id = Uuid;
203
204 fn entity_id(&self) -> &Self::Id {
205 &self.id
206 }
207
208 fn entity_type() -> &'static str {
209 "Package"
210 }
211}
212
213impl backbone_core::PersistentEntity for Package {
214 fn entity_id(&self) -> String {
215 self.id.to_string()
216 }
217 fn set_entity_id(&mut self, id: String) {
218 if let Ok(uuid) = uuid::Uuid::parse_str(&id) {
219 self.id = uuid;
220 }
221 }
222 fn created_at(&self) -> Option<chrono::DateTime<chrono::Utc>> {
223 self.metadata.created_at
224 }
225 fn set_created_at(&mut self, ts: chrono::DateTime<chrono::Utc>) {
226 self.metadata.created_at = Some(ts);
227 }
228 fn updated_at(&self) -> Option<chrono::DateTime<chrono::Utc>> {
229 self.metadata.updated_at
230 }
231 fn set_updated_at(&mut self, ts: chrono::DateTime<chrono::Utc>) {
232 self.metadata.updated_at = Some(ts);
233 }
234 fn deleted_at(&self) -> Option<chrono::DateTime<chrono::Utc>> {
235 self.metadata.deleted_at
236 }
237 fn set_deleted_at(&mut self, ts: Option<chrono::DateTime<chrono::Utc>>) {
238 self.metadata.deleted_at = ts;
239 }
240}
241
242impl backbone_orm::EntityRepoMeta for Package {
243 fn column_types() -> std::collections::HashMap<String, String> {
244 let mut m = std::collections::HashMap::new();
245 m.insert("id".to_string(), "uuid".to_string());
246 m.insert("location_id".to_string(), "uuid".to_string());
247 m.insert("parent_package_id".to_string(), "uuid".to_string());
248 m.insert("package_type_id".to_string(), "uuid".to_string());
249 m.insert("pack_date".to_string(), "date".to_string());
250 m
251 }
252 fn search_fields() -> &'static [&'static str] {
253 &["name", "complete_name", "parent_path"]
254 }
255}
256
257#[derive(Debug, Clone, Default)]
262pub struct PackageBuilder {
263 name: Option<String>,
264 complete_name: Option<String>,
265 location_id: Option<Uuid>,
266 parent_package_id: Option<Uuid>,
267 parent_path: Option<String>,
268 pack_date: Option<NaiveDate>,
269 package_type_id: Option<Uuid>,
270}
271
272impl PackageBuilder {
273 pub fn name(mut self, value: String) -> Self {
275 self.name = Some(value);
276 self
277 }
278
279 pub fn complete_name(mut self, value: String) -> Self {
281 self.complete_name = Some(value);
282 self
283 }
284
285 pub fn location_id(mut self, value: Uuid) -> Self {
287 self.location_id = Some(value);
288 self
289 }
290
291 pub fn parent_package_id(mut self, value: Uuid) -> Self {
293 self.parent_package_id = Some(value);
294 self
295 }
296
297 pub fn parent_path(mut self, value: String) -> Self {
299 self.parent_path = Some(value);
300 self
301 }
302
303 pub fn pack_date(mut self, value: NaiveDate) -> Self {
305 self.pack_date = Some(value);
306 self
307 }
308
309 pub fn package_type_id(mut self, value: Uuid) -> Self {
311 self.package_type_id = Some(value);
312 self
313 }
314
315 pub fn build(self) -> Result<Package, String> {
319 let name = self.name.ok_or_else(|| "name is required".to_string())?;
320 let complete_name = self.complete_name.ok_or_else(|| "complete_name is required".to_string())?;
321 let parent_path = self.parent_path.ok_or_else(|| "parent_path is required".to_string())?;
322
323 Ok(Package {
324 id: Uuid::new_v4(),
325 name,
326 complete_name,
327 location_id: self.location_id,
328 parent_package_id: self.parent_package_id,
329 parent_path,
330 pack_date: self.pack_date,
331 package_type_id: self.package_type_id,
332 metadata: AuditMetadata::default(),
333 })
334 }
335}