Skip to content

Commit

Permalink
Start adding more migrations
Browse files Browse the repository at this point in the history
  • Loading branch information
Einliterflasche committed Oct 9, 2023
1 parent 8cf0b3c commit b9c7a9c
Showing 1 changed file with 86 additions and 29 deletions.
115 changes: 86 additions & 29 deletions pg-worm/src/migration/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,46 @@ impl Table {

self
}

fn up(&self) -> String {
let mut up = format!(
"CREATE TABLE {} ({})",
self.name,
self.columns.iter().map(|i| i.up())._join(", ")
);

if !self.constraints.is_empty() {
up.push_str(&format!(
", {}",
self.constraints.iter().map(|i| i.up())._join(", ")
));
}

up
}

fn down(&self) -> String {
format!("DROP TABLE IF EXISTS {}", self.name)
}

fn drop_all_constraints_cascading(&self) -> String {
// This is a pl/pgsql code block which first queries for all
// constraints on a given table and then removes them.
format!(
r#"DO $$
DECLARE i RECORD;
BEGIN
FOR i IN (SELECT conname
FROM pg_catalog.pg_constraint con
INNER JOIN pg_catalog.pg_class rel ON rel.oid = con.conrelid
INNER JOIN pg_catalog.pg_namespace nsp ON nsp.oid = connamespace
WHERE rel.relname = {0}) LOOP
EXECUTE format('ALTER TABLE {0} DROP CONSTRAINT %I CASCADE', i.conname);
END LOOP;
END $$;"#,
self.name
)
}
}

impl Column {
Expand Down Expand Up @@ -98,32 +138,7 @@ impl Column {

self
}
}

trait Up {
fn up(&self) -> String;
}

impl Up for Table {
fn up(&self) -> String {
let mut up = format!(
"CREATE TABLE {} ({})",
self.name,
self.columns.iter().map(|i| i.up())._join(", ")
);

if !self.constraints.is_empty() {
up.push_str(&format!(
", {}",
self.constraints.iter().map(|i| i.up())._join(", ")
));
}

up
}
}

impl Up for Column {
fn up(&self) -> String {
let mut up = format!("{} {}", self.name, self.data_type);

Expand All @@ -141,9 +156,40 @@ impl Up for Column {

up
}

fn down(&self) -> String {
format!("DROP COLUMN IF EXISTS {}", self.name)
}

fn migrate_from(&self, other: &Column, table: &Table) -> Vec<String> {
let mut statements = Vec::new();

if other.constraints.len() > 0 {
statements.push(table.drop_all_constraints_cascading());
}

if self.constraints.len() > 0 {
let mut stmts = self
.constraints
.iter()
.map(|i| i.migrate_to(&self))
.collect::<Vec<String>>();

statements.append(&mut stmts);
}

if self.data_type != other.data_type {
statements.push(format!(
"ALTER COLUMN {} SET TYPE {}",
self.name, self.data_type
));
}

statements
}
}

impl Up for TableConstraint {
impl TableConstraint {
fn up(&self) -> String {
use TableConstraint as C;

Expand All @@ -167,7 +213,7 @@ impl Up for TableConstraint {
}
}

impl Up for ColumnConstraint {
impl ColumnConstraint {
fn up(&self) -> String {
use ColumnConstraint as C;

Expand All @@ -184,8 +230,21 @@ impl Up for ColumnConstraint {
C::RawCheckNamed(name, check) => format!("CONSTRAINT {name} CHECK ({check})"),
}
}

fn migrate_to(&self, column: &Column) -> String {
use ColumnConstraint as C;

match self {
C::NotNull => format!("ALTER COLUMN {} DROP NULL", column.name),
C::PrimaryKey => format!("ADD CONSTRAINT PRIMARY KEY ({})", column.name),
C::Unique => format!("ALTER COLUMN {} SET UNIQUE", column.name),
_ => todo!(),
}
}
}

/// Convenience method to avoid writing `.iter().map(|i| i.to_string()).collect::<Vec<String>>().join()`
/// all the time.
trait Join {
fn _join(self, _: &str) -> String;
}
Expand All @@ -206,8 +265,6 @@ where

#[cfg(test)]
mod tests {
use crate::migration::Up;

use super::{Column, Table};

#[test]
Expand Down

0 comments on commit b9c7a9c

Please sign in to comment.