systemprompt_database/lifecycle/installation/extension/
current.rs1use systemprompt_extension::{ExtensionRegistry, LoaderError};
15use systemprompt_identifiers::ExtensionId;
16
17use super::super::prepare::prepare_extension_schema;
18use crate::lifecycle::migrations::{ChecksumDrift, MigrationService, PendingMigration};
19use crate::services::DatabaseProvider;
20
21#[derive(Debug, Default)]
23pub struct SchemaCurrency {
24 pub fresh_extensions: Vec<ExtensionId>,
25 pub pending: Vec<PendingMigration>,
26 pub drift: Vec<ChecksumDrift>,
27}
28
29impl SchemaCurrency {
30 #[must_use]
31 pub const fn is_current(&self) -> bool {
32 self.fresh_extensions.is_empty() && self.pending.is_empty() && self.drift.is_empty()
33 }
34}
35
36pub async fn schema_currency(
37 db: &dyn DatabaseProvider,
38 registry: &ExtensionRegistry,
39 disabled_extensions: &[ExtensionId],
40) -> Result<SchemaCurrency, LoaderError> {
41 let migrations = MigrationService::new(db);
42 let mut currency = SchemaCurrency::default();
43
44 for ext in registry.enabled_schema_extensions(disabled_extensions)? {
45 let prepared = prepare_extension_schema(ext.as_ref())?;
46 let freshness = migrations
47 .assess_freshness(&prepared.extension_id, &prepared.owned_tables)
48 .await?;
49 if freshness.tables_total > 0 && freshness.tables_present == 0 {
50 currency.fresh_extensions.push(prepared.extension_id);
51 continue;
52 }
53 if ext.has_migrations() {
54 let status = migrations.status(ext.as_ref()).await?;
55 currency.pending.extend(status.pending);
56 currency.drift.extend(status.drift);
57 }
58 }
59
60 Ok(currency)
61}