1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
use crate::{Dialect, Column, ToSql, Type};
use crate::util::SqlExtension;

#[derive(Debug)]
pub enum AlterColumnAction {
    SetType(Type),
    SetNullable(bool),
}

/// Alter table action
#[derive(Debug)]
pub enum AlterAction {
    AddColumn {
        column: Column,
    },
    AlterColumn {
        name: String,
        action: AlterColumnAction,
    },
}

impl AlterAction {
    pub fn set_nullable(name: String, nullable: bool) -> Self {
        Self::AlterColumn {
            name,
            action: AlterColumnAction::SetNullable(nullable),
        }
    }

    pub fn set_type(name: String, typ: Type) -> Self {
        Self::AlterColumn {
            name,
            action: AlterColumnAction::SetType(typ),
        }
    }
}

#[derive(Debug)]
pub struct AlterTable {
    pub schema: Option<String>,
    pub name: String,
    pub actions: Vec<AlterAction>,
}

impl ToSql for AlterTable {
    fn write_sql(&self, buf: &mut String, dialect: Dialect) {
        #[cfg(feature = "tracing")]
        tracing::error_span!("alter-table", table = format!(
            "{}{}{}",
            self.schema.as_deref().unwrap_or(""),
            if self.schema.is_some() { "." } else { "" },
            self.name
        ));
        buf.push_str("ALTER TABLE ");
        buf.push_table_name(&self.schema, &self.name);
        buf.push_sql_sequence(&self.actions, ",", dialect);
    }
}

impl ToSql for AlterAction {
    fn write_sql(&self, buf: &mut String, dialect: Dialect) {
        use AlterAction::*;
        match self {
            AddColumn { column } => {
                buf.push_str(" ADD COLUMN ");
                buf.push_str(&column.to_sql(dialect));
            }
            AlterColumn { name, action } => {
                use AlterColumnAction::*;
                buf.push_str(" ALTER COLUMN ");
                buf.push_quoted(name);
                match action {
                    SetType(ty) => {
                        buf.push_str(" TYPE ");
                        buf.push_sql(ty, dialect);
                        buf.push_str(" USING ");
                        buf.push_quoted(name);
                        buf.push_str("::");
                        buf.push_sql(ty, dialect);
                    }
                    SetNullable(nullable) => {
                        if *nullable {
                            buf.push_str(" DROP NOT NULL");
                        } else {
                            buf.push_str(" SET NOT NULL");
                        }
                    }
                }
            }
        }
    }
}