waypoint-core 0.4.0

Lightweight, Flyway-compatible SQL migration library for PostgreSQL and MySQL
Documentation
//! PostgreSQL dialect implementation.

use super::{DatabaseDialect, DialectKind};

/// PostgreSQL 12+ dialect.
pub struct PostgresDialect;

impl DatabaseDialect for PostgresDialect {
    fn kind(&self) -> DialectKind {
        DialectKind::Postgres
    }

    fn quote_ident(&self, name: &str) -> String {
        format!("\"{}\"", name.replace('"', "\"\""))
    }

    fn history_table_ddl(&self, schema: &str, table: &str) -> String {
        let fq = self.qualified_table(schema, table);
        let success_idx = self.quote_ident(&format!("{}_s_idx", table));
        let version_idx = self.quote_ident(&format!("{}_v_idx", table));
        format!(
            r#"
CREATE TABLE IF NOT EXISTS {fq} (
    installed_rank INTEGER PRIMARY KEY,
    version        VARCHAR(50),
    description    VARCHAR(200) NOT NULL,
    type           VARCHAR(20) NOT NULL,
    script         VARCHAR(1000) NOT NULL,
    checksum       INTEGER,
    installed_by   VARCHAR(100) NOT NULL,
    installed_on   TIMESTAMPTZ NOT NULL DEFAULT now(),
    execution_time INTEGER NOT NULL,
    success        BOOLEAN NOT NULL,
    reversal_sql   TEXT
);

CREATE INDEX IF NOT EXISTS {success_idx} ON {fq} (success);
CREATE INDEX IF NOT EXISTS {version_idx} ON {fq} (version);
"#
        )
    }

    fn supports_transactional_ddl(&self) -> bool {
        true
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn quotes_identifier_with_double_quotes() {
        let d = PostgresDialect;
        assert_eq!(d.quote_ident("users"), r#""users""#);
        assert_eq!(d.quote_ident(r#"my"table"#), r#""my""table""#);
    }

    #[test]
    fn history_ddl_contains_required_columns() {
        let d = PostgresDialect;
        let ddl = d.history_table_ddl("public", "waypoint_schema_history");
        for col in [
            "installed_rank",
            "version",
            "description",
            "type",
            "script",
            "checksum",
            "installed_by",
            "installed_on",
            "execution_time",
            "success",
            "reversal_sql",
        ] {
            assert!(ddl.contains(col), "DDL missing column {}", col);
        }
        assert!(ddl.contains("TIMESTAMPTZ"));
    }

    #[test]
    fn supports_transactional_ddl() {
        assert!(PostgresDialect.supports_transactional_ddl());
    }
}