Skip to main content

miryad_core/migration/
mod.rs

1mod m20260822_000001_create_api_tokens;
2mod m20260822_000002_create_users_groups;
3mod m20260822_000003_seed_admin_group;
4
5use sea_orm::sea_query::IntoIden;
6
7pub struct Migrator;
8
9impl sea_orm_migration::MigratorTrait for Migrator {
10    fn migrations() -> Vec<Box<dyn sea_orm_migration::MigrationTrait>> {
11        vec![
12            Box::new(m20260822_000001_create_api_tokens::Migration),
13            Box::new(m20260822_000002_create_users_groups::Migration),
14            Box::new(m20260822_000003_seed_admin_group::Migration),
15        ]
16    }
17
18    /// Table de suivi dédiée, distincte du défaut `seaql_migrations` — une app consommatrice
19    /// compose ce `Migrator` avec son propre `MigratorTrait` métier sur la même connexion
20    /// (pattern documenté). Sans ça, `sea_orm_migration::Migrator::up()` valide que *toute*
21    /// entrée de la table de suivi est connue du migrateur en cours d'exécution : le second
22    /// migrateur à tourner échoue sur les entrées laissées par le premier.
23    fn migration_table_name() -> sea_orm::DynIden {
24        sea_orm::sea_query::Alias::new("seaql_migrations_miryad_core").into_iden()
25    }
26}
27
28#[cfg(test)]
29mod tests {
30    use super::*;
31    use sea_orm::Database;
32    use sea_orm_migration::MigratorTrait as _;
33    use sea_orm_migration::prelude::*;
34
35    /// Migrateur indépendant représentant l'app consommatrice — utilise le
36    /// `migration_table_name()` par défaut (`seaql_migrations`), comme documenté pour le pattern
37    /// "composer deux `MigratorTrait` sur la même connexion".
38    struct AppMigrator;
39
40    impl MigratorTrait for AppMigrator {
41        fn migrations() -> Vec<Box<dyn MigrationTrait>> {
42            vec![Box::new(AppMigration)]
43        }
44    }
45
46    #[derive(DeriveMigrationName)]
47    struct AppMigration;
48
49    #[async_trait::async_trait]
50    impl MigrationTrait for AppMigration {
51        async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
52            manager
53                .create_table(
54                    Table::create()
55                        .table(Alias::new("app_widgets"))
56                        .col(
57                            ColumnDef::new(Alias::new("id"))
58                                .integer()
59                                .not_null()
60                                .primary_key(),
61                        )
62                        .to_owned(),
63                )
64                .await
65        }
66
67        async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
68            manager
69                .drop_table(Table::drop().table(Alias::new("app_widgets")).to_owned())
70                .await
71        }
72    }
73
74    #[tokio::test]
75    async fn composes_with_an_independent_migrator_sharing_the_default_table_name() {
76        let db = Database::connect("sqlite::memory:")
77            .await
78            .expect("in-memory sqlite connects");
79
80        Migrator::up(&db, None)
81            .await
82            .expect("miryad-core migrations apply cleanly");
83        AppMigrator::up(&db, None)
84            .await
85            .expect("app migrator composes without colliding on the tracking table");
86
87        // Régression : réappliquer le migrateur miryad-core après que l'app ait tourné son propre
88        // migrateur (table de suivi par défaut) ne doit pas non plus échouer.
89        Migrator::up(&db, None)
90            .await
91            .expect("miryad-core migrator remains idempotent alongside an app migrator");
92    }
93}