sea_orm_migration/
migrator.rs1mod queries;
2
3mod exec;
4use exec::*;
5
6mod with_self;
7pub use with_self::*;
8
9use std::fmt::Display;
10use tracing::info;
11
12use super::{IntoSchemaManagerConnection, MigrationTrait, SchemaManager, seaql_migrations};
13use sea_orm::sea_query::IntoIden;
14use sea_orm::{ConnectionTrait, DbErr, DynIden};
15
16#[derive(Copy, Clone, Debug, PartialEq, Eq)]
17pub enum MigrationStatus {
19 Pending,
21 Applied,
23}
24
25impl Display for MigrationStatus {
26 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
27 let status = match self {
28 MigrationStatus::Pending => "Pending",
29 MigrationStatus::Applied => "Applied",
30 };
31 write!(f, "{status}")
32 }
33}
34
35pub struct Migration {
36 migration: Box<dyn MigrationTrait>,
37 status: MigrationStatus,
38}
39
40impl Migration {
41 pub fn name(&self) -> &str {
43 self.migration.name()
44 }
45
46 pub fn status(&self) -> MigrationStatus {
48 self.status
49 }
50}
51
52#[async_trait::async_trait]
54pub trait MigratorTrait: Send {
55 fn migrations() -> Vec<Box<dyn MigrationTrait>>;
57
58 fn migration_table_name() -> DynIden {
60 seaql_migrations::Entity.into_iden()
61 }
62
63 fn get_migration_files() -> Vec<Migration> {
65 Self::migrations()
66 .into_iter()
67 .map(|migration| Migration {
68 migration,
69 status: MigrationStatus::Pending,
70 })
71 .collect()
72 }
73
74 async fn get_migration_models<C>(db: &C) -> Result<Vec<seaql_migrations::Model>, DbErr>
76 where
77 C: ConnectionTrait,
78 {
79 Self::install(db).await?;
80 get_migration_models(db, Self::migration_table_name()).await
81 }
82
83 async fn get_migration_with_status<C>(db: &C) -> Result<Vec<Migration>, DbErr>
85 where
86 C: ConnectionTrait,
87 {
88 Self::install(db).await?;
89 get_migration_with_status(
90 Self::get_migration_files(),
91 Self::get_migration_models(db).await?,
92 )
93 }
94
95 async fn get_pending_migrations<C>(db: &C) -> Result<Vec<Migration>, DbErr>
97 where
98 C: ConnectionTrait,
99 {
100 Self::install(db).await?;
101 Ok(Self::get_migration_with_status(db)
102 .await?
103 .into_iter()
104 .filter(|file| file.status == MigrationStatus::Pending)
105 .collect())
106 }
107
108 async fn get_applied_migrations<C>(db: &C) -> Result<Vec<Migration>, DbErr>
110 where
111 C: ConnectionTrait,
112 {
113 Self::install(db).await?;
114 Ok(Self::get_migration_with_status(db)
115 .await?
116 .into_iter()
117 .filter(|file| file.status == MigrationStatus::Applied)
118 .collect())
119 }
120
121 async fn install<C>(db: &C) -> Result<(), DbErr>
123 where
124 C: ConnectionTrait,
125 {
126 install(db, Self::migration_table_name()).await
127 }
128
129 async fn status<C>(db: &C) -> Result<(), DbErr>
131 where
132 C: ConnectionTrait,
133 {
134 Self::install(db).await?;
135
136 info!("Checking migration status");
137
138 for Migration { migration, status } in Self::get_migration_with_status(db).await? {
139 info!("Migration '{}'... {}", migration.name(), status);
140 }
141
142 Ok(())
143 }
144
145 async fn fresh<'c, C>(db: C) -> Result<(), DbErr>
147 where
148 C: IntoSchemaManagerConnection<'c>,
149 {
150 let db = db.into_database_executor();
151 let manager = SchemaManager::new(db);
152 exec_fresh::<Self>(&manager).await
153 }
154
155 async fn refresh<'c, C>(db: C) -> Result<(), DbErr>
157 where
158 C: IntoSchemaManagerConnection<'c>,
159 {
160 let db = db.into_database_executor();
161 let manager = SchemaManager::new(db);
162 exec_down::<Self>(&manager, None).await?;
163 exec_up::<Self>(&manager, None).await
164 }
165
166 async fn reset<'c, C>(db: C) -> Result<(), DbErr>
168 where
169 C: IntoSchemaManagerConnection<'c>,
170 {
171 let db = db.into_database_executor();
172 let manager = SchemaManager::new(db);
173 exec_down::<Self>(&manager, None).await?;
174 uninstall(&manager, Self::migration_table_name()).await
175 }
176
177 async fn uninstall<'c, C>(db: C) -> Result<(), DbErr>
180 where
181 C: IntoSchemaManagerConnection<'c>,
182 {
183 let db = db.into_database_executor();
184 let manager = SchemaManager::new(db);
185 uninstall(&manager, Self::migration_table_name()).await
186 }
187
188 async fn up<'c, C>(db: C, steps: Option<u32>) -> Result<(), DbErr>
190 where
191 C: IntoSchemaManagerConnection<'c>,
192 {
193 let db = db.into_database_executor();
194 let manager = SchemaManager::new(db);
195 exec_up::<Self>(&manager, steps).await
196 }
197
198 async fn down<'c, C>(db: C, steps: Option<u32>) -> Result<(), DbErr>
200 where
201 C: IntoSchemaManagerConnection<'c>,
202 {
203 let db = db.into_database_executor();
204 let manager = SchemaManager::new(db);
205 exec_down::<Self>(&manager, steps).await
206 }
207}
208
209async fn exec_fresh<M>(manager: &SchemaManager<'_>) -> Result<(), DbErr>
210where
211 M: MigratorTrait + ?Sized,
212{
213 let db = manager.get_connection();
214
215 M::install(db).await?;
216
217 drop_everything(db).await?;
218
219 exec_up::<M>(manager, None).await
220}
221
222async fn exec_up<M>(manager: &SchemaManager<'_>, steps: Option<u32>) -> Result<(), DbErr>
223where
224 M: MigratorTrait + ?Sized,
225{
226 let db = manager.get_connection();
227
228 M::install(db).await?;
229
230 exec_up_with(
231 manager,
232 steps,
233 M::get_pending_migrations(db).await?,
234 M::migration_table_name(),
235 )
236 .await
237}
238
239async fn exec_down<M>(manager: &SchemaManager<'_>, steps: Option<u32>) -> Result<(), DbErr>
240where
241 M: MigratorTrait + ?Sized,
242{
243 let db = manager.get_connection();
244
245 M::install(db).await?;
246
247 exec_down_with(
248 manager,
249 steps,
250 M::get_applied_migrations(db).await?,
251 M::migration_table_name(),
252 )
253 .await
254}