Skip to main content

sea_orm_migration/migrator/
with_self.rs

1use super::{Migration, MigrationStatus, exec::*};
2use crate::{IntoSchemaManagerConnection, MigrationTrait, SchemaManager, seaql_migrations};
3use sea_orm::sea_query::IntoIden;
4use sea_orm::{ConnectionTrait, DbErr, DynIden};
5
6use tracing::info;
7
8/// Performing migrations on a database
9#[async_trait::async_trait]
10pub trait MigratorTraitSelf: Sized + Send + Sync {
11    /// Vector of migrations in time sequence
12    fn migrations(&self) -> Vec<Box<dyn MigrationTrait>>;
13
14    /// Name of the migration table, it is `seaql_migrations` by default
15    fn migration_table_name(&self) -> DynIden {
16        seaql_migrations::Entity.into_iden()
17    }
18
19    /// Get list of migrations wrapped in `Migration` struct
20    fn get_migration_files(&self) -> Vec<Migration> {
21        self.migrations()
22            .into_iter()
23            .map(|migration| Migration {
24                migration,
25                status: MigrationStatus::Pending,
26            })
27            .collect()
28    }
29
30    /// Get list of applied migrations from database
31    async fn get_migration_models<C>(&self, db: &C) -> Result<Vec<seaql_migrations::Model>, DbErr>
32    where
33        C: ConnectionTrait,
34    {
35        self.install(db).await?;
36        get_migration_models(db, self.migration_table_name()).await
37    }
38
39    /// Get list of migrations with status
40    async fn get_migration_with_status<C>(&self, db: &C) -> Result<Vec<Migration>, DbErr>
41    where
42        C: ConnectionTrait,
43    {
44        self.install(db).await?;
45        get_migration_with_status(
46            self.get_migration_files(),
47            self.get_migration_models(db).await?,
48        )
49    }
50
51    /// Get list of pending migrations
52    async fn get_pending_migrations<C>(&self, db: &C) -> Result<Vec<Migration>, DbErr>
53    where
54        C: ConnectionTrait,
55    {
56        self.install(db).await?;
57        Ok(self
58            .get_migration_with_status(db)
59            .await?
60            .into_iter()
61            .filter(|file| file.status == MigrationStatus::Pending)
62            .collect())
63    }
64
65    /// Get list of applied migrations
66    async fn get_applied_migrations<C>(&self, db: &C) -> Result<Vec<Migration>, DbErr>
67    where
68        C: ConnectionTrait,
69    {
70        self.install(db).await?;
71        Ok(self
72            .get_migration_with_status(db)
73            .await?
74            .into_iter()
75            .filter(|file| file.status == MigrationStatus::Applied)
76            .collect())
77    }
78
79    /// Create migration table `seaql_migrations` in the database
80    async fn install<C>(&self, db: &C) -> Result<(), DbErr>
81    where
82        C: ConnectionTrait,
83    {
84        install(db, self.migration_table_name()).await
85    }
86
87    /// Check the status of all migrations
88    async fn status<C>(&self, db: &C) -> Result<(), DbErr>
89    where
90        C: ConnectionTrait,
91    {
92        self.install(db).await?;
93
94        info!("Checking migration status");
95
96        for Migration { migration, status } in self.get_migration_with_status(db).await? {
97            info!("Migration '{}'... {}", migration.name(), status);
98        }
99
100        Ok(())
101    }
102
103    /// Drop all tables from the database, then reapply all migrations
104    async fn fresh<'c, C>(&self, db: C) -> Result<(), DbErr>
105    where
106        C: IntoSchemaManagerConnection<'c>,
107    {
108        let db = db.into_database_executor();
109        let manager = SchemaManager::new(db);
110        exec_fresh(self, &manager).await
111    }
112
113    /// Rollback all applied migrations, then reapply all migrations
114    async fn refresh<'c, C>(&self, db: C) -> Result<(), DbErr>
115    where
116        C: IntoSchemaManagerConnection<'c>,
117    {
118        let db = db.into_database_executor();
119        let manager = SchemaManager::new(db);
120        exec_down(self, &manager, None).await?;
121        exec_up(self, &manager, None).await
122    }
123
124    /// Rollback all applied migrations
125    async fn reset<'c, C>(&self, db: C) -> Result<(), DbErr>
126    where
127        C: IntoSchemaManagerConnection<'c>,
128    {
129        let db = db.into_database_executor();
130        let manager = SchemaManager::new(db);
131        exec_down(self, &manager, None).await?;
132        uninstall(&manager, self.migration_table_name()).await
133    }
134
135    /// Uninstall migration tracking table only (non-destructive)
136    /// This will drop the `seaql_migrations` table but won't rollback other schema changes.
137    async fn uninstall<'c, C>(&self, db: C) -> Result<(), DbErr>
138    where
139        C: IntoSchemaManagerConnection<'c>,
140    {
141        let db = db.into_database_executor();
142        let manager = SchemaManager::new(db);
143        uninstall(&manager, self.migration_table_name()).await
144    }
145
146    /// Apply pending migrations
147    async fn up<'c, C>(&self, db: C, steps: Option<u32>) -> Result<(), DbErr>
148    where
149        C: IntoSchemaManagerConnection<'c>,
150    {
151        let db = db.into_database_executor();
152        let manager = SchemaManager::new(db);
153        exec_up(self, &manager, steps).await
154    }
155
156    /// Rollback applied migrations
157    async fn down<'c, C>(&self, db: C, steps: Option<u32>) -> Result<(), DbErr>
158    where
159        C: IntoSchemaManagerConnection<'c>,
160    {
161        let db = db.into_database_executor();
162        let manager = SchemaManager::new(db);
163        exec_down(self, &manager, steps).await
164    }
165}
166
167#[async_trait::async_trait]
168impl<M> MigratorTraitSelf for M
169where
170    M: super::MigratorTrait + Sized + Send + Sync,
171{
172    fn migrations(&self) -> Vec<Box<dyn MigrationTrait>> {
173        M::migrations()
174    }
175
176    fn migration_table_name(&self) -> DynIden {
177        M::migration_table_name()
178    }
179
180    fn get_migration_files(&self) -> Vec<Migration> {
181        M::get_migration_files()
182    }
183
184    async fn get_migration_models<C>(&self, db: &C) -> Result<Vec<seaql_migrations::Model>, DbErr>
185    where
186        C: ConnectionTrait,
187    {
188        M::get_migration_models(db).await
189    }
190
191    async fn get_migration_with_status<C>(&self, db: &C) -> Result<Vec<Migration>, DbErr>
192    where
193        C: ConnectionTrait,
194    {
195        M::get_migration_with_status(db).await
196    }
197
198    async fn get_pending_migrations<C>(&self, db: &C) -> Result<Vec<Migration>, DbErr>
199    where
200        C: ConnectionTrait,
201    {
202        M::get_pending_migrations(db).await
203    }
204
205    async fn get_applied_migrations<C>(&self, db: &C) -> Result<Vec<Migration>, DbErr>
206    where
207        C: ConnectionTrait,
208    {
209        M::get_applied_migrations(db).await
210    }
211
212    async fn install<C>(&self, db: &C) -> Result<(), DbErr>
213    where
214        C: ConnectionTrait,
215    {
216        M::install(db).await
217    }
218
219    /// Check the status of all migrations
220    async fn status<C>(&self, db: &C) -> Result<(), DbErr>
221    where
222        C: ConnectionTrait,
223    {
224        M::status(db).await
225    }
226
227    async fn fresh<'c, C>(&self, db: C) -> Result<(), DbErr>
228    where
229        C: IntoSchemaManagerConnection<'c>,
230    {
231        M::fresh(db).await
232    }
233
234    async fn refresh<'c, C>(&self, db: C) -> Result<(), DbErr>
235    where
236        C: IntoSchemaManagerConnection<'c>,
237    {
238        M::refresh(db).await
239    }
240
241    async fn reset<'c, C>(&self, db: C) -> Result<(), DbErr>
242    where
243        C: IntoSchemaManagerConnection<'c>,
244    {
245        M::reset(db).await
246    }
247
248    async fn uninstall<'c, C>(&self, db: C) -> Result<(), DbErr>
249    where
250        C: IntoSchemaManagerConnection<'c>,
251    {
252        M::uninstall(db).await
253    }
254
255    async fn up<'c, C>(&self, db: C, steps: Option<u32>) -> Result<(), DbErr>
256    where
257        C: IntoSchemaManagerConnection<'c>,
258    {
259        M::up(db, steps).await
260    }
261
262    async fn down<'c, C>(&self, db: C, steps: Option<u32>) -> Result<(), DbErr>
263    where
264        C: IntoSchemaManagerConnection<'c>,
265    {
266        M::down(db, steps).await
267    }
268}
269
270async fn exec_fresh<M>(migrator: &M, manager: &SchemaManager<'_>) -> Result<(), DbErr>
271where
272    M: MigratorTraitSelf,
273{
274    let db = manager.get_connection();
275
276    migrator.install(db).await?;
277
278    drop_everything(db).await?;
279
280    exec_up(migrator, manager, None).await
281}
282
283async fn exec_up<M>(
284    migrator: &M,
285    manager: &SchemaManager<'_>,
286    steps: Option<u32>,
287) -> Result<(), DbErr>
288where
289    M: MigratorTraitSelf,
290{
291    let db = manager.get_connection();
292
293    migrator.install(db).await?;
294
295    exec_up_with(
296        manager,
297        steps,
298        migrator.get_pending_migrations(db).await?,
299        migrator.migration_table_name(),
300    )
301    .await
302}
303
304async fn exec_down<M>(
305    migrator: &M,
306    manager: &SchemaManager<'_>,
307    steps: Option<u32>,
308) -> Result<(), DbErr>
309where
310    M: MigratorTraitSelf,
311{
312    let db = manager.get_connection();
313
314    migrator.install(db).await?;
315
316    exec_down_with(
317        manager,
318        steps,
319        migrator.get_applied_migrations(db).await?,
320        migrator.migration_table_name(),
321    )
322    .await
323}