78 lines
2.1 KiB
Rust
78 lines
2.1 KiB
Rust
use std::sync::Arc;
|
|
|
|
use sqlx::{PgPool, query};
|
|
|
|
use crate::RegistryError;
|
|
|
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
|
pub struct ExtensionMigration {
|
|
pub version: u32,
|
|
pub sql: &'static str,
|
|
}
|
|
|
|
pub trait RegistryExtension: Send + Sync {
|
|
fn name(&self) -> &str;
|
|
fn migrations(&self) -> &[ExtensionMigration];
|
|
}
|
|
|
|
pub async fn apply_extension_migrations(
|
|
pool: &PgPool,
|
|
extensions: &[Arc<dyn RegistryExtension>],
|
|
) -> Result<(), RegistryError> {
|
|
query(
|
|
"create table if not exists __crank_ext_migrations (
|
|
extension_name text not null,
|
|
version integer not null,
|
|
applied_at timestamptz not null default now(),
|
|
primary key (extension_name, version)
|
|
)",
|
|
)
|
|
.execute(pool)
|
|
.await?;
|
|
|
|
for extension in extensions {
|
|
for migration in extension.migrations() {
|
|
let already_applied = query(
|
|
"select 1
|
|
from __crank_ext_migrations
|
|
where extension_name = $1 and version = $2",
|
|
)
|
|
.bind(extension.name())
|
|
.bind(i32::try_from(migration.version).map_err(|_| {
|
|
RegistryError::InvalidNumericValue {
|
|
field: "extension_migration.version",
|
|
value: migration.version as i64,
|
|
}
|
|
})?)
|
|
.fetch_optional(pool)
|
|
.await?
|
|
.is_some();
|
|
|
|
if already_applied {
|
|
continue;
|
|
}
|
|
|
|
let mut tx = pool.begin().await?;
|
|
|
|
query(migration.sql).execute(&mut *tx).await?;
|
|
query(
|
|
"insert into __crank_ext_migrations (extension_name, version)
|
|
values ($1, $2)",
|
|
)
|
|
.bind(extension.name())
|
|
.bind(i32::try_from(migration.version).map_err(|_| {
|
|
RegistryError::InvalidNumericValue {
|
|
field: "extension_migration.version",
|
|
value: migration.version as i64,
|
|
}
|
|
})?)
|
|
.execute(&mut *tx)
|
|
.await?;
|
|
|
|
tx.commit().await?;
|
|
}
|
|
}
|
|
|
|
Ok(())
|
|
}
|