1use std::path::Path;
4
5use toolu_orm_connection::DbConnection;
6use toolu_orm_core::dialect::Dialect;
7
8use crate::migrate::{ensure_migrations_table, get_applied_migrations, MigrateError};
9
10pub struct MigrationStatus {
11 pub applied: Vec<String>,
12 pub pending: Vec<String>,
13}
14
15pub async fn get_status(
21 conn: &impl DbConnection,
22 migrations_dir: &str,
23 dialect: Dialect,
24) -> Result<MigrationStatus, MigrateError> {
25 ensure_migrations_table(conn, dialect).await?;
26 let applied = get_applied_migrations(conn).await?;
27 let all_files = collect_all_sql_files(migrations_dir)?;
28
29 let pending: Vec<String> = all_files
30 .into_iter()
31 .filter(|f| !applied.contains(f))
32 .collect();
33
34 Ok(MigrationStatus { applied, pending })
35}
36
37fn collect_all_sql_files(migrations_dir: &str) -> Result<Vec<String>, MigrateError> {
38 let path = Path::new(migrations_dir);
39 if !path.exists() {
40 return Ok(vec![]);
41 }
42
43 let mut all_files: Vec<String> = Vec::new();
44 let entries =
45 std::fs::read_dir(path).map_err(|e| MigrateError::ReadDir(format!("{migrations_dir}: {e}")))?;
46
47 for entry in entries {
48 let entry = entry.map_err(|e| MigrateError::ReadDir(format!("{migrations_dir}: {e}")))?;
49 let name = entry.file_name().to_string_lossy().into_owned();
50 if name.ends_with(".sql") {
51 all_files.push(name);
52 }
53 }
54
55 all_files.sort();
56 Ok(all_files)
57}