registry: add extension migration seam
This commit is contained in:
@@ -148,4 +148,5 @@ Progress:
|
|||||||
- Phase 0 / task `0.5`: введены `PolicyEngine`, `SessionActor`, `PolicyAction`, `PolicyScope`, `PolicyDecision` и default `OwnerOnlyPolicyEngine` в public seam `crank_core::ext::access`
|
- Phase 0 / task `0.5`: введены `PolicyEngine`, `SessionActor`, `PolicyAction`, `PolicyScope`, `PolicyDecision` и default `OwnerOnlyPolicyEngine` в public seam `crank_core::ext::access`
|
||||||
- Phase 0 / task `0.6`: введены `AuditSink`, `NoopAuditSink`, `AuditEventId` и базовые audit-типы в public seam `crank_core::ext::audit`
|
- Phase 0 / task `0.6`: введены `AuditSink`, `NoopAuditSink`, `AuditEventId` и базовые audit-типы в public seam `crank_core::ext::audit`
|
||||||
- Phase 0 / task `0.7`: введены `CapabilityProfile` и `CommunityCapabilityProfile`, а `admin-api` capability payload теперь собирается через public seam вместо локального literal
|
- Phase 0 / task `0.7`: введены `CapabilityProfile` и `CommunityCapabilityProfile`, а `admin-api` capability payload теперь собирается через public seam вместо локального literal
|
||||||
|
- Phase 0 / task `0.13`: введены `RegistryExtension`, `ExtensionMigration` и `apply_extension_migrations(...)` в `crank-registry` как отдельный public seam для additive private migrations
|
||||||
- backward-compatible alias `CommunityMachineCredentialVerifier` сохранен, поведение Community не изменено
|
- backward-compatible alias `CommunityMachineCredentialVerifier` сохранен, поведение Community не изменено
|
||||||
|
|||||||
@@ -0,0 +1,77 @@
|
|||||||
|
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(())
|
||||||
|
}
|
||||||
@@ -1,9 +1,11 @@
|
|||||||
mod error;
|
mod error;
|
||||||
|
mod ext;
|
||||||
mod migrations;
|
mod migrations;
|
||||||
mod model;
|
mod model;
|
||||||
mod postgres;
|
mod postgres;
|
||||||
|
|
||||||
pub use error::RegistryError;
|
pub use error::RegistryError;
|
||||||
|
pub use ext::{ExtensionMigration, RegistryExtension, apply_extension_migrations};
|
||||||
pub use model::{
|
pub use model::{
|
||||||
AgentSummary, AgentVersionRecord, AsyncJobFilter, AsyncJobRecord, AuthUserRecord,
|
AgentSummary, AgentVersionRecord, AsyncJobFilter, AsyncJobRecord, AuthUserRecord,
|
||||||
CreateAgentRequest, CreateAsyncJobRequest, CreateInvitationRequest, CreateInvocationLogRequest,
|
CreateAgentRequest, CreateAsyncJobRequest, CreateInvitationRequest, CreateInvocationLogRequest,
|
||||||
|
|||||||
Reference in New Issue
Block a user