migrations.rs

 1use std::path::Path;
 2use std::time::Duration;
 3
 4use anyhow::{Result, anyhow};
 5use collections::HashMap;
 6use sea_orm::ConnectOptions;
 7use sqlx::Connection;
 8use sqlx::migrate::{Migrate, Migration, MigrationSource};
 9
10/// Runs the database migrations for the specified database.
11pub async fn run_database_migrations(
12    database_options: &ConnectOptions,
13    migrations_path: impl AsRef<Path>,
14) -> Result<Vec<(Migration, Duration)>> {
15    let migrations = MigrationSource::resolve(migrations_path.as_ref())
16        .await
17        .map_err(|err| anyhow!("failed to load migrations: {err:?}"))?;
18
19    let mut connection = sqlx::AnyConnection::connect(database_options.get_url()).await?;
20
21    connection.ensure_migrations_table().await?;
22    let applied_migrations: HashMap<_, _> = connection
23        .list_applied_migrations()
24        .await?
25        .into_iter()
26        .map(|migration| (migration.version, migration))
27        .collect();
28
29    let mut new_migrations = Vec::new();
30    for migration in migrations {
31        match applied_migrations.get(&migration.version) {
32            Some(applied_migration) => {
33                anyhow::ensure!(
34                    migration.checksum == applied_migration.checksum,
35                    "checksum mismatch for applied migration {}",
36                    migration.description
37                );
38            }
39            None => {
40                let elapsed = connection.apply(&migration).await?;
41                new_migrations.push((migration, elapsed));
42            }
43        }
44    }
45
46    Ok(new_migrations)
47}