@@ -10,7 +10,7 @@ use sea_orm::sea_query::{
1010} ;
1111use sea_orm:: {
1212 ActiveValue , ConnectionTrait , DbBackend , DbErr , DynIden , EntityTrait , FromQueryResult ,
13- Iterable , QueryFilter , Schema , Statement ,
13+ Iterable , QueryFilter , Schema , Statement , TransactionTrait ,
1414} ;
1515
1616pub async fn get_migration_models < C > (
@@ -198,6 +198,48 @@ pub async fn drop_everything<C: ConnectionTrait>(db: &C) -> Result<(), DbErr> {
198198 Ok ( ( ) )
199199}
200200
201+ fn should_use_transaction ( migration : & dyn crate :: MigrationTrait , backend : DbBackend ) -> bool {
202+ match migration. use_transaction ( ) {
203+ Some ( v) => v,
204+ None => backend == DbBackend :: Postgres ,
205+ }
206+ }
207+
208+ async fn insert_migration_record < C : ConnectionTrait > (
209+ db : & C ,
210+ name : & str ,
211+ migration_table_name : DynIden ,
212+ ) -> Result < ( ) , DbErr > {
213+ #[ cfg( not( feature = "with-time" ) ) ]
214+ let applied_at = SystemTime :: now ( )
215+ . duration_since ( SystemTime :: UNIX_EPOCH )
216+ . expect ( "SystemTime before UNIX EPOCH!" )
217+ . as_secs ( ) as i64 ;
218+ #[ cfg( feature = "with-time" ) ]
219+ let applied_at = sea_orm:: prelude:: TimeDateTimeWithTimeZone :: now_utc ( ) . unix_timestamp ( ) ;
220+ seaql_migrations:: Entity :: insert ( seaql_migrations:: ActiveModel {
221+ version : ActiveValue :: Set ( name. to_owned ( ) ) ,
222+ applied_at : ActiveValue :: Set ( applied_at) ,
223+ } )
224+ . table_name ( migration_table_name)
225+ . exec ( db)
226+ . await ?;
227+ Ok ( ( ) )
228+ }
229+
230+ async fn delete_migration_record < C : ConnectionTrait > (
231+ db : & C ,
232+ name : & str ,
233+ migration_table_name : DynIden ,
234+ ) -> Result < ( ) , DbErr > {
235+ seaql_migrations:: Entity :: delete_many ( )
236+ . filter ( Expr :: col ( seaql_migrations:: Column :: Version ) . eq ( name) )
237+ . table_name ( migration_table_name)
238+ . exec ( db)
239+ . await ?;
240+ Ok ( ( ) )
241+ }
242+
201243pub async fn exec_up_with (
202244 manager : & SchemaManager < ' _ > ,
203245 mut steps : Option < u32 > ,
@@ -222,23 +264,23 @@ pub async fn exec_up_with(
222264 }
223265 * steps -= 1 ;
224266 }
267+
268+ let use_txn = should_use_transaction ( migration. as_ref ( ) , db. get_database_backend ( ) ) ;
225269 info ! ( "Applying migration '{}'" , migration. name( ) ) ;
226- migration. up ( manager) . await ?;
227- info ! ( "Migration '{}' has been applied" , migration. name( ) ) ;
228- #[ cfg( not( feature = "with-time" ) ) ]
229- let applied_at = SystemTime :: now ( )
230- . duration_since ( SystemTime :: UNIX_EPOCH )
231- . expect ( "SystemTime before UNIX EPOCH!" )
232- . as_secs ( ) as i64 ;
233- #[ cfg( feature = "with-time" ) ]
234- let applied_at = sea_orm:: prelude:: TimeDateTimeWithTimeZone :: now_utc ( ) . unix_timestamp ( ) ;
235- seaql_migrations:: Entity :: insert ( seaql_migrations:: ActiveModel {
236- version : ActiveValue :: Set ( migration. name ( ) . to_owned ( ) ) ,
237- applied_at : ActiveValue :: Set ( applied_at) ,
238- } )
239- . table_name ( migration_table_name. clone ( ) )
240- . exec ( db)
241- . await ?;
270+
271+ if use_txn {
272+ let transaction = db. begin ( ) . await ?;
273+ let txn_manager = SchemaManager :: new ( & transaction) ;
274+ migration. up ( & txn_manager) . await ?;
275+ info ! ( "Migration '{}' has been applied" , migration. name( ) ) ;
276+ insert_migration_record ( & transaction, migration. name ( ) , migration_table_name. clone ( ) )
277+ . await ?;
278+ transaction. commit ( ) . await ?;
279+ } else {
280+ migration. up ( manager) . await ?;
281+ info ! ( "Migration '{}' has been applied" , migration. name( ) ) ;
282+ insert_migration_record ( db, migration. name ( ) , migration_table_name. clone ( ) ) . await ?;
283+ }
242284 }
243285
244286 Ok ( ( ) )
@@ -268,14 +310,23 @@ pub async fn exec_down_with(
268310 }
269311 * steps -= 1 ;
270312 }
313+
314+ let use_txn = should_use_transaction ( migration. as_ref ( ) , db. get_database_backend ( ) ) ;
271315 info ! ( "Rolling back migration '{}'" , migration. name( ) ) ;
272- migration. down ( manager) . await ?;
273- info ! ( "Migration '{}' has been rollbacked" , migration. name( ) ) ;
274- seaql_migrations:: Entity :: delete_many ( )
275- . filter ( Expr :: col ( seaql_migrations:: Column :: Version ) . eq ( migration. name ( ) ) )
276- . table_name ( migration_table_name. clone ( ) )
277- . exec ( db)
278- . await ?;
316+
317+ if use_txn {
318+ let transaction = db. begin ( ) . await ?;
319+ let txn_manager = SchemaManager :: new ( & transaction) ;
320+ migration. down ( & txn_manager) . await ?;
321+ info ! ( "Migration '{}' has been rolled back" , migration. name( ) ) ;
322+ delete_migration_record ( & transaction, migration. name ( ) , migration_table_name. clone ( ) )
323+ . await ?;
324+ transaction. commit ( ) . await ?;
325+ } else {
326+ migration. down ( manager) . await ?;
327+ info ! ( "Migration '{}' has been rolled back" , migration. name( ) ) ;
328+ delete_migration_record ( db, migration. name ( ) , migration_table_name. clone ( ) ) . await ?;
329+ }
279330 }
280331
281332 Ok ( ( ) )
0 commit comments