rorm_sql/
alter_table.rs

1use std::fmt::Write;
2
3use crate::create_column::{CreateColumn, CreateColumnImpl};
4use crate::error::Error;
5use crate::Value;
6
7/**
8Representation of operations to execute in the context of an ALTER TABLE statement.
9 */
10#[derive(Debug)]
11pub enum AlterTableOperation<'until_build, 'post_build> {
12    /// Use this operation to rename a table
13    RenameTo {
14        /// New name of the table
15        name: String,
16    },
17    /// Use this operation to rename a column within a table
18    RenameColumnTo {
19        /// Current column name
20        column_name: String,
21        /// New column name
22        new_column_name: String,
23    },
24    /// Use this operation to add a column to an existing table.
25    AddColumn {
26        /// Operation to use for adding the column
27        operation: CreateColumnImpl<'until_build, 'post_build>,
28    },
29    /// Use this operation to drop an existing column.
30    DropColumn {
31        /// Name of the column to drop
32        name: String,
33    },
34}
35
36/**
37The trait representing an alter table builder
38*/
39pub trait AlterTable<'post_build> {
40    /**
41    This method is used to build the alter table statement.
42     */
43    fn build(self) -> Result<Vec<(String, Vec<Value<'post_build>>)>, Error>;
44}
45
46/**
47Representation of the data of an ALTER TABLE statement.
48 */
49#[derive(Debug)]
50pub struct AlterTableData<'until_build, 'post_build> {
51    /// Name of the table to operate on
52    pub(crate) name: &'until_build str,
53    /// Operation to execute
54    pub(crate) operation: AlterTableOperation<'until_build, 'post_build>,
55    pub(crate) lookup: Vec<Value<'post_build>>,
56    pub(crate) statements: Vec<(String, Vec<Value<'post_build>>)>,
57}
58
59/**
60Implementation of the [AlterTable] trait for the different database dialects.
61
62Should only be constructed via [crate::DBImpl::alter_table].
63 */
64#[derive(Debug)]
65pub enum AlterTableImpl<'until_build, 'post_build> {
66    /**
67    SQLite representation of the ALTER TABLE operation.
68     */
69    #[cfg(feature = "sqlite")]
70    SQLite(AlterTableData<'until_build, 'post_build>),
71    /**
72    MySQL representation of the ALTER TABLE operation.
73     */
74    #[cfg(feature = "mysql")]
75    MySQL(AlterTableData<'until_build, 'post_build>),
76    /**
77    Postgres representation of the ALTER TABLE operation.
78     */
79    #[cfg(feature = "postgres")]
80    Postgres(AlterTableData<'until_build, 'post_build>),
81}
82
83impl<'post_build> AlterTable<'post_build> for AlterTableImpl<'_, 'post_build> {
84    fn build(self) -> Result<Vec<(String, Vec<Value<'post_build>>)>, Error> {
85        match self {
86            #[cfg(feature = "sqlite")]
87            AlterTableImpl::SQLite(mut d) => {
88                let mut s = format!("ALTER TABLE \"{}\" ", d.name);
89
90                match d.operation {
91                    AlterTableOperation::RenameTo { name } => {
92                        write!(s, "RENAME TO \"{name}\"").unwrap();
93                    }
94                    AlterTableOperation::RenameColumnTo {
95                        column_name,
96                        new_column_name,
97                    } => write!(
98                        s,
99                        "RENAME COLUMN \"{column_name}\" TO \"{new_column_name}\""
100                    )
101                    .unwrap(),
102                    AlterTableOperation::AddColumn { mut operation } => {
103                        write!(s, "ADD COLUMN ").unwrap();
104
105                        #[cfg(any(feature = "mysql", feature = "postgres"))]
106                        if let CreateColumnImpl::SQLite(ref mut ccd) = operation {
107                            ccd.statements = Some(&mut d.statements);
108                            ccd.lookup = Some(&mut d.lookup);
109                        }
110                        #[cfg(not(any(feature = "mysql", feature = "postgres")))]
111                        {
112                            let CreateColumnImpl::SQLite(ref mut ccd) = operation;
113                            ccd.statements = Some(&mut d.statements);
114                            ccd.lookup = Some(&mut d.lookup);
115                        }
116
117                        operation.build(&mut s)?;
118                    }
119                    AlterTableOperation::DropColumn { name } => {
120                        write!(s, "DROP COLUMN \"{name}\"").unwrap()
121                    }
122                };
123
124                write!(s, ";").unwrap();
125
126                let mut statements = vec![(s, d.lookup)];
127                statements.extend(d.statements);
128
129                Ok(statements)
130            }
131            #[cfg(feature = "mysql")]
132            AlterTableImpl::MySQL(mut d) => {
133                let mut s = format!("ALTER TABLE `{}` ", d.name);
134
135                match d.operation {
136                    AlterTableOperation::RenameTo { name } => {
137                        write!(s, "RENAME TO `{name}`").unwrap();
138                    }
139                    AlterTableOperation::RenameColumnTo {
140                        column_name,
141                        new_column_name,
142                    } => write!(s, "RENAME COLUMN `{column_name}` TO `{new_column_name}`").unwrap(),
143                    AlterTableOperation::AddColumn { mut operation } => {
144                        write!(s, "ADD COLUMN ").unwrap();
145
146                        #[cfg(any(feature = "sqlite", feature = "postgres"))]
147                        if let CreateColumnImpl::MySQL(ref mut ccd) = operation {
148                            ccd.statements = Some(&mut d.statements);
149                            ccd.lookup = Some(&mut d.lookup);
150                        }
151                        #[cfg(not(any(feature = "sqlite", feature = "postgres")))]
152                        {
153                            let CreateColumnImpl::MySQL(ref mut ccd) = operation;
154                            ccd.statements = Some(&mut d.statements);
155                            ccd.lookup = Some(&mut d.lookup);
156                        }
157
158                        operation.build(&mut s)?;
159                    }
160                    AlterTableOperation::DropColumn { name } => {
161                        write!(s, "DROP COLUMN `{name}`").unwrap()
162                    }
163                };
164
165                write!(s, ";").unwrap();
166
167                let mut statements = vec![(s, d.lookup)];
168                statements.extend(d.statements);
169
170                Ok(statements)
171            }
172            #[cfg(feature = "postgres")]
173            AlterTableImpl::Postgres(mut d) => {
174                let mut s = format!("ALTER TABLE \"{}\" ", d.name);
175
176                match d.operation {
177                    AlterTableOperation::RenameTo { name } => {
178                        write!(s, "RENAME TO \"{name}\"").unwrap();
179                    }
180
181                    AlterTableOperation::RenameColumnTo {
182                        column_name,
183                        new_column_name,
184                    } => {
185                        write!(
186                            s,
187                            "RENAME COLUMN \"{column_name}\" TO \"{new_column_name}\""
188                        )
189                        .unwrap();
190                    }
191                    AlterTableOperation::AddColumn { mut operation } => {
192                        write!(s, "ADD COLUMN ").unwrap();
193
194                        #[cfg(any(feature = "sqlite", feature = "mysql"))]
195                        if let CreateColumnImpl::Postgres(ref mut ccd) = operation {
196                            ccd.statements = Some(&mut d.statements);
197                        }
198                        #[cfg(not(any(feature = "sqlite", feature = "mysql")))]
199                        {
200                            let CreateColumnImpl::Postgres(ref mut ccd) = operation;
201                            ccd.statements = Some(&mut d.statements);
202                        }
203
204                        operation.build(&mut s)?;
205                    }
206                    AlterTableOperation::DropColumn { name } => {
207                        write!(s, "DROP COLUMN \"{name}\"").unwrap()
208                    }
209                };
210
211                write!(s, ";").unwrap();
212
213                let mut statements = vec![(s, d.lookup)];
214                statements.extend(d.statements);
215
216                Ok(statements)
217            }
218        }
219    }
220}