Skip to main content

waypoint_core/dialect/
postgres.rs

1//! PostgreSQL dialect implementation.
2
3use super::{DatabaseDialect, DialectKind};
4
5/// PostgreSQL 12+ dialect.
6pub struct PostgresDialect;
7
8impl DatabaseDialect for PostgresDialect {
9    fn kind(&self) -> DialectKind {
10        DialectKind::Postgres
11    }
12
13    fn quote_ident(&self, name: &str) -> String {
14        format!("\"{}\"", name.replace('"', "\"\""))
15    }
16
17    fn history_table_ddl(&self, schema: &str, table: &str) -> String {
18        let fq = self.qualified_table(schema, table);
19        let success_idx = self.quote_ident(&format!("{}_s_idx", table));
20        let version_idx = self.quote_ident(&format!("{}_v_idx", table));
21        format!(
22            r#"
23CREATE TABLE IF NOT EXISTS {fq} (
24    installed_rank INTEGER PRIMARY KEY,
25    version        VARCHAR(50),
26    description    VARCHAR(200) NOT NULL,
27    type           VARCHAR(20) NOT NULL,
28    script         VARCHAR(1000) NOT NULL,
29    checksum       INTEGER,
30    installed_by   VARCHAR(100) NOT NULL,
31    installed_on   TIMESTAMPTZ NOT NULL DEFAULT now(),
32    execution_time INTEGER NOT NULL,
33    success        BOOLEAN NOT NULL,
34    reversal_sql   TEXT
35);
36
37CREATE INDEX IF NOT EXISTS {success_idx} ON {fq} (success);
38CREATE INDEX IF NOT EXISTS {version_idx} ON {fq} (version);
39"#
40        )
41    }
42
43    fn supports_transactional_ddl(&self) -> bool {
44        true
45    }
46}
47
48#[cfg(test)]
49mod tests {
50    use super::*;
51
52    #[test]
53    fn quotes_identifier_with_double_quotes() {
54        let d = PostgresDialect;
55        assert_eq!(d.quote_ident("users"), r#""users""#);
56        assert_eq!(d.quote_ident(r#"my"table"#), r#""my""table""#);
57    }
58
59    #[test]
60    fn history_ddl_contains_required_columns() {
61        let d = PostgresDialect;
62        let ddl = d.history_table_ddl("public", "waypoint_schema_history");
63        for col in [
64            "installed_rank",
65            "version",
66            "description",
67            "type",
68            "script",
69            "checksum",
70            "installed_by",
71            "installed_on",
72            "execution_time",
73            "success",
74            "reversal_sql",
75        ] {
76            assert!(ddl.contains(col), "DDL missing column {}", col);
77        }
78        assert!(ddl.contains("TIMESTAMPTZ"));
79    }
80
81    #[test]
82    fn supports_transactional_ddl() {
83        assert!(PostgresDialect.supports_transactional_ddl());
84    }
85}