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}