1use crate::{DataType, default_table_name};
2
3#[derive(Debug, Clone, PartialEq, Eq)]
4pub struct PropertyDescriptor {
5 pub name: String,
6 pub data_type: DataType,
7 pub nullable: bool,
8 pub column_name: String,
9 pub is_id: bool,
10 pub is_version: bool,
11 pub max_length: Option<u32>,
12 pub numeric_precision: Option<u32>,
13 pub numeric_scale: Option<u32>,
14}
15
16impl PropertyDescriptor {
17 pub fn new(name: impl Into<String>, data_type: DataType) -> Self {
18 let name = name.into();
19 Self {
20 column_name: name.clone(),
21 name,
22 data_type,
23 nullable: true,
24 is_id: false,
25 is_version: false,
26 max_length: None,
27 numeric_precision: None,
28 numeric_scale: None,
29 }
30 }
31
32 pub fn column_name(mut self, column_name: impl Into<String>) -> Self {
33 self.column_name = column_name.into();
34 self
35 }
36
37 pub fn not_null(mut self) -> Self {
38 self.nullable = false;
39 self
40 }
41
42 pub fn id(mut self) -> Self {
43 self.is_id = true;
44 self
45 }
46
47 pub fn version(mut self) -> Self {
48 self.is_version = true;
49 self
50 }
51
52 pub fn max_length(mut self, max_length: u32) -> Self {
53 self.max_length = Some(max_length);
54 self
55 }
56
57 pub fn numeric_precision(mut self, precision: u32) -> Self {
58 self.numeric_precision = Some(precision);
59 self
60 }
61
62 pub fn numeric_scale(mut self, scale: u32) -> Self {
63 self.numeric_scale = Some(scale);
64 self
65 }
66}
67
68#[derive(Debug, Clone, PartialEq, Eq)]
69pub struct RelationDescriptor {
70 pub name: String,
71 pub target_entity: String,
72 pub local_key: String,
73 pub foreign_key: String,
74 pub many: bool,
75 pub attach: bool,
76 pub delete_missing: bool,
77}
78
79impl RelationDescriptor {
80 pub fn new(name: impl Into<String>, target_entity: impl Into<String>) -> Self {
81 Self {
82 name: name.into(),
83 target_entity: target_entity.into(),
84 local_key: "id".to_owned(),
85 foreign_key: "id".to_owned(),
86 many: false,
87 attach: true,
88 delete_missing: true,
89 }
90 }
91
92 pub fn local_key(mut self, key: impl Into<String>) -> Self {
93 self.local_key = key.into();
94 self
95 }
96
97 pub fn foreign_key(mut self, key: impl Into<String>) -> Self {
98 self.foreign_key = key.into();
99 self
100 }
101
102 pub fn many(mut self) -> Self {
103 self.many = true;
104 self
105 }
106
107 pub fn attach(mut self) -> Self {
108 self.attach = true;
109 self
110 }
111
112 pub fn detached(mut self) -> Self {
113 self.attach = false;
114 self
115 }
116
117 pub fn delete_missing(mut self) -> Self {
118 self.delete_missing = true;
119 self
120 }
121
122 pub fn keep_missing(mut self) -> Self {
123 self.delete_missing = false;
124 self
125 }
126}
127
128#[derive(Debug, Clone, PartialEq, Eq)]
129pub struct EntityDescriptor {
130 pub name: String,
131 pub table_name: String,
132 pub data_service: Option<String>,
133 pub properties: Vec<PropertyDescriptor>,
134 pub relations: Vec<RelationDescriptor>,
135 pub audit_mask_fields: Vec<String>,
136 pub audit_mask_fields_declared: bool,
138 pub audit_value_max_len: Option<usize>,
139}
140
141impl EntityDescriptor {
142 pub fn new(name: impl Into<String>) -> Self {
143 let name = name.into();
144 Self {
145 table_name: default_table_name(&name),
146 name,
147 data_service: None,
148 properties: Vec::new(),
149 relations: Vec::new(),
150 audit_mask_fields: Vec::new(),
151 audit_mask_fields_declared: false,
152 audit_value_max_len: None,
153 }
154 }
155
156 pub fn table_name(mut self, table_name: impl Into<String>) -> Self {
157 self.table_name = table_name.into();
158 self
159 }
160
161 pub fn data_service(mut self, data_service: impl Into<String>) -> Self {
162 self.data_service = Some(data_service.into());
163 self
164 }
165
166 pub fn property(mut self, property: PropertyDescriptor) -> Self {
167 self.properties.push(property);
168 self
169 }
170
171 pub fn relation(mut self, relation: RelationDescriptor) -> Self {
172 self.relations.push(relation);
173 self
174 }
175
176 pub fn audit_mask_fields(mut self, fields: Vec<String>) -> Self {
177 self.audit_mask_fields = fields;
178 self.audit_mask_fields_declared = true;
179 self
180 }
181
182 pub fn audit_value_max_len(mut self, max_len: Option<usize>) -> Self {
183 self.audit_value_max_len = max_len;
184 self
185 }
186
187 pub fn property_by_name(&self, name: &str) -> Option<&PropertyDescriptor> {
188 self.properties
189 .iter()
190 .find(|property| property.name == name)
191 }
192
193 pub fn relation_by_name(&self, name: &str) -> Option<&RelationDescriptor> {
194 self.relations.iter().find(|relation| relation.name == name)
195 }
196
197 pub fn id_property(&self) -> Option<&PropertyDescriptor> {
198 self.properties.iter().find(|property| property.is_id)
199 }
200
201 pub fn version_property(&self) -> Option<&PropertyDescriptor> {
202 self.properties.iter().find(|property| property.is_version)
203 }
204
205 pub fn writable_properties(&self) -> impl Iterator<Item = &PropertyDescriptor> {
206 self.properties.iter().filter(|property| !property.is_id)
207 }
208}
209
210#[cfg(test)]
211mod tests {
212 use super::*;
213
214 #[test]
215 fn test_property_descriptor_builder() {
216 let prop = PropertyDescriptor::new("username", DataType::Text)
217 .column_name("user_name")
218 .not_null()
219 .id()
220 .version()
221 .max_length(120)
222 .numeric_precision(19)
223 .numeric_scale(7);
224
225 assert_eq!(prop.name, "username");
226 assert_eq!(prop.column_name, "user_name");
227 assert_eq!(prop.data_type, DataType::Text);
228 assert!(!prop.nullable);
229 assert!(prop.is_id);
230 assert!(prop.is_version);
231 assert_eq!(prop.max_length, Some(120));
232 assert_eq!(prop.numeric_precision, Some(19));
233 assert_eq!(prop.numeric_scale, Some(7));
234 }
235
236 #[test]
237 fn test_relation_descriptor_builder() {
238 let rel = RelationDescriptor::new("orders", "Order")
239 .local_key("user_id")
240 .foreign_key("customer_id")
241 .many()
242 .detached()
243 .keep_missing();
244
245 assert_eq!(rel.name, "orders");
246 assert_eq!(rel.target_entity, "Order");
247 assert_eq!(rel.local_key, "user_id");
248 assert_eq!(rel.foreign_key, "customer_id");
249 assert!(rel.many);
250 assert!(!rel.attach);
251 assert!(!rel.delete_missing);
252 }
253
254 #[test]
255 fn test_entity_descriptor_builder_and_lookups() {
256 let mut entity = EntityDescriptor::new("User")
257 .table_name("users")
258 .data_service("auth_db")
259 .audit_mask_fields(vec!["password".to_string()])
260 .audit_value_max_len(Some(255));
261
262 let id_prop = PropertyDescriptor::new("id", DataType::I64).id();
263 let name_prop = PropertyDescriptor::new("name", DataType::Text);
264 let version_prop = PropertyDescriptor::new("version", DataType::I64).version();
265
266 let orders_rel = RelationDescriptor::new("orders", "Order");
267
268 entity = entity
269 .property(id_prop.clone())
270 .property(name_prop.clone())
271 .property(version_prop.clone())
272 .relation(orders_rel.clone());
273
274 assert_eq!(entity.name, "User");
275 assert_eq!(entity.table_name, "users");
276 assert_eq!(entity.data_service, Some("auth_db".to_string()));
277 assert_eq!(entity.audit_mask_fields, vec!["password".to_string()]);
278 assert!(entity.audit_mask_fields_declared);
279 assert_eq!(entity.audit_value_max_len, Some(255));
280
281 assert_eq!(entity.property_by_name("name"), Some(&name_prop));
283 assert_eq!(entity.property_by_name("missing"), None);
284
285 assert_eq!(entity.relation_by_name("orders"), Some(&orders_rel));
286 assert_eq!(entity.relation_by_name("missing"), None);
287
288 assert_eq!(entity.id_property(), Some(&id_prop));
289 assert_eq!(entity.version_property(), Some(&version_prop));
290
291 let writable: Vec<_> = entity.writable_properties().collect();
292 assert_eq!(writable.len(), 2);
293 assert!(writable.contains(&&name_prop));
294 assert!(writable.contains(&&version_prop));
295 }
296}