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_value_max_len: Option<usize>,
137}
138
139impl EntityDescriptor {
140 pub fn new(name: impl Into<String>) -> Self {
141 let name = name.into();
142 Self {
143 table_name: default_table_name(&name),
144 name,
145 data_service: None,
146 properties: Vec::new(),
147 relations: Vec::new(),
148 audit_mask_fields: Vec::new(),
149 audit_value_max_len: None,
150 }
151 }
152
153 pub fn table_name(mut self, table_name: impl Into<String>) -> Self {
154 self.table_name = table_name.into();
155 self
156 }
157
158 pub fn data_service(mut self, data_service: impl Into<String>) -> Self {
159 self.data_service = Some(data_service.into());
160 self
161 }
162
163 pub fn property(mut self, property: PropertyDescriptor) -> Self {
164 self.properties.push(property);
165 self
166 }
167
168 pub fn relation(mut self, relation: RelationDescriptor) -> Self {
169 self.relations.push(relation);
170 self
171 }
172
173 pub fn audit_mask_fields(mut self, fields: Vec<String>) -> Self {
174 self.audit_mask_fields = fields;
175 self
176 }
177
178 pub fn audit_value_max_len(mut self, max_len: Option<usize>) -> Self {
179 self.audit_value_max_len = max_len;
180 self
181 }
182
183 pub fn property_by_name(&self, name: &str) -> Option<&PropertyDescriptor> {
184 self.properties
185 .iter()
186 .find(|property| property.name == name)
187 }
188
189 pub fn relation_by_name(&self, name: &str) -> Option<&RelationDescriptor> {
190 self.relations.iter().find(|relation| relation.name == name)
191 }
192
193 pub fn id_property(&self) -> Option<&PropertyDescriptor> {
194 self.properties.iter().find(|property| property.is_id)
195 }
196
197 pub fn version_property(&self) -> Option<&PropertyDescriptor> {
198 self.properties.iter().find(|property| property.is_version)
199 }
200
201 pub fn writable_properties(&self) -> impl Iterator<Item = &PropertyDescriptor> {
202 self.properties.iter().filter(|property| !property.is_id)
203 }
204}
205
206#[cfg(test)]
207mod tests {
208 use super::*;
209
210 #[test]
211 fn test_property_descriptor_builder() {
212 let prop = PropertyDescriptor::new("username", DataType::Text)
213 .column_name("user_name")
214 .not_null()
215 .id()
216 .version()
217 .max_length(120)
218 .numeric_precision(19)
219 .numeric_scale(7);
220
221 assert_eq!(prop.name, "username");
222 assert_eq!(prop.column_name, "user_name");
223 assert_eq!(prop.data_type, DataType::Text);
224 assert!(!prop.nullable);
225 assert!(prop.is_id);
226 assert!(prop.is_version);
227 assert_eq!(prop.max_length, Some(120));
228 assert_eq!(prop.numeric_precision, Some(19));
229 assert_eq!(prop.numeric_scale, Some(7));
230 }
231
232 #[test]
233 fn test_relation_descriptor_builder() {
234 let rel = RelationDescriptor::new("orders", "Order")
235 .local_key("user_id")
236 .foreign_key("customer_id")
237 .many()
238 .detached()
239 .keep_missing();
240
241 assert_eq!(rel.name, "orders");
242 assert_eq!(rel.target_entity, "Order");
243 assert_eq!(rel.local_key, "user_id");
244 assert_eq!(rel.foreign_key, "customer_id");
245 assert!(rel.many);
246 assert!(!rel.attach);
247 assert!(!rel.delete_missing);
248 }
249
250 #[test]
251 fn test_entity_descriptor_builder_and_lookups() {
252 let mut entity = EntityDescriptor::new("User")
253 .table_name("users")
254 .data_service("auth_db")
255 .audit_mask_fields(vec!["password".to_string()])
256 .audit_value_max_len(Some(255));
257
258 let id_prop = PropertyDescriptor::new("id", DataType::I64).id();
259 let name_prop = PropertyDescriptor::new("name", DataType::Text);
260 let version_prop = PropertyDescriptor::new("version", DataType::I64).version();
261
262 let orders_rel = RelationDescriptor::new("orders", "Order");
263
264 entity = entity
265 .property(id_prop.clone())
266 .property(name_prop.clone())
267 .property(version_prop.clone())
268 .relation(orders_rel.clone());
269
270 assert_eq!(entity.name, "User");
271 assert_eq!(entity.table_name, "users");
272 assert_eq!(entity.data_service, Some("auth_db".to_string()));
273 assert_eq!(entity.audit_mask_fields, vec!["password".to_string()]);
274 assert_eq!(entity.audit_value_max_len, Some(255));
275
276 assert_eq!(entity.property_by_name("name"), Some(&name_prop));
278 assert_eq!(entity.property_by_name("missing"), None);
279
280 assert_eq!(entity.relation_by_name("orders"), Some(&orders_rel));
281 assert_eq!(entity.relation_by_name("missing"), None);
282
283 assert_eq!(entity.id_property(), Some(&id_prop));
284 assert_eq!(entity.version_property(), Some(&version_prop));
285
286 let writable: Vec<_> = entity.writable_properties().collect();
287 assert_eq!(writable.len(), 2);
288 assert!(writable.contains(&&name_prop));
289 assert!(writable.contains(&&version_prop));
290 }
291}