systemprompt_database/lifecycle/installation/
report.rs1use serde::Serialize;
10use systemprompt_identifiers::ExtensionId;
11
12use super::undeclared::SchemaResidue;
13
14#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
15pub struct ForeignKeyDrift {
16 pub extension: ExtensionId,
17 pub table: String,
18 pub constraint: String,
19 pub sql: String,
20 pub cause: String,
21}
22
23#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize)]
33pub struct SchemaInstallReport {
34 pub foreign_key_drift: Vec<ForeignKeyDrift>,
35 pub residue: SchemaResidue,
36 pub ahead: Vec<SchemaAhead>,
37}
38
39impl SchemaAhead {
40 #[must_use]
41 pub fn from_currency(currency: &super::extension::current::SchemaCurrency) -> Vec<Self> {
42 currency
43 .ahead
44 .iter()
45 .map(|m| Self {
46 extension: m.extension_id.clone(),
47 version: m.version,
48 name: m.name.clone(),
49 breaks_older: currency
50 .breaking
51 .iter()
52 .any(|b| b.extension_id == m.extension_id && b.version == m.version),
53 })
54 .collect()
55 }
56}
57
58#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
60pub struct SchemaAhead {
61 pub extension: ExtensionId,
62 pub version: u32,
63 pub name: String,
64 pub breaks_older: bool,
65}
66
67impl SchemaInstallReport {
68 #[must_use]
69 pub const fn is_clean(&self) -> bool {
70 self.foreign_key_drift.is_empty()
71 }
72
73 #[must_use]
74 pub const fn is_tidy(&self) -> bool {
75 self.residue.is_empty()
76 }
77
78 #[must_use]
79 pub const fn is_ahead(&self) -> bool {
80 !self.ahead.is_empty()
81 }
82
83 #[must_use]
84 pub fn breaks_this_release(&self) -> bool {
85 self.ahead.iter().any(|m| m.breaks_older)
86 }
87}