Skip to main content

rust_ef/
entity.rs

1//! Entity type trait and state definitions.
2
3use crate::error::EFResult;
4use crate::metadata::EntityTypeMeta;
5use crate::provider::DbValue;
6use std::collections::HashMap;
7
8// ---------------------------------------------------------------------------
9// Entity materialization ?converts raw rows into entity instances
10// ---------------------------------------------------------------------------
11
12/// Materializes entities from raw database row data using the `IFromRow` trait.
13pub fn materialize_entities<T: IEntityType + IFromRow>(rows: &[Vec<DbValue>]) -> EFResult<Vec<T>> {
14    let mut entities = Vec::with_capacity(rows.len());
15    for row in rows {
16        let entity = T::from_row(row)?;
17        entities.push(entity);
18    }
19    Ok(entities)
20}
21
22/// Represents the state of an entity in the change tracker.
23#[derive(Debug, Clone, Copy, PartialEq, Eq)]
24pub enum EntityState {
25    Detached,
26    Added,
27    Unchanged,
28    Modified,
29    Deleted,
30}
31
32/// The core trait that every entity type must implement.
33pub trait IEntityType: Send + Sync + 'static {
34    fn entity_meta() -> EntityTypeMeta
35    where
36        Self: Sized;
37
38    fn entity_meta_instance(&self) -> EntityTypeMeta
39    where
40        Self: Sized,
41    {
42        Self::entity_meta()
43    }
44}
45
46/// Trait for materializing an entity from a database row.
47///
48/// Used by [`materialize_entities`] to deserialize query results.
49/// Auto-generated by `#[derive(EntityType)]`.
50pub trait IFromRow: IEntityType + Sized {
51    fn from_row(values: &[DbValue]) -> EFResult<Self>;
52}
53
54/// Extracts primary key values from an entity for SaveChanges WHERE clauses.
55///
56/// Auto-generated by `#[derive(EntityType)]`.
57pub trait IGetKeyValues: IEntityType {
58    fn key_values(&self) -> HashMap<String, DbValue>;
59}
60
61/// Extracts all scalar property values from an entity for INSERT/UPDATE.
62///
63/// Auto-generated by `#[derive(EntityType)]`.
64pub trait IEntitySnapshot: IEntityType {
65    fn snapshot(&self) -> HashMap<String, DbValue>;
66}
67
68/// Attaches lazy-loading contexts to navigation properties.
69///
70/// Auto-generated by `#[derive(EntityType)]`. Called by `QueryBuilder::to_list()`
71/// when lazy loading is enabled on the `DbContext`. For each navigation field,
72/// the macro implementation constructs a `LazyContextImpl` and calls
73/// `set_lazy_context` on the corresponding container.
74///
75/// Entities without navigation properties get a no-op implementation.
76pub trait ILazyInit: IEntityType {
77    /// Attaches lazy contexts to all navigation properties on this entity.
78    ///
79    /// `depth` is the current recursion depth (0 for top-level entities
80    /// materialized by `to_list`). Each lazy `load()` call increments the
81    /// depth when attaching contexts to child entities.
82    fn attach_lazy_contexts(
83        &mut self,
84        provider: std::sync::Arc<dyn crate::provider::IDatabaseProvider>,
85        filter_map: Option<
86            std::sync::Arc<std::collections::HashMap<String, crate::query::CompiledFilter>>,
87        >,
88        depth: usize,
89    );
90}
91
92/// Applies eagerly-loaded navigation data to an entity.
93///
94/// Auto-generated by `#[derive(EntityType)]` for types with navigation properties.
95#[async_trait::async_trait]
96pub trait INavigationSetter: IEntityType {
97    fn apply_has_many(&mut self, field: &str, rows: &[Vec<DbValue>]) -> EFResult<()> {
98        let _ = (field, rows);
99        Ok(())
100    }
101
102    fn apply_reference(&mut self, field: &str, row: &[DbValue]) -> EFResult<()> {
103        let _ = (field, row);
104        Ok(())
105    }
106
107    /// Loads nested includes after the parent navigation was populated.
108    ///
109    /// `filter_map` carries per-table query filters (e.g. tenant isolation)
110    /// so that nested navigation loading respects the same filters as
111    /// top-level loading.
112    async fn load_nested_includes(
113        &mut self,
114        parent_navigation: &str,
115        nested: &[crate::query::IncludePath],
116        provider: &dyn crate::provider::IDatabaseProvider,
117        filter_map: Option<&std::collections::HashMap<String, crate::query::CompiledFilter>>,
118    ) -> EFResult<()> {
119        let _ = (parent_navigation, nested, provider, filter_map);
120        Ok(())
121    }
122}