1use {
2 super::{DataType, Expr},
3 crate::ast::ToSql,
4 serde::{Deserialize, Serialize},
5};
6
7#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
8pub enum AlterTableOperation {
9 AddColumn { column_def: ColumnDef },
11 DropColumn {
13 column_name: String,
14 if_exists: bool,
15 },
16 RenameColumn {
18 old_column_name: String,
19 new_column_name: String,
20 },
21 RenameTable { table_name: String },
23}
24
25#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
26pub struct ColumnDef {
27 pub name: String,
28 pub data_type: DataType,
29 pub nullable: bool,
30 pub default: Option<Expr>,
32 pub unique: Option<ColumnUniqueOption>,
34 pub comment: Option<String>,
35}
36
37#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
38pub struct ColumnUniqueOption {
39 pub is_primary: bool,
40}
41
42#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
43pub struct OperateFunctionArg {
44 pub name: String,
45 pub data_type: DataType,
46 pub default: Option<Expr>,
48}
49
50impl ToSql for ColumnDef {
51 fn to_sql(&self) -> String {
52 let ColumnDef {
53 name,
54 data_type,
55 nullable,
56 default,
57 unique,
58 comment,
59 } = self;
60 {
61 let nullable = match nullable {
62 true => "NULL",
63 false => "NOT NULL",
64 };
65 let column_def = format!(r#""{name}" {data_type} {nullable}"#);
66 let default = default
67 .as_ref()
68 .map(|expr| format!("DEFAULT {}", expr.to_sql()));
69 let unique = unique.as_ref().map(ToSql::to_sql);
70 let comment = comment
71 .as_ref()
72 .map(|comment| format!("COMMENT '{comment}'"));
73
74 [Some(column_def), default, unique, comment]
75 .into_iter()
76 .flatten()
77 .collect::<Vec<_>>()
78 .join(" ")
79 }
80 }
81}
82
83impl ToSql for ColumnUniqueOption {
84 fn to_sql(&self) -> String {
85 if self.is_primary {
86 "PRIMARY KEY"
87 } else {
88 "UNIQUE"
89 }
90 .to_owned()
91 }
92}
93
94#[cfg(test)]
95mod tests {
96 use crate::ast::{AstLiteral, ColumnDef, ColumnUniqueOption, DataType, Expr, ToSql};
97
98 #[test]
99 fn to_sql_column_def() {
100 assert_eq!(
101 r#""name" TEXT NOT NULL UNIQUE"#,
102 ColumnDef {
103 name: "name".to_owned(),
104 data_type: DataType::Text,
105 nullable: false,
106 default: None,
107 unique: Some(ColumnUniqueOption { is_primary: false }),
108 comment: None,
109 }
110 .to_sql()
111 );
112
113 assert_eq!(
114 r#""accepted" BOOLEAN NULL"#,
115 ColumnDef {
116 name: "accepted".to_owned(),
117 data_type: DataType::Boolean,
118 nullable: true,
119 default: None,
120 unique: None,
121 comment: None,
122 }
123 .to_sql()
124 );
125
126 assert_eq!(
127 r#""id" INT NOT NULL PRIMARY KEY"#,
128 ColumnDef {
129 name: "id".to_owned(),
130 data_type: DataType::Int,
131 nullable: false,
132 default: None,
133 unique: Some(ColumnUniqueOption { is_primary: true }),
134 comment: None,
135 }
136 .to_sql()
137 );
138
139 assert_eq!(
140 r#""accepted" BOOLEAN NOT NULL DEFAULT FALSE"#,
141 ColumnDef {
142 name: "accepted".to_owned(),
143 data_type: DataType::Boolean,
144 nullable: false,
145 default: Some(Expr::Literal(AstLiteral::Boolean(false))),
146 unique: None,
147 comment: None,
148 }
149 .to_sql()
150 );
151
152 assert_eq!(
153 r#""accepted" BOOLEAN NOT NULL DEFAULT FALSE UNIQUE"#,
154 ColumnDef {
155 name: "accepted".to_owned(),
156 data_type: DataType::Boolean,
157 nullable: false,
158 default: Some(Expr::Literal(AstLiteral::Boolean(false))),
159 unique: Some(ColumnUniqueOption { is_primary: false }),
160 comment: None,
161 }
162 .to_sql()
163 );
164
165 assert_eq!(
166 r#""accepted" BOOLEAN NOT NULL COMMENT 'this is comment'"#,
167 ColumnDef {
168 name: "accepted".to_owned(),
169 data_type: DataType::Boolean,
170 nullable: false,
171 default: None,
172 unique: None,
173 comment: Some("this is comment".to_owned()),
174 }
175 .to_sql()
176 );
177 }
178}