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}