1use crate::entity::{IEntitySnapshot, IEntityType};
9use crate::metadata::EntityTypeMeta;
10use crate::provider::DbValue;
11use crate::query::{BoolExpr, CompiledFilter};
12use std::any::TypeId;
13use std::collections::HashMap;
14use std::marker::PhantomData;
15use std::sync::Arc;
16use std::sync::OnceLock;
17
18#[derive(Debug, Clone, Default)]
23pub(crate) struct EntityConfig {
24 pub(crate) table_name: Option<String>,
25 pub(crate) primary_key_fields: Option<Vec<String>>,
26 pub(crate) property_overrides: HashMap<String, PropertyConfigOverride>,
27 pub(crate) query_filter: Option<BoolExpr>,
28 pub(crate) seed_rows: Vec<HashMap<String, DbValue>>,
29}
30
31#[derive(Debug, Clone, Default)]
32pub(crate) struct PropertyConfigOverride {
33 pub(crate) column_name: Option<String>,
34 pub(crate) is_required: Option<bool>,
35 pub(crate) max_length: Option<usize>,
36 pub(crate) is_unique: Option<bool>,
37 pub(crate) has_index: Option<bool>,
38}
39
40pub struct ModelBuilder {
46 entity_metas: Vec<EntityTypeMeta>,
47 configs: HashMap<TypeId, EntityConfig>,
48 build_cache: OnceLock<Vec<EntityTypeMeta>>,
50 filter_cache: OnceLock<Arc<HashMap<String, CompiledFilter>>>,
53}
54
55impl ModelBuilder {
56 pub fn new() -> Self {
57 Self {
58 entity_metas: Vec::new(),
59 configs: HashMap::new(),
60 build_cache: OnceLock::new(),
61 filter_cache: OnceLock::new(),
62 }
63 }
64
65 pub(crate) fn from_built(built: &crate::metadata_cache::BuiltMetadata) -> Self {
75 Self {
76 entity_metas: built.model_metas.clone(),
77 configs: built.configs.clone(),
78 build_cache: OnceLock::new(),
79 filter_cache: OnceLock::new(),
80 }
81 }
82
83 pub(crate) fn configs(&self) -> &HashMap<TypeId, EntityConfig> {
87 &self.configs
88 }
89
90 pub(crate) fn entity_metas_vec(&self) -> &[EntityTypeMeta] {
93 &self.entity_metas
94 }
95
96 fn invalidate_cache(&mut self) {
101 self.build_cache.take();
102 self.filter_cache.take();
103 }
104
105 #[doc(hidden)]
107 pub fn build_cache_populated(&self) -> bool {
108 self.build_cache.get().is_some()
109 }
110
111 #[doc(hidden)]
114 pub fn filter_cache_populated(&self) -> bool {
115 self.filter_cache.get().is_some()
116 }
117
118 pub fn entity<T: IEntityType>(&mut self) -> EntityTypeBuilder<'_, T> {
119 let meta = T::entity_meta();
120 let type_id = meta.type_id;
121 if !self.entity_metas.iter().any(|m| m.type_id == type_id) {
122 self.entity_metas.push(meta);
123 self.invalidate_cache();
124 }
125 self.configs.entry(type_id).or_default();
126 EntityTypeBuilder::new(self, type_id)
127 }
128
129 pub fn apply_configuration<C, T>(&mut self) -> &mut Self
130 where
131 C: IEntityTypeConfiguration<T> + Default + Send + Sync + 'static,
132 T: IEntityType,
133 {
134 let meta = T::entity_meta();
135 let type_id = meta.type_id;
136 if !self.entity_metas.iter().any(|m| m.type_id == type_id) {
137 self.entity_metas.push(meta);
138 self.invalidate_cache();
139 }
140
141 let config = C::default();
142 let mut builder = EntityTypeBuilder::new(self, type_id);
143 config.configure(&mut builder);
144
145 self
146 }
147
148 pub fn build(&self) -> Vec<EntityTypeMeta> {
149 self.build_cache
150 .get_or_init(|| {
151 self.entity_metas
152 .iter()
153 .map(|meta| self.apply_config_to_meta(meta))
154 .collect()
155 })
156 .clone()
157 }
158
159 fn apply_config_to_meta(&self, meta: &EntityTypeMeta) -> EntityTypeMeta {
160 let config = match self.configs.get(&meta.type_id) {
161 Some(c) => c,
162 None => return meta.clone(),
163 };
164
165 let mut result = meta.clone();
166 if let Some(ref table) = config.table_name {
167 result.table_name = std::borrow::Cow::Owned(table.clone());
168 }
169
170 if let Some(ref pk_fields) = config.primary_key_fields {
171 for prop in &mut result.properties {
172 prop.is_primary_key = pk_fields.iter().any(|f| f == prop.field_name.as_ref());
173 }
174 }
175
176 for prop in &mut result.properties {
177 if let Some(override_cfg) = config.property_overrides.get(prop.field_name.as_ref()) {
178 if let Some(ref col) = override_cfg.column_name {
179 prop.column_name = std::borrow::Cow::Owned(col.clone());
180 }
181 if let Some(required) = override_cfg.is_required {
182 prop.is_required = required;
183 }
184 if let Some(max_len) = override_cfg.max_length {
185 prop.max_length = Some(max_len);
186 }
187 if let Some(unique) = override_cfg.is_unique {
188 prop.is_unique = unique;
189 }
190 if let Some(index) = override_cfg.has_index {
191 prop.has_index = index;
192 }
193 }
194 }
195
196 result
197 }
198
199 pub fn entity_metas_mut(&mut self) -> &mut Vec<EntityTypeMeta> {
208 &mut self.entity_metas
211 }
212
213 pub fn find_entity<T: IEntityType>(&self) -> Option<&EntityTypeMeta> {
214 let type_id = TypeId::of::<T>();
215 self.entity_metas.iter().find(|m| m.type_id == type_id)
216 }
217
218 pub fn has_entity(&self, type_id: TypeId) -> bool {
221 self.entity_metas.iter().any(|m| m.type_id == type_id)
222 }
223
224 pub fn register_entity_meta(&mut self, meta: EntityTypeMeta) {
232 let type_id = meta.type_id;
233 if !self.entity_metas.iter().any(|m| m.type_id == type_id) {
234 self.entity_metas.push(meta);
235 self.invalidate_cache();
236 }
237 self.configs.entry(type_id).or_default();
238 }
239
240 pub fn has_query_filter<T: IEntityType>(&mut self, filter: BoolExpr) -> &mut Self {
244 let type_id = TypeId::of::<T>();
245 let config = self.configs.entry(type_id).or_default();
246 config.query_filter = Some(filter);
247
248 let meta = T::entity_meta();
249 if !self.entity_metas.iter().any(|m| m.type_id == type_id) {
250 self.entity_metas.push(meta);
251 }
252
253 self.invalidate_cache();
254 self
255 }
256
257 pub fn get_query_filter(&self, type_id: &TypeId) -> Option<&BoolExpr> {
258 self.configs
259 .get(type_id)
260 .and_then(|c| c.query_filter.as_ref())
261 }
262
263 pub fn filters_by_table(&self) -> Arc<HashMap<String, CompiledFilter>> {
276 self.filter_cache
277 .get_or_init(|| {
278 let mut map = HashMap::new();
279 for meta in &self.entity_metas {
280 if let Some(config) = self.configs.get(&meta.type_id) {
281 if let Some(filter) = &config.query_filter {
282 map.insert(
283 meta.table_name.to_string(),
284 CompiledFilter::new(filter.clone()),
285 );
286 }
287 }
288 }
289 Arc::new(map)
290 })
291 .clone()
292 }
293
294 pub fn seed_rows_for(&self, type_id: &TypeId) -> &[HashMap<String, DbValue>] {
296 self.configs
297 .get(type_id)
298 .map(|c| c.seed_rows.as_slice())
299 .unwrap_or(&[])
300 }
301}
302
303impl Default for ModelBuilder {
304 fn default() -> Self {
305 Self::new()
306 }
307}
308
309pub struct EntityTypeBuilder<'a, T> {
314 model: &'a mut ModelBuilder,
315 type_id: TypeId,
316 _phantom: PhantomData<T>,
317}
318
319impl<'a, T> EntityTypeBuilder<'a, T> {
320 pub fn new(model: &'a mut ModelBuilder, type_id: TypeId) -> Self {
321 Self {
322 model,
323 type_id,
324 _phantom: PhantomData,
325 }
326 }
327
328 pub fn to_table(&mut self, name: &str) -> &mut Self {
329 if let Some(config) = self.model.configs.get_mut(&self.type_id) {
330 config.table_name = Some(name.to_string());
331 }
332 self.model.invalidate_cache();
333 self
334 }
335
336 pub fn property_named<'b>(&'b mut self, field_name: &'static str) -> PropertyBuilder<'b, T> {
337 PropertyBuilder {
338 model: self.model,
339 type_id: self.type_id,
340 field_name,
341 _entity: PhantomData,
342 _value: PhantomData,
343 }
344 }
345
346 pub fn has_key_named(&mut self, field_name: &str) -> &mut Self {
347 if let Some(config) = self.model.configs.get_mut(&self.type_id) {
348 config.primary_key_fields = Some(vec![field_name.to_string()]);
349 }
350 self.model.invalidate_cache();
351 self
352 }
353
354 pub fn has_keys(&mut self, field_names: &[&str]) -> &mut Self {
355 if let Some(config) = self.model.configs.get_mut(&self.type_id) {
356 config.primary_key_fields = Some(field_names.iter().map(|s| s.to_string()).collect());
357 }
358 self.model.invalidate_cache();
359 self
360 }
361
362 #[doc(hidden)]
366 pub fn has_key(&mut self, columns: &'static [&'static str]) -> &mut Self {
367 if let Some(config) = self.model.configs.get_mut(&self.type_id) {
368 config.primary_key_fields = Some(columns.iter().map(|s| s.to_string()).collect());
369 }
370 self.model.invalidate_cache();
371 self
372 }
373
374 #[doc(hidden)]
380 pub fn has_index(&mut self, columns: &'static [&'static str]) -> &mut Self {
381 if let Some(config) = self.model.configs.get_mut(&self.type_id) {
382 for col in columns {
384 let override_cfg = config
385 .property_overrides
386 .entry(col.to_string())
387 .or_default();
388 override_cfg.has_index = Some(true);
389 }
390 }
391 self.model.invalidate_cache();
392 self
393 }
394
395 pub fn has_data(&mut self, data: &[T]) -> &mut Self
397 where
398 T: IEntitySnapshot,
399 {
400 if let Some(config) = self.model.configs.get_mut(&self.type_id) {
401 config.seed_rows = data.iter().map(|e| e.snapshot()).collect();
402 }
403 self.model.invalidate_cache();
404 self
405 }
406}
407
408pub struct PropertyBuilder<'a, T, V = ()> {
413 model: &'a mut ModelBuilder,
414 type_id: TypeId,
415 field_name: &'static str,
416 _entity: PhantomData<T>,
417 _value: PhantomData<V>,
418}
419
420impl<'a, T, V> PropertyBuilder<'a, T, V> {
421 fn override_entry(&mut self) -> &mut PropertyConfigOverride {
422 self.model.invalidate_cache();
425 self.model
426 .configs
427 .entry(self.type_id)
428 .or_default()
429 .property_overrides
430 .entry(self.field_name.to_string())
431 .or_default()
432 }
433
434 pub fn is_required(mut self) -> Self {
435 self.override_entry().is_required = Some(true);
436 self
437 }
438
439 pub fn has_max_length(mut self, n: usize) -> Self {
440 self.override_entry().max_length = Some(n);
441 self
442 }
443
444 pub fn has_column_name(mut self, name: &'static str) -> Self {
445 self.override_entry().column_name = Some(name.to_string());
446 self
447 }
448
449 pub fn is_unique(mut self) -> Self {
450 self.override_entry().is_unique = Some(true);
451 self
452 }
453
454 pub fn has_index(mut self) -> Self {
455 self.override_entry().has_index = Some(true);
456 self
457 }
458}
459
460pub trait IEntityTypeConfiguration<T: IEntityType> {
465 fn configure(&self, entity: &mut EntityTypeBuilder<'_, T>);
466}