Skip to main content

modo_db/
record.rs

1use sea_orm::{
2    ActiveModelBehavior, ActiveModelTrait, ConnectionTrait, EntityTrait, FromQueryResult,
3};
4
5use crate::query::{EntityDeleteMany, EntityQuery, EntityUpdateMany};
6
7/// Core trait for domain model types backed by a database table.
8///
9/// The `#[modo_db::entity]` macro generates an implementation of this trait
10/// for each entity struct. It provides CRUD operations and query builders.
11///
12/// Most methods are macro-generated (not default impls) because they need
13/// either PK-specific signatures or concrete type context for hook resolution.
14#[allow(clippy::wrong_self_convention)]
15pub trait Record: Sized + Send + Sync + 'static {
16    type Entity: EntityTrait;
17    type ActiveModel: ActiveModelTrait<Entity = Self::Entity> + ActiveModelBehavior + Send + 'static;
18
19    // --- Required methods (macro generates) ---
20
21    /// Convert a SeaORM model to the domain type.
22    fn from_model(model: <Self::Entity as EntityTrait>::Model) -> Self;
23
24    /// Convert to an active model with ALL fields set.
25    fn into_active_model_full(&self) -> Self::ActiveModel;
26
27    /// Convert to an active model with only PK fields set (rest NotSet).
28    fn into_active_model(&self) -> Self::ActiveModel;
29
30    /// Fill auto-generated fields (ID, timestamps) on an active model.
31    fn apply_auto_fields(am: &mut Self::ActiveModel, is_insert: bool);
32
33    // --- Query builders (default impls — no hooks needed) ---
34
35    /// Fetch all records.
36    fn find_all(
37        db: &impl ConnectionTrait,
38    ) -> impl std::future::Future<Output = Result<Vec<Self>, modo::Error>> + Send
39    where
40        <Self::Entity as EntityTrait>::Model: FromQueryResult + Send + Sync,
41        Self: From<<Self::Entity as EntityTrait>::Model>,
42    {
43        async {
44            use sea_orm::EntityTrait as _;
45            let models = Self::Entity::find()
46                .all(db)
47                .await
48                .map_err(crate::error::db_err_to_error)?;
49            Ok(models.into_iter().map(Self::from_model).collect())
50        }
51    }
52
53    /// Start a chainable query builder.
54    fn query() -> EntityQuery<Self, Self::Entity>
55    where
56        <Self::Entity as EntityTrait>::Model: FromQueryResult + Send + Sync,
57        Self: From<<Self::Entity as EntityTrait>::Model>,
58    {
59        use sea_orm::EntityTrait as _;
60        EntityQuery::new(Self::Entity::find())
61    }
62
63    /// Start a bulk UPDATE builder.
64    fn update_many() -> EntityUpdateMany<Self::Entity> {
65        use sea_orm::EntityTrait as _;
66        EntityUpdateMany::new(Self::Entity::update_many())
67    }
68
69    /// Start a bulk DELETE builder.
70    fn delete_many() -> EntityDeleteMany<Self::Entity> {
71        use sea_orm::EntityTrait as _;
72        EntityDeleteMany::new(Self::Entity::delete_many())
73    }
74}