use super::MigrationService;
use systemprompt_extension::{Extension, LoaderError};
#[derive(Debug, Clone)]
pub struct MarkAppliedOutcome {
pub extension_id: String,
pub version: u32,
pub name: String,
pub checksum: String,
}
impl MigrationService<'_> {
pub async fn mark_applied(
&self,
extension: &dyn Extension,
version: u32,
) -> Result<MarkAppliedOutcome, LoaderError> {
let ext_id = extension.metadata().id;
let migration = extension
.migrations()
.into_iter()
.find(|m| m.version == version)
.ok_or_else(|| LoaderError::MigrationFailed {
extension: ext_id.to_string(),
message: format!(
"Migration version {version} is not defined for extension '{ext_id}'"
),
})?;
self.ensure_migrations_table_exists().await?;
let applied = self.get_applied_migrations(ext_id).await?;
if applied.iter().any(|m| m.version == version) {
return Err(LoaderError::MigrationFailed {
extension: ext_id.to_string(),
message: format!(
"Migration {version} ('{}') is already tracked as applied for extension \
'{ext_id}'; nothing to do",
migration.name
),
});
}
let id = format!("{ext_id}_{:03}", migration.version);
let checksum = migration.checksum();
self.db
.execute(
&"INSERT INTO extension_migrations (id, extension_id, version, name, checksum) \
VALUES ($1, $2, $3, $4, $5)",
&[&id, &ext_id, &migration.version, &migration.name, &checksum],
)
.await
.map_err(|e| LoaderError::MigrationFailed {
extension: ext_id.to_string(),
message: format!("Failed to record migration as applied: {e}"),
})?;
Ok(MarkAppliedOutcome {
extension_id: ext_id.to_string(),
version: migration.version,
name: migration.name.clone(),
checksum,
})
}
}