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