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::{
97 ast::{ColumnDef, ColumnUniqueOption, DataType, Expr, ToSql},
98 data::Value,
99 };
100
101 #[test]
102 fn to_sql_column_def() {
103 assert_eq!(
104 r#""name" TEXT NOT NULL UNIQUE"#,
105 ColumnDef {
106 name: "name".to_owned(),
107 data_type: DataType::Text,
108 nullable: false,
109 default: None,
110 unique: Some(ColumnUniqueOption { is_primary: false }),
111 comment: None,
112 }
113 .to_sql()
114 );
115
116 assert_eq!(
117 r#""accepted" BOOLEAN NULL"#,
118 ColumnDef {
119 name: "accepted".to_owned(),
120 data_type: DataType::Boolean,
121 nullable: true,
122 default: None,
123 unique: None,
124 comment: None,
125 }
126 .to_sql()
127 );
128
129 assert_eq!(
130 r#""id" INT NOT NULL PRIMARY KEY"#,
131 ColumnDef {
132 name: "id".to_owned(),
133 data_type: DataType::Int,
134 nullable: false,
135 default: None,
136 unique: Some(ColumnUniqueOption { is_primary: true }),
137 comment: None,
138 }
139 .to_sql()
140 );
141
142 assert_eq!(
143 r#""accepted" BOOLEAN NOT NULL DEFAULT FALSE"#,
144 ColumnDef {
145 name: "accepted".to_owned(),
146 data_type: DataType::Boolean,
147 nullable: false,
148 default: Some(Expr::Value(Value::Bool(false))),
149 unique: None,
150 comment: None,
151 }
152 .to_sql()
153 );
154
155 assert_eq!(
156 r#""accepted" BOOLEAN NOT NULL DEFAULT FALSE UNIQUE"#,
157 ColumnDef {
158 name: "accepted".to_owned(),
159 data_type: DataType::Boolean,
160 nullable: false,
161 default: Some(Expr::Value(Value::Bool(false))),
162 unique: Some(ColumnUniqueOption { is_primary: false }),
163 comment: None,
164 }
165 .to_sql()
166 );
167
168 assert_eq!(
169 r#""accepted" BOOLEAN NOT NULL COMMENT 'this is comment'"#,
170 ColumnDef {
171 name: "accepted".to_owned(),
172 data_type: DataType::Boolean,
173 nullable: false,
174 default: None,
175 unique: None,
176 comment: Some("this is comment".to_owned()),
177 }
178 .to_sql()
179 );
180 }
181}