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(act) => format!("ON INSERT {}", act),
166 };
167 write!(f, "{}", value)
168 }
169}
170
171impl Display for ast::RefAct {
172 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
173 let value = match self {
174 Self::Cascade => "CASCADE",
175 Self::NoAction => "NO ACTION",
176 Self::Restrict => "RESTRICT",
177 Self::SetDefault => "SET DEFAULT",
178 Self::SetNull => "SET NULL",
179 };
180 write!(f, "{}", value)
181 }
182}
183
184impl Display for ast::DeferSubclause {
185 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
186 let value = format!(
187 "{}{}",
188 if self.deferrable {
189 "NOT DEFERRABLE"
190 } else {
191 "DEFERRABLE"
192 },
193 if let Some(init_deffered) = &self.init_deferred {
194 match init_deffered {
195 ast::InitDeferredPred::InitiallyDeferred => " INITIALLY DEFERRED",
196 ast::InitDeferredPred::InitiallyImmediate => " INITIALLY IMMEDIATE",
197 }
198 } else {
199 ""
200 }
201 );
202 write!(f, "{}", value)
203 }
204}
205#[cfg(test)]
206mod tests {
207 use crate::to_sql_string_test;
208
209 to_sql_string_test!(
210 test_alter_table_rename,
211 "ALTER TABLE t RENAME TO new_table_name;"
212 );
213
214 to_sql_string_test!(
215 test_alter_table_add_column,
216 "ALTER TABLE t ADD COLUMN c INTEGER;"
217 );
218
219 to_sql_string_test!(
220 test_alter_table_add_column_with_default,
221 "ALTER TABLE t ADD COLUMN c TEXT DEFAULT 'value';"
222 );
223
224 to_sql_string_test!(
225 test_alter_table_add_column_not_null_default,
226 "ALTER TABLE t ADD COLUMN c REAL NOT NULL DEFAULT 0.0;"
227 );
228
229 to_sql_string_test!(
230 test_alter_table_add_column_unique,
231 "ALTER TABLE t ADD COLUMN c TEXT UNIQUE",
232 ignore = "ParserError = Cannot add a UNIQUE column;"
233 );
234
235 to_sql_string_test!(
236 test_alter_table_rename_column,
237 "ALTER TABLE t RENAME COLUMN old_name TO new_name;"
238 );
239
240 to_sql_string_test!(test_alter_table_drop_column, "ALTER TABLE t DROP COLUMN c;");
241
242 to_sql_string_test!(
243 test_alter_table_add_column_check,
244 "ALTER TABLE t ADD COLUMN c INTEGER CHECK (c > 0);"
245 );
246
247 to_sql_string_test!(
248 test_alter_table_add_column_foreign_key,
249 "ALTER TABLE t ADD COLUMN c INTEGER REFERENCES t2(id) ON DELETE CASCADE;"
250 );
251
252 to_sql_string_test!(
253 test_alter_table_add_column_foreign_key_on_insert,
254 "ALTER TABLE t ADD COLUMN c INTEGER REFERENCES t2(id) ON INSERT CASCADE;"
255 );
256
257 to_sql_string_test!(
258 test_alter_table_add_column_foreign_key_on_insert_and_update,
259 "ALTER TABLE t ADD COLUMN c INTEGER REFERENCES t2(id) ON INSERT CASCADE ON UPDATE SET NULL;"
260 );
261
262 to_sql_string_test!(
263 test_alter_table_add_column_collate,
264 "ALTER TABLE t ADD COLUMN c TEXT COLLATE NOCASE;"
265 );
266
267 to_sql_string_test!(
268 test_alter_table_add_column_primary_key,
269 "ALTER TABLE t ADD COLUMN c INTEGER PRIMARY KEY;",
270 ignore = "ParserError = Cannot add a PRIMARY KEY column"
271 );
272
273 to_sql_string_test!(
274 test_alter_table_add_column_primary_key_autoincrement,
275 "ALTER TABLE t ADD COLUMN c INTEGER PRIMARY KEY AUTOINCREMENT;",
276 ignore = "ParserError = Cannot add a PRIMARY KEY column"
277 );
278
279 to_sql_string_test!(
280 test_alter_table_add_generated_column,
281 "ALTER TABLE t ADD COLUMN c_generated AS (a + b) STORED;"
282 );
283
284 to_sql_string_test!(
285 test_alter_table_add_column_schema,
286 "ALTER TABLE schema_name.t ADD COLUMN c INTEGER;"
287 );
288}