limbo_sqlite3_parser/to_sql_string/stmt/
alter_table.rs1use std::fmt::Display;
2
3use crate::{ast, to_sql_string::ToSqlString};
4
5impl ToSqlString for ast::AlterTableBody {
6 fn to_sql_string<C: crate::to_sql_string::ToSqlContext>(&self, context: &C) -> String {
7 match self {
8 Self::AddColumn(col_def) => format!("ADD COLUMN {}", col_def.to_sql_string(context)),
9 Self::DropColumn(name) => format!("DROP COLUMN {}", name.0),
10 Self::RenameColumn { old, new } => format!("RENAME COLUMN {} TO {}", old.0, new.0),
11 Self::RenameTo(name) => format!("RENAME TO {}", name.0),
12 }
13 }
14}
15
16impl ToSqlString for ast::ColumnDefinition {
17 fn to_sql_string<C: crate::to_sql_string::ToSqlContext>(&self, context: &C) -> String {
18 format!(
19 "{}{}{}",
20 self.col_name.0,
21 if let Some(col_type) = &self.col_type {
22 format!(" {}", col_type.to_sql_string(context))
23 } else {
24 "".to_string()
25 },
26 if !self.constraints.is_empty() {
27 format!(
28 " {}",
29 self.constraints
30 .iter()
31 .map(|constraint| constraint.to_sql_string(context))
32 .collect::<Vec<_>>()
33 .join(" ")
34 )
35 } else {
36 "".to_string()
37 }
38 )
39 }
40}
41
42impl ToSqlString for ast::NamedColumnConstraint {
43 fn to_sql_string<C: crate::to_sql_string::ToSqlContext>(&self, context: &C) -> String {
44 let mut ret = Vec::new();
45 if let Some(name) = &self.name {
46 ret.push(format!("CONSTRAINT {}", name.0));
47 }
48 ret.push(self.constraint.to_sql_string(context));
49 ret.join(" ")
50 }
51}
52
53impl ToSqlString for ast::ColumnConstraint {
54 fn to_sql_string<C: crate::to_sql_string::ToSqlContext>(&self, context: &C) -> String {
55 match self {
56 Self::Check(expr) => format!("CHECK ({})", expr.to_sql_string(context)),
57 Self::Collate { collation_name } => format!("COLLATE {}", collation_name.0),
58 Self::Default(expr) => {
59 if matches!(expr, ast::Expr::Literal(..)) {
60 format!("DEFAULT {}", expr.to_sql_string(context))
61 } else {
62 format!("DEFAULT ({})", expr.to_sql_string(context))
63 }
64 }
65 Self::Defer(expr) => expr.to_string(),
66 Self::ForeignKey {
67 clause,
68 deref_clause,
69 } => format!(
70 "{}{}",
71 clause,
72 if let Some(deref) = deref_clause {
73 deref.to_string()
74 } else {
75 "".to_string()
76 }
77 ),
78 Self::Generated { expr, typ } => {
79 format!(
81 "AS ({}){}",
82 expr.to_sql_string(context),
83 if let Some(typ) = typ {
84 format!(" {}", &typ.0)
85 } else {
86 "".to_string()
87 }
88 )
89 }
90 Self::NotNull {
91 nullable: _,
92 conflict_clause,
93 } => {
94 format!(
96 "NOT NULL{}",
97 conflict_clause.map_or("".to_string(), |conflict| format!(" {}", conflict))
98 )
99 }
100 Self::PrimaryKey {
101 order,
102 conflict_clause,
103 auto_increment,
104 } => {
105 format!(
106 "PRIMARY KEY{}{}{}",
107 order.map_or("".to_string(), |order| format!(" {}", order)),
108 conflict_clause.map_or("".to_string(), |conflict| format!(" {}", conflict)),
109 auto_increment.then_some(" AUTOINCREMENT").unwrap_or("")
110 )
111 }
112 Self::Unique(conflict_clause) => {
113 format!(
114 "UNIQUE{}",
115 conflict_clause.map_or("".to_string(), |conflict| format!(" {}", conflict))
116 )
117 }
118 }
119 }
120}
121
122impl Display for ast::ForeignKeyClause {
123 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
124 let value = format!(
125 "REFERENCES {}{}{}",
126 self.tbl_name.0,
127 if let Some(columns) = &self.columns {
128 format!(
129 "({})",
130 columns
131 .iter()
132 .map(|cols| cols.to_string())
133 .collect::<Vec<_>>()
134 .join(", ")
135 )
136 } else {
137 "".to_string()
138 },
139 if !self.args.is_empty() {
140 format!(
141 " {}",
142 self.args
143 .iter()
144 .map(|arg| arg.to_string())
145 .collect::<Vec<_>>()
146 .join(" ")
147 )
148 } else {
149 "".to_string()
150 }
151 );
152 write!(f, "{}", value)
153 }
154}
155
156impl Display for ast::RefArg {
157 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
158 let value = match self {
159 Self::Match(name) => format!("MATCH {}", name.0),
160 Self::OnDelete(act) => format!("ON DELETE {}", act),
161 Self::OnUpdate(act) => format!("ON UPDATE {}", act),
162 Self::OnInsert(..) => unimplemented!(
163 "On Insert does not exist in SQLite: https://www.sqlite.org/lang_altertable.html"
164 ),
165 };
166 write!(f, "{}", value)
167 }
168}
169
170impl Display for ast::RefAct {
171 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
172 let value = match self {
173 Self::Cascade => "CASCADE",
174 Self::NoAction => "NO ACTION",
175 Self::Restrict => "RESTRICT",
176 Self::SetDefault => "SET DEFAULT",
177 Self::SetNull => "SET NULL",
178 };
179 write!(f, "{}", value)
180 }
181}
182
183impl Display for ast::DeferSubclause {
184 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
185 let value = format!(
186 "{}{}",
187 if self.deferrable {
188 "NOT DEFERRABLE"
189 } else {
190 "DEFERRABLE"
191 },
192 if let Some(init_deffered) = &self.init_deferred {
193 match init_deffered {
194 ast::InitDeferredPred::InitiallyDeferred => " INITIALLY DEFERRED",
195 ast::InitDeferredPred::InitiallyImmediate => " INITIALLY IMMEDIATE",
196 }
197 } else {
198 ""
199 }
200 );
201 write!(f, "{}", value)
202 }
203}
204#[cfg(test)]
205mod tests {
206 use crate::to_sql_string_test;
207
208 to_sql_string_test!(
209 test_alter_table_rename,
210 "ALTER TABLE t RENAME TO new_table_name;"
211 );
212
213 to_sql_string_test!(
214 test_alter_table_add_column,
215 "ALTER TABLE t ADD COLUMN c INTEGER;"
216 );
217
218 to_sql_string_test!(
219 test_alter_table_add_column_with_default,
220 "ALTER TABLE t ADD COLUMN c TEXT DEFAULT 'value';"
221 );
222
223 to_sql_string_test!(
224 test_alter_table_add_column_not_null_default,
225 "ALTER TABLE t ADD COLUMN c REAL NOT NULL DEFAULT 0.0;"
226 );
227
228 to_sql_string_test!(
229 test_alter_table_add_column_unique,
230 "ALTER TABLE t ADD COLUMN c TEXT UNIQUE",
231 ignore = "ParserError = Cannot add a UNIQUE column;"
232 );
233
234 to_sql_string_test!(
235 test_alter_table_rename_column,
236 "ALTER TABLE t RENAME COLUMN old_name TO new_name;"
237 );
238
239 to_sql_string_test!(test_alter_table_drop_column, "ALTER TABLE t DROP COLUMN c;");
240
241 to_sql_string_test!(
242 test_alter_table_add_column_check,
243 "ALTER TABLE t ADD COLUMN c INTEGER CHECK (c > 0);"
244 );
245
246 to_sql_string_test!(
247 test_alter_table_add_column_foreign_key,
248 "ALTER TABLE t ADD COLUMN c INTEGER REFERENCES t2(id) ON DELETE CASCADE;"
249 );
250
251 to_sql_string_test!(
252 test_alter_table_add_column_collate,
253 "ALTER TABLE t ADD COLUMN c TEXT COLLATE NOCASE;"
254 );
255
256 to_sql_string_test!(
257 test_alter_table_add_column_primary_key,
258 "ALTER TABLE t ADD COLUMN c INTEGER PRIMARY KEY;",
259 ignore = "ParserError = Cannot add a PRIMARY KEY column"
260 );
261
262 to_sql_string_test!(
263 test_alter_table_add_column_primary_key_autoincrement,
264 "ALTER TABLE t ADD COLUMN c INTEGER PRIMARY KEY AUTOINCREMENT;",
265 ignore = "ParserError = Cannot add a PRIMARY KEY column"
266 );
267
268 to_sql_string_test!(
269 test_alter_table_add_generated_column,
270 "ALTER TABLE t ADD COLUMN c_generated AS (a + b) STORED;"
271 );
272
273 to_sql_string_test!(
274 test_alter_table_add_column_schema,
275 "ALTER TABLE schema_name.t ADD COLUMN c INTEGER;"
276 );
277}