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}