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