Skip to main content

teaql_core/
meta.rs

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        // Lookups
277        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}