sea_query/table/alter.rs
1use crate::{
2 ColumnDef, IntoColumnDef, SchemaStatementBuilder, TableForeignKey, backend::SchemaBuilder,
3 types::*,
4};
5use inherent::inherent;
6
7/// Alter a table
8///
9/// # Examples
10///
11/// ```
12/// use sea_query::{tests_cfg::*, *};
13///
14/// let table = Table::alter()
15/// .table(Font::Table)
16/// .add_column(ColumnDef::new("new_col").integer().not_null().default(100))
17/// .to_owned();
18///
19/// assert_eq!(
20/// table.to_string(MysqlQueryBuilder),
21/// r#"ALTER TABLE `font` ADD COLUMN `new_col` int NOT NULL DEFAULT 100"#
22/// );
23/// assert_eq!(
24/// table.to_string(PostgresQueryBuilder),
25/// r#"ALTER TABLE "font" ADD COLUMN "new_col" integer NOT NULL DEFAULT 100"#
26/// );
27/// assert_eq!(
28/// table.to_string(SqliteQueryBuilder),
29/// r#"ALTER TABLE "font" ADD COLUMN "new_col" integer NOT NULL DEFAULT 100"#,
30/// );
31/// ```
32#[derive(Default, Debug, Clone)]
33pub struct TableAlterStatement {
34 pub(crate) table: Option<TableRef>,
35 pub(crate) options: Vec<TableAlterOption>,
36}
37
38/// table alter add column options
39#[derive(Debug, Clone)]
40pub struct AddColumnOption {
41 pub(crate) column: ColumnDef,
42 pub(crate) if_not_exists: bool,
43}
44
45/// All available table alter options
46#[allow(clippy::large_enum_variant)]
47#[derive(Debug, Clone)]
48#[non_exhaustive]
49pub enum TableAlterOption {
50 AddColumn(AddColumnOption),
51 ModifyColumn(ColumnDef),
52 RenameColumn(DynIden, DynIden),
53 DropColumn(DynIden),
54 AddForeignKey(TableForeignKey),
55 DropForeignKey(DynIden),
56}
57
58impl TableAlterStatement {
59 /// Construct alter table statement
60 pub fn new() -> Self {
61 Self::default()
62 }
63
64 /// Set table name
65 pub fn table<T>(&mut self, table: T) -> &mut Self
66 where
67 T: IntoTableRef,
68 {
69 self.table = Some(table.into_table_ref());
70 self
71 }
72
73 /// Add a column to an existing table
74 ///
75 /// # Examples
76 ///
77 /// ```
78 /// use sea_query::{tests_cfg::*, *};
79 ///
80 /// let table = Table::alter()
81 /// .table(Font::Table)
82 /// .add_column(ColumnDef::new("new_col").integer().not_null().default(100))
83 /// .to_owned();
84 ///
85 /// assert_eq!(
86 /// table.to_string(MysqlQueryBuilder),
87 /// r#"ALTER TABLE `font` ADD COLUMN `new_col` int NOT NULL DEFAULT 100"#
88 /// );
89 /// assert_eq!(
90 /// table.to_string(PostgresQueryBuilder),
91 /// r#"ALTER TABLE "font" ADD COLUMN "new_col" integer NOT NULL DEFAULT 100"#
92 /// );
93 /// assert_eq!(
94 /// table.to_string(SqliteQueryBuilder),
95 /// r#"ALTER TABLE "font" ADD COLUMN "new_col" integer NOT NULL DEFAULT 100"#,
96 /// );
97 /// ```
98 pub fn add_column<C: IntoColumnDef>(&mut self, column_def: C) -> &mut Self {
99 self.options
100 .push(TableAlterOption::AddColumn(AddColumnOption {
101 column: column_def.into_column_def(),
102 if_not_exists: false,
103 }));
104 self
105 }
106
107 /// Try add a column to an existing table if it does not exists
108 ///
109 /// # Examples
110 ///
111 /// ```
112 /// use sea_query::{tests_cfg::*, *};
113 ///
114 /// let table = Table::alter()
115 /// .table(Font::Table)
116 /// .add_column_if_not_exists(ColumnDef::new("new_col").integer().not_null().default(100))
117 /// .to_owned();
118 ///
119 /// assert_eq!(
120 /// table.to_string(MysqlQueryBuilder),
121 /// r#"ALTER TABLE `font` ADD COLUMN IF NOT EXISTS `new_col` int NOT NULL DEFAULT 100"#
122 /// );
123 /// assert_eq!(
124 /// table.to_string(PostgresQueryBuilder),
125 /// r#"ALTER TABLE "font" ADD COLUMN IF NOT EXISTS "new_col" integer NOT NULL DEFAULT 100"#
126 /// );
127 /// assert_eq!(
128 /// table.to_string(SqliteQueryBuilder),
129 /// r#"ALTER TABLE "font" ADD COLUMN "new_col" integer NOT NULL DEFAULT 100"#,
130 /// );
131 /// ```
132 pub fn add_column_if_not_exists<C: IntoColumnDef>(&mut self, column_def: C) -> &mut Self {
133 self.options
134 .push(TableAlterOption::AddColumn(AddColumnOption {
135 column: column_def.into_column_def(),
136 if_not_exists: true,
137 }));
138 self
139 }
140
141 /// Modify a column in an existing table
142 ///
143 /// # Examples
144 ///
145 /// ```
146 /// use sea_query::{tests_cfg::*, *};
147 ///
148 /// let table = Table::alter()
149 /// .table(Font::Table)
150 /// .modify_column(ColumnDef::new("new_col").big_integer().default(999))
151 /// .to_owned();
152 ///
153 /// assert_eq!(
154 /// table.to_string(MysqlQueryBuilder),
155 /// r#"ALTER TABLE `font` MODIFY COLUMN `new_col` bigint DEFAULT 999"#
156 /// );
157 /// assert_eq!(
158 /// table.to_string(PostgresQueryBuilder),
159 /// [
160 /// r#"ALTER TABLE "font""#,
161 /// r#"ALTER COLUMN "new_col" TYPE bigint,"#,
162 /// r#"ALTER COLUMN "new_col" SET DEFAULT 999"#,
163 /// ]
164 /// .join(" ")
165 /// );
166 /// // Sqlite not support modifying table column
167 /// ```
168 pub fn modify_column<C: IntoColumnDef>(&mut self, column_def: C) -> &mut Self {
169 self.add_alter_option(TableAlterOption::ModifyColumn(column_def.into_column_def()))
170 }
171
172 /// Rename a column in an existing table
173 ///
174 /// # Examples
175 ///
176 /// ```
177 /// use sea_query::{tests_cfg::*, *};
178 ///
179 /// let table = Table::alter()
180 /// .table(Font::Table)
181 /// .rename_column("new_col", "new_column")
182 /// .to_owned();
183 ///
184 /// assert_eq!(
185 /// table.to_string(MysqlQueryBuilder),
186 /// r#"ALTER TABLE `font` RENAME COLUMN `new_col` TO `new_column`"#
187 /// );
188 /// assert_eq!(
189 /// table.to_string(PostgresQueryBuilder),
190 /// r#"ALTER TABLE "font" RENAME COLUMN "new_col" TO "new_column""#
191 /// );
192 /// assert_eq!(
193 /// table.to_string(SqliteQueryBuilder),
194 /// r#"ALTER TABLE "font" RENAME COLUMN "new_col" TO "new_column""#
195 /// );
196 /// ```
197 pub fn rename_column<T, R>(&mut self, from_name: T, to_name: R) -> &mut Self
198 where
199 T: IntoIden,
200 R: IntoIden,
201 {
202 self.add_alter_option(TableAlterOption::RenameColumn(
203 from_name.into_iden(),
204 to_name.into_iden(),
205 ))
206 }
207
208 /// Drop a column from an existing table
209 ///
210 /// # Examples
211 ///
212 /// ```
213 /// use sea_query::{tests_cfg::*, *};
214 ///
215 /// let table = Table::alter()
216 /// .table(Font::Table)
217 /// .drop_column("new_column")
218 /// .to_owned();
219 ///
220 /// assert_eq!(
221 /// table.to_string(MysqlQueryBuilder),
222 /// r#"ALTER TABLE `font` DROP COLUMN `new_column`"#
223 /// );
224 /// assert_eq!(
225 /// table.to_string(PostgresQueryBuilder),
226 /// r#"ALTER TABLE "font" DROP COLUMN "new_column""#
227 /// );
228 /// assert_eq!(
229 /// table.to_string(SqliteQueryBuilder),
230 /// r#"ALTER TABLE "font" DROP COLUMN "new_column""#
231 /// );
232 /// ```
233 pub fn drop_column<T>(&mut self, col_name: T) -> &mut Self
234 where
235 T: IntoIden,
236 {
237 self.add_alter_option(TableAlterOption::DropColumn(col_name.into_iden()))
238 }
239
240 /// Add a foreign key to existing table
241 ///
242 /// # Examples
243 ///
244 /// ```
245 /// use sea_query::{tests_cfg::*, *};
246 ///
247 /// let foreign_key_char = TableForeignKey::new()
248 /// .name("FK_character_glyph")
249 /// .from_tbl(Char::Table)
250 /// .from_col(Char::FontId)
251 /// .from_col(Char::Id)
252 /// .to_tbl(Glyph::Table)
253 /// .to_col(Char::FontId)
254 /// .to_col(Char::Id)
255 /// .on_delete(ForeignKeyAction::Cascade)
256 /// .on_update(ForeignKeyAction::Cascade)
257 /// .to_owned();
258 ///
259 /// let foreign_key_font = TableForeignKey::new()
260 /// .name("FK_character_font")
261 /// .from_tbl(Char::Table)
262 /// .from_col(Char::FontId)
263 /// .to_tbl(Font::Table)
264 /// .to_col(Font::Id)
265 /// .on_delete(ForeignKeyAction::Cascade)
266 /// .on_update(ForeignKeyAction::Cascade)
267 /// .to_owned();
268 ///
269 /// let table = Table::alter()
270 /// .table(Character::Table)
271 /// .add_foreign_key(&foreign_key_char)
272 /// .add_foreign_key(&foreign_key_font)
273 /// .to_owned();
274 ///
275 /// assert_eq!(
276 /// table.to_string(MysqlQueryBuilder),
277 /// [
278 /// r#"ALTER TABLE `character`"#,
279 /// r#"ADD CONSTRAINT `FK_character_glyph`"#,
280 /// r#"FOREIGN KEY (`font_id`, `id`) REFERENCES `glyph` (`font_id`, `id`)"#,
281 /// r#"ON DELETE CASCADE ON UPDATE CASCADE,"#,
282 /// r#"ADD CONSTRAINT `FK_character_font`"#,
283 /// r#"FOREIGN KEY (`font_id`) REFERENCES `font` (`id`)"#,
284 /// r#"ON DELETE CASCADE ON UPDATE CASCADE"#,
285 /// ]
286 /// .join(" ")
287 /// );
288 ///
289 /// assert_eq!(
290 /// table.to_string(PostgresQueryBuilder),
291 /// [
292 /// r#"ALTER TABLE "character""#,
293 /// r#"ADD CONSTRAINT "FK_character_glyph""#,
294 /// r#"FOREIGN KEY ("font_id", "id") REFERENCES "glyph" ("font_id", "id")"#,
295 /// r#"ON DELETE CASCADE ON UPDATE CASCADE,"#,
296 /// r#"ADD CONSTRAINT "FK_character_font""#,
297 /// r#"FOREIGN KEY ("font_id") REFERENCES "font" ("id")"#,
298 /// r#"ON DELETE CASCADE ON UPDATE CASCADE"#,
299 /// ]
300 /// .join(" ")
301 /// );
302 ///
303 /// // Sqlite not support modifying table column
304 /// ```
305 pub fn add_foreign_key(&mut self, foreign_key: &TableForeignKey) -> &mut Self {
306 self.add_alter_option(TableAlterOption::AddForeignKey(foreign_key.to_owned()))
307 }
308
309 /// Drop a foreign key from existing table
310 ///
311 /// # Examples
312 ///
313 /// ```
314 /// use sea_query::{tests_cfg::*, *};
315 ///
316 /// let table = Table::alter()
317 /// .table(Character::Table)
318 /// .drop_foreign_key("FK_character_glyph")
319 /// .drop_foreign_key("FK_character_font")
320 /// .to_owned();
321 ///
322 /// assert_eq!(
323 /// table.to_string(MysqlQueryBuilder),
324 /// [
325 /// r#"ALTER TABLE `character`"#,
326 /// r#"DROP FOREIGN KEY `FK_character_glyph`,"#,
327 /// r#"DROP FOREIGN KEY `FK_character_font`"#,
328 /// ]
329 /// .join(" ")
330 /// );
331 ///
332 /// assert_eq!(
333 /// table.to_string(PostgresQueryBuilder),
334 /// [
335 /// r#"ALTER TABLE "character""#,
336 /// r#"DROP CONSTRAINT "FK_character_glyph","#,
337 /// r#"DROP CONSTRAINT "FK_character_font""#,
338 /// ]
339 /// .join(" ")
340 /// );
341 ///
342 /// // Sqlite not support modifying table column
343 /// ```
344 pub fn drop_foreign_key<T>(&mut self, name: T) -> &mut Self
345 where
346 T: IntoIden,
347 {
348 self.add_alter_option(TableAlterOption::DropForeignKey(name.into_iden()))
349 }
350
351 fn add_alter_option(&mut self, alter_option: TableAlterOption) -> &mut Self {
352 self.options.push(alter_option);
353 self
354 }
355
356 pub fn take(&mut self) -> Self {
357 Self {
358 table: self.table.take(),
359 options: std::mem::take(&mut self.options),
360 }
361 }
362}
363
364#[inherent]
365impl SchemaStatementBuilder for TableAlterStatement {
366 pub fn build<T: SchemaBuilder>(&self, schema_builder: T) -> String {
367 let mut sql = String::with_capacity(256);
368 schema_builder.prepare_table_alter_statement(self, &mut sql);
369 sql
370 }
371
372 pub fn build_any(&self, schema_builder: &dyn SchemaBuilder) -> String {
373 let mut sql = String::with_capacity(256);
374 schema_builder.prepare_table_alter_statement(self, &mut sql);
375 sql
376 }
377
378 pub fn to_string<T: SchemaBuilder>(&self, schema_builder: T) -> String;
379}