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}
198
199impl super::Entity for Package {
200 type Id = Uuid;
201
202 fn entity_id(&self) -> &Self::Id {
203 &self.id
204 }
205
206 fn entity_type() -> &'static str {
207 "Package"
208 }
209}
210
211impl backbone_core::PersistentEntity for Package {
212 fn entity_id(&self) -> String {
213 self.id.to_string()
214 }
215 fn set_entity_id(&mut self, id: String) {
216 if let Ok(uuid) = uuid::Uuid::parse_str(&id) {
217 self.id = uuid;
218 }
219 }
220 fn created_at(&self) -> Option<chrono::DateTime<chrono::Utc>> {
221 self.metadata.created_at
222 }
223 fn set_created_at(&mut self, ts: chrono::DateTime<chrono::Utc>) {
224 self.metadata.created_at = Some(ts);
225 }
226 fn updated_at(&self) -> Option<chrono::DateTime<chrono::Utc>> {
227 self.metadata.updated_at
228 }
229 fn set_updated_at(&mut self, ts: chrono::DateTime<chrono::Utc>) {
230 self.metadata.updated_at = Some(ts);
231 }
232 fn deleted_at(&self) -> Option<chrono::DateTime<chrono::Utc>> {
233 self.metadata.deleted_at
234 }
235 fn set_deleted_at(&mut self, ts: Option<chrono::DateTime<chrono::Utc>>) {
236 self.metadata.deleted_at = ts;
237 }
238}
239
240impl backbone_orm::EntityRepoMeta for Package {
241 fn column_types() -> std::collections::HashMap<String, String> {
242 let mut m = std::collections::HashMap::new();
243 m.insert("id".to_string(), "uuid".to_string());
244 m.insert("location_id".to_string(), "uuid".to_string());
245 m.insert("parent_package_id".to_string(), "uuid".to_string());
246 m.insert("package_type_id".to_string(), "uuid".to_string());
247 m.insert("pack_date".to_string(), "date".to_string());
248 m
249 }
250 fn search_fields() -> &'static [&'static str] {
251 &["name", "complete_name", "parent_path"]
252 }
253 fn relations() -> &'static [(&'static str, &'static str, &'static str)] {
254 &[("location", "locations", "locationId"), ("parentPackage", "packages", "parentPackageId"), ("packageType", "package_types", "packageTypeId")]
255 }
256}
257
258#[derive(Debug, Clone, Default)]
263pub struct PackageBuilder {
264 name: Option<String>,
265 complete_name: Option<String>,
266 location_id: Option<Uuid>,
267 parent_package_id: Option<Uuid>,
268 parent_path: Option<String>,
269 pack_date: Option<NaiveDate>,
270 package_type_id: Option<Uuid>,
271}
272
273impl PackageBuilder {
274 pub fn name(mut self, value: String) -> Self {
276 self.name = Some(value);
277 self
278 }
279
280 pub fn complete_name(mut self, value: String) -> Self {
282 self.complete_name = Some(value);
283 self
284 }
285
286 pub fn location_id(mut self, value: Uuid) -> Self {
288 self.location_id = Some(value);
289 self
290 }
291
292 pub fn parent_package_id(mut self, value: Uuid) -> Self {
294 self.parent_package_id = Some(value);
295 self
296 }
297
298 pub fn parent_path(mut self, value: String) -> Self {
300 self.parent_path = Some(value);
301 self
302 }
303
304 pub fn pack_date(mut self, value: NaiveDate) -> Self {
306 self.pack_date = Some(value);
307 self
308 }
309
310 pub fn package_type_id(mut self, value: Uuid) -> Self {
312 self.package_type_id = Some(value);
313 self
314 }
315
316 pub fn build(self) -> Result<Package, String> {
320 let name = self.name.ok_or_else(|| "name is required".to_string())?;
321 let complete_name = self.complete_name.ok_or_else(|| "complete_name is required".to_string())?;
322 let parent_path = self.parent_path.ok_or_else(|| "parent_path is required".to_string())?;
323
324 Ok(Package {
325 id: Uuid::new_v4(),
326 name,
327 complete_name,
328 location_id: self.location_id,
329 parent_package_id: self.parent_package_id,
330 parent_path,
331 pack_date: self.pack_date,
332 package_type_id: self.package_type_id,
333 metadata: AuditMetadata::default(),
334 })
335 }
336}