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