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 if migration.checksum != applied_migration.checksum {
34 Err(anyhow!(
35 "checksum mismatch for applied migration {}",
36 migration.description
37 ))?;
38 }
39 }
40 None => {
41 let elapsed = connection.apply(&migration).await?;
42 new_migrations.push((migration, elapsed));
43 }
44 }
45 }
46
47 Ok(new_migrations)
48}