1use crate::db_set::DbSet;
18use crate::entity::{
19 EntityState, IEntitySnapshot, IEntityType, IFromRow, IGetKeyValues, INavigationSetter,
20};
21use crate::error::{EFError, EFResult};
22use crate::interceptor::InterceptorPipeline;
23use crate::metadata::EntityTypeMeta;
24use crate::migration::MigrationEngine;
25use crate::model_builder::ModelBuilder;
26use crate::provider::{DbValue, IDatabaseProvider};
27use crate::tracking::ChangeTracker;
28use crate::transaction::{DbTransaction, ITransaction};
29use std::any::{Any, TypeId};
30use std::collections::HashMap;
31use std::future::Future;
32use std::pin::Pin;
33use std::sync::Arc;
34
35use super::{DbContextOptions, ErasedSetOps, SetOps};
36
37pub struct DbContext {
44 pub(crate) sets: HashMap<TypeId, Box<dyn Any + Send + Sync>>,
45 pub(crate) savers: HashMap<TypeId, Box<dyn ErasedSetOps>>,
46 pub(crate) entity_metas: HashMap<TypeId, EntityTypeMeta>,
47 pub(crate) model_builder: ModelBuilder,
48 pub(crate) change_tracker: ChangeTracker,
49 pub(crate) provider: Arc<dyn IDatabaseProvider>,
50 pub(crate) interceptor_pipeline: InterceptorPipeline,
51 pub(crate) lazy_loading_enabled: bool,
52 pub(crate) ambient_transaction: Option<Box<dyn ITransaction>>,
57}
58
59impl DbContext {
60 pub fn from_options(options: &DbContextOptions) -> EFResult<Self> {
68 let provider = options.create_provider()?;
69 let built = options
70 .metadata_cache
71 .get_or_build(options.context_key.as_deref());
72 let ctx = Self {
73 sets: HashMap::new(),
74 savers: HashMap::new(),
75 entity_metas: built.entity_metas.clone(),
76 model_builder: ModelBuilder::from_built(&built),
77 change_tracker: ChangeTracker::new(),
78 provider,
79 interceptor_pipeline: InterceptorPipeline::new(options.interceptors.clone()),
80 lazy_loading_enabled: options.lazy_loading_enabled,
81 ambient_transaction: None,
82 };
83 Ok(ctx)
84 }
85
86 pub fn set<T>(&mut self) -> &mut DbSet<T>
87 where
88 T: IEntityType
89 + IEntitySnapshot
90 + IGetKeyValues
91 + IFromRow
92 + INavigationSetter
93 + Send
94 + Sync
95 + 'static,
96 {
97 let type_id = TypeId::of::<T>();
98 self.savers
99 .entry(type_id)
100 .or_insert_with(|| Box::new(SetOps::<T>::new()));
101 self.entity_metas
102 .entry(type_id)
103 .or_insert_with(T::entity_meta);
104 if !self.model_builder.has_entity(type_id) {
105 self.model_builder.register_entity_meta(T::entity_meta());
106 }
107 self.sets.entry(type_id).or_insert_with(|| {
108 let table_name = self
109 .model_builder
110 .build()
111 .into_iter()
112 .find(|m| m.type_id == type_id)
113 .map(|m| m.table_name.to_string())
114 .unwrap_or_else(|| T::entity_meta().table_name.to_string());
115 let mut db_set = DbSet::<T>::with_provider(table_name, Arc::clone(&self.provider));
116 if let Some(filter) = self.model_builder.get_query_filter(&type_id) {
117 db_set.set_query_filter(filter.clone());
118 }
119 db_set.set_filter_map(self.model_builder.filters_by_table());
120 db_set.set_lazy_loading_enabled(self.lazy_loading_enabled);
121 Box::new(db_set)
122 });
123 self.sets
124 .get_mut(&type_id)
125 .and_then(|b| b.downcast_mut::<DbSet<T>>())
126 .expect("DbSet type mismatch")
127 }
128
129 pub fn model(&mut self) -> &mut ModelBuilder {
131 &mut self.model_builder
132 }
133
134 pub fn model_builder(&self) -> &ModelBuilder {
136 &self.model_builder
137 }
138
139 pub fn entity_metas_contains<T: IEntityType>(&self) -> bool {
142 self.entity_metas.contains_key(&TypeId::of::<T>())
143 }
144
145 pub fn discover_entities(&mut self) -> EFResult<()> {
157 Ok(())
158 }
159
160 pub fn detect_changes(&mut self) {
162 let type_ids: Vec<TypeId> = self.sets.keys().copied().collect();
163 for type_id in type_ids {
164 let Some(set) = self.sets.get_mut(&type_id) else {
165 continue;
166 };
167 let Some(saver) = self.savers.get(&type_id) else {
168 continue;
169 };
170 saver.detect_changes(set.as_mut(), &mut self.change_tracker);
171 }
172 }
173
174 pub async fn ensure_created(&self) -> EFResult<()> {
181 let mut metas: Vec<EntityTypeMeta> = self.model_builder.build();
182 if metas.is_empty() {
183 metas = self.entity_metas.values().cloned().collect();
184 }
185 if metas.is_empty() {
186 return Err(EFError::configuration(
187 "No entity types registered. Call ctx.discover_entities() or ctx.set::<T>() before ensure_created().",
188 ));
189 }
190 let dialect = self.provider.migration_dialect();
191 MigrationEngine::new(dialect)
192 .ensure_created(&*self.provider, &metas)
193 .await?;
194
195 for meta in &metas {
196 let rows = self.model_builder.seed_rows_for(&meta.type_id);
197 if !rows.is_empty() {
198 MigrationEngine::new(dialect)
199 .apply_seed_data(&*self.provider, meta, rows)
200 .await?;
201 }
202 }
203 Ok(())
204 }
205
206 pub async fn ensure_deleted(&self) -> EFResult<()> {
208 let mut metas: Vec<EntityTypeMeta> = self.model_builder.build();
209 if metas.is_empty() {
210 metas = self.entity_metas.values().cloned().collect();
211 }
212 if metas.is_empty() {
213 return Err(EFError::configuration(
214 "No entity types registered. Call ctx.discover_entities() or ctx.set::<T>() before ensure_deleted().",
215 ));
216 }
217 let dialect = self.provider.migration_dialect();
218 MigrationEngine::new(dialect)
219 .ensure_deleted(&*self.provider, &metas)
220 .await
221 }
222}
223
224impl DbContext {
229 pub fn provider(&self) -> &dyn IDatabaseProvider {
231 &*self.provider
232 }
233
234 pub fn change_tracker(&self) -> &ChangeTracker {
236 &self.change_tracker
237 }
238
239 pub fn change_tracker_mut(&mut self) -> &mut ChangeTracker {
241 &mut self.change_tracker
242 }
243
244 pub async fn sql_query<T: IFromRow + IEntityType>(
257 &self,
258 sql: &str,
259 params: &[DbValue],
260 ) -> EFResult<Vec<T>> {
261 let mut conn = self.provider.get_connection().await?;
262 let rows = conn.query(sql, params).await?;
263 crate::entity::materialize_entities(&rows)
264 }
265
266 pub fn transaction_mut(&mut self) -> Option<&mut Box<dyn ITransaction>> {
274 self.ambient_transaction.as_mut()
275 }
276
277 pub async fn begin_transaction(&mut self) -> EFResult<Box<dyn ITransaction>> {
290 let mut conn = self.provider.get_connection().await?;
291 conn.begin_transaction().await?;
292 Ok(Box::new(DbTransaction::new(conn)))
293 }
294
295 pub async fn use_transaction<F, R>(&mut self, f: F) -> EFResult<R>
316 where
317 for<'a> F: FnOnce(&'a mut Self) -> Pin<Box<dyn Future<Output = EFResult<R>> + Send + 'a>>,
318 R: Send + 'static,
319 {
320 if self.ambient_transaction.is_some() {
321 return Err(EFError::transaction(
322 "ambient transaction already active; nested use_transaction is not supported",
323 ));
324 }
325 let mut conn = self.provider.get_connection().await?;
326 conn.begin_transaction().await?;
327 self.ambient_transaction = Some(Box::new(DbTransaction::new(conn)));
328 let result = f(self).await;
329 let txn = self.ambient_transaction.take().ok_or_else(|| {
330 EFError::transaction("ambient_transaction was consumed during use_transaction closure")
331 })?;
332 match result {
333 Ok(r) => {
334 txn.commit().await?;
335 Ok(r)
336 }
337 Err(e) => {
338 let _ = txn.rollback().await;
339 Err(e)
340 }
341 }
342 }
343}
344
345impl DbContext {
350 fn ensure_registered<T>(&mut self) -> (TypeId, String)
353 where
354 T: IEntityType
355 + IEntitySnapshot
356 + IGetKeyValues
357 + IFromRow
358 + INavigationSetter
359 + Send
360 + Sync
361 + 'static,
362 {
363 let type_id = TypeId::of::<T>();
364 self.savers
365 .entry(type_id)
366 .or_insert_with(|| Box::new(SetOps::<T>::new()));
367 self.entity_metas
368 .entry(type_id)
369 .or_insert_with(T::entity_meta);
370 if !self.model_builder.has_entity(type_id) {
371 self.model_builder.register_entity_meta(T::entity_meta());
372 }
373 let type_name = self.entity_metas[&type_id].type_name.to_string();
374 (type_id, type_name)
375 }
376
377 pub fn add<T>(&mut self, entity: T)
380 where
381 T: IEntityType
382 + IEntitySnapshot
383 + IGetKeyValues
384 + IFromRow
385 + INavigationSetter
386 + Send
387 + Sync
388 + 'static,
389 {
390 let (type_id, type_name) = self.ensure_registered::<T>();
391 let entry_id =
392 self.change_tracker
393 .track(type_id, &type_name, EntityState::Added, None, false);
394 self.set::<T>().push_entry(entity, entry_id);
395 }
396
397 pub fn attach<T>(&mut self, entity: T)
400 where
401 T: IEntityType
402 + IEntitySnapshot
403 + IGetKeyValues
404 + IFromRow
405 + INavigationSetter
406 + Send
407 + Sync
408 + 'static,
409 {
410 let (type_id, type_name) = self.ensure_registered::<T>();
411 let snapshot = entity.snapshot();
412 let entry_id = self.change_tracker.track(
413 type_id,
414 &type_name,
415 EntityState::Unchanged,
416 Some(snapshot),
417 false,
418 );
419 self.set::<T>().push_entry(entity, entry_id);
420 }
421
422 pub fn update<T>(&mut self, entity: T)
425 where
426 T: IEntityType
427 + IEntitySnapshot
428 + IGetKeyValues
429 + IFromRow
430 + INavigationSetter
431 + Send
432 + Sync
433 + 'static,
434 {
435 let (type_id, type_name) = self.ensure_registered::<T>();
436 let entry_id =
437 self.change_tracker
438 .track(type_id, &type_name, EntityState::Modified, None, false);
439 self.set::<T>().push_entry(entity, entry_id);
440 }
441
442 pub fn upsert<T>(&mut self, entity: T)
444 where
445 T: IEntityType
446 + IEntitySnapshot
447 + IGetKeyValues
448 + IFromRow
449 + INavigationSetter
450 + Send
451 + Sync
452 + 'static,
453 {
454 let (type_id, type_name) = self.ensure_registered::<T>();
455 let entry_id =
456 self.change_tracker
457 .track(type_id, &type_name, EntityState::Added, None, true);
458 self.set::<T>().push_entry(entity, entry_id);
459 }
460
461 pub fn remove_at<T>(&mut self, index: usize) -> EFResult<()>
463 where
464 T: IEntityType
465 + IEntitySnapshot
466 + IGetKeyValues
467 + IFromRow
468 + INavigationSetter
469 + Send
470 + Sync
471 + 'static,
472 {
473 let entry_id = self
474 .set::<T>()
475 .entry_id_at(index)
476 .ok_or_else(|| EFError::not_found("Entity not found at the given index".to_string()))?;
477 self.change_tracker
478 .set_state(entry_id, EntityState::Deleted);
479 Ok(())
480 }
481
482 pub fn remove_all<T>(&mut self)
484 where
485 T: IEntityType
486 + IEntitySnapshot
487 + IGetKeyValues
488 + IFromRow
489 + INavigationSetter
490 + Send
491 + Sync
492 + 'static,
493 {
494 let entry_ids: Vec<u64> = self.set::<T>().entries.iter().map(|e| e.entry_id).collect();
495 for entry_id in entry_ids {
496 self.change_tracker
497 .set_state(entry_id, EntityState::Deleted);
498 }
499 }
500
501 pub async fn load_all<T>(&mut self) -> EFResult<()>
504 where
505 T: IEntityType
506 + IEntitySnapshot
507 + IGetKeyValues
508 + IFromRow
509 + INavigationSetter
510 + crate::entity::ILazyInit
511 + Send
512 + Sync
513 + 'static,
514 {
515 let type_id = TypeId::of::<T>();
516 let items = self.set::<T>().query().to_list().await?;
517 self.set::<T>().clear_entries();
518 self.change_tracker.clear_by_type(type_id);
519 for item in items {
520 self.attach::<T>(item);
521 }
522 Ok(())
523 }
524}