assert_migrator_reversible/
assert_migrator_reversible.rs1use ::sea_orm_migration::prelude::MigratorTrait;
2
3#[cfg(feature = "tokio")]
4use ::tokio::runtime::Builder;
5#[cfg(feature = "tokio")]
6use ::tokio::runtime::Runtime;
7
8use crate::build_db_connection;
9use crate::DbConnection;
10
11use crate::queries::get_table_schemas;
12use crate::queries::get_type_schemas;
13use crate::queries::TableSchema;
14use crate::queries::TypeSchema;
15
16#[cfg(feature = "tokio")]
25pub fn assert_migrator_reversible<'a, M>(migrator: M, db_conn: Option<DbConnection<'a>>)
26where
27 M: MigratorTrait,
28{
29 build_tokio_runtime()
30 .block_on(async move { assert_migrator_reversible_async(migrator, db_conn).await });
31}
32
33pub async fn assert_migrator_reversible_async<'a, M>(migrator: M, db_conn: Option<DbConnection<'a>>)
37where
38 M: MigratorTrait,
39{
40 let maybe_index = find_index_of_non_reversible_migration_async(migrator, db_conn).await;
41 if let Some(index) = maybe_index {
42 panic!("Migration at index {} is not reversible", index);
43 }
44}
45
46#[cfg(feature = "tokio")]
66pub fn find_index_of_non_reversible_migration<'a, M>(
67 migrator: M,
68 db_conn: Option<DbConnection<'a>>,
69) -> Option<usize>
70where
71 M: MigratorTrait,
72{
73 build_tokio_runtime().block_on(async move {
74 find_index_of_non_reversible_migration_async(migrator, db_conn).await
75 })
76}
77
78pub async fn find_index_of_non_reversible_migration_async<'a, M>(
82 _migrator: M,
83 db_conn: Option<DbConnection<'a>>,
84) -> Option<usize>
85where
86 M: MigratorTrait,
87{
88 let db_connection = build_db_connection(db_conn).await;
89 let num_migrations = M::migrations().len();
90 let mut migration_step_schemas: Vec<Vec<TableSchema>> = Vec::with_capacity(num_migrations);
91 let mut migration_type_schemas: Vec<Vec<TypeSchema>> = Vec::with_capacity(num_migrations);
92
93 for _ in 0..num_migrations {
95 let table_schemas = get_table_schemas(&db_connection).await;
96 migration_step_schemas.push(table_schemas);
97
98 let type_schemas = get_type_schemas(&db_connection).await;
99 migration_type_schemas.push(type_schemas);
100
101 <M as MigratorTrait>::up(&db_connection, Some(1))
102 .await
103 .expect("expect migration up should succeed");
104 }
105
106 for i in 0..num_migrations {
108 <M as MigratorTrait>::down(&db_connection, Some(1))
109 .await
110 .expect("expect migration down should succeed");
111
112 let down_table_schemas = get_table_schemas(&db_connection).await;
114 let up_table_schemas = migration_step_schemas
115 .pop()
116 .expect("expect up table schemas should exist");
117 if down_table_schemas != up_table_schemas {
118 for i in 0..up_table_schemas.len() {
119 let left = &up_table_schemas[i];
120 let right = &down_table_schemas[i];
121
122 if left != right {
123 println!("{:#?}", left);
124 println!("{:#?}", right);
125 return Some(num_migrations - i - 1);
126 }
127 }
128 return Some(num_migrations - i - 1);
129 }
130
131 let down_type_schemas = get_type_schemas(&db_connection).await;
133 let up_type_schemas = migration_type_schemas
134 .pop()
135 .expect("expect up table schemas should exist");
136 if down_type_schemas != up_type_schemas {
137 return Some(num_migrations - i - 1);
138 }
139 }
140
141 None
142}
143
144#[cfg(feature = "tokio")]
145fn build_tokio_runtime() -> Runtime {
146 Builder::new_current_thread()
147 .enable_time()
148 .enable_io()
149 .build()
150 .expect("Expect to be able to start Tokio runtime for testing")
151}