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}