Skip to main content

sea_query/backend/
table_builder.rs

1use crate::*;
2
3pub trait TableBuilder:
4    IndexBuilder + ForeignKeyBuilder + QuotedBuilder + TableRefBuilder + QueryBuilder
5{
6    /// Translate [`TableCreateStatement`] into SQL statement.
7    fn prepare_table_create_statement(
8        &self,
9        create: &TableCreateStatement,
10        sql: &mut impl SqlWriter,
11    ) {
12        sql.write_str("CREATE ").unwrap();
13
14        self.prepare_create_temporary_table(create, sql);
15
16        sql.write_str("TABLE ").unwrap();
17
18        self.prepare_create_table_if_not_exists(create, sql);
19
20        if let Some(table_ref) = &create.table {
21            self.prepare_table_ref_table_stmt(table_ref, sql);
22        }
23
24        if let Some(partition_of) = &create.partition_of {
25            sql.write_str(" PARTITION OF ").unwrap();
26            self.prepare_table_ref_table_stmt(partition_of, sql);
27        }
28
29        if !create.columns.is_empty()
30            || !create.indexes.is_empty()
31            || !create.foreign_keys.is_empty()
32            || !create.check.is_empty()
33        {
34            sql.write_str(" ( ").unwrap();
35            let mut first = true;
36
37            create.columns.iter().for_each(|column_def| {
38                if !first {
39                    sql.write_str(", ").unwrap();
40                }
41                self.prepare_column_def(column_def, sql);
42                first = false;
43            });
44
45            create.indexes.iter().for_each(|index| {
46                if !first {
47                    sql.write_str(", ").unwrap();
48                }
49                self.prepare_table_index_expression(index, sql);
50                first = false;
51            });
52
53            create.foreign_keys.iter().for_each(|foreign_key| {
54                if !first {
55                    sql.write_str(", ").unwrap();
56                }
57                self.prepare_foreign_key_create_statement_internal(
58                    foreign_key,
59                    sql,
60                    Mode::Creation,
61                );
62                first = false;
63            });
64
65            create.check.iter().for_each(|check| {
66                if !first {
67                    sql.write_str(", ").unwrap();
68                }
69                self.prepare_check_constraint(check, sql);
70                first = false;
71            });
72
73            sql.write_str(" )").unwrap();
74        }
75
76        if let Some(partition_values) = &create.partition_values {
77            sql.write_str(" ").unwrap();
78            self.prepare_partition_values(partition_values, sql);
79        }
80
81        if let Some(partition_by) = &create.partition_by {
82            sql.write_str(" PARTITION BY ").unwrap();
83            self.prepare_partition_by(partition_by, sql);
84        }
85
86        if !create.partitions.is_empty() {
87            sql.write_str(" ( ").unwrap();
88            let mut first = true;
89            for partition in create.partitions.iter() {
90                if !first {
91                    sql.write_str(", ").unwrap();
92                }
93                self.prepare_partition_definition(&partition.name, partition.values.as_ref(), sql);
94                first = false;
95            }
96            sql.write_str(" )").unwrap();
97        }
98
99        self.prepare_table_opt(create, sql);
100
101        if let Some(extra) = &create.extra {
102            sql.write_str(" ").unwrap();
103            sql.write_str(extra).unwrap();
104        }
105    }
106
107    /// Translate [`TableRef`] into SQL statement.
108    fn prepare_table_ref_table_stmt(&self, table_ref: &TableRef, sql: &mut impl SqlWriter) {
109        match table_ref {
110            // Support only unaliased (but potentialy qualified) table names.
111            TableRef::Table(.., None) => self.prepare_table_ref_iden(table_ref, sql),
112            _ => panic!("Not supported"),
113        }
114    }
115
116    /// Translate [`ColumnDef`] into SQL statement.
117    fn prepare_column_def(&self, column_def: &ColumnDef, sql: &mut impl SqlWriter);
118
119    /// Translate [`ColumnDef`] into SQL statement.
120    fn prepare_column_def_internal(
121        &self,
122        _is_alter_column: bool,
123        column_def: &ColumnDef,
124        sql: &mut impl SqlWriter,
125    ) {
126        self.prepare_column_def(column_def, sql);
127    }
128
129    /// Translate [`ColumnType`] into SQL statement.
130    fn prepare_column_type(&self, column_type: &ColumnType, sql: &mut impl SqlWriter);
131
132    /// Translate [`ColumnSpec`] into SQL statement.
133    fn prepare_column_spec(&self, column_spec: &ColumnSpec, sql: &mut impl SqlWriter) {
134        let ColumnSpec {
135            nullable,
136            default,
137            auto_increment,
138            unique,
139            primary_key,
140            check,
141            generated,
142            extra,
143            comment,
144            using: _,
145        } = column_spec;
146
147        if let Some(nullable) = nullable {
148            sql.write_str(if *nullable { " NULL" } else { " NOT NULL" })
149                .unwrap();
150        }
151
152        if let Some(default) = default {
153            sql.write_str(" DEFAULT ").unwrap();
154            // Wrap expressions in parentheses.
155            // Most of database backends support this syntax.
156            //
157            // In MySQL 5.7, the DEFAULT clause doesn't accept any expressions,
158            // so it will be invalid SQL in any case.
159            //
160            // References:
161            // https://sqlite.org/lang_createtable.html
162            match default {
163                Expr::Value(_) | Expr::Constant(_) | Expr::Keyword(_) => {
164                    self.prepare_expr(default, sql)
165                }
166                _ => {
167                    sql.write_str("(").unwrap();
168                    self.prepare_expr(default, sql);
169                    sql.write_str(")").unwrap()
170                }
171            }
172        }
173
174        if let Some(generated) = generated {
175            self.prepare_generated_column(&generated.expr, generated.stored, sql);
176        }
177
178        if *primary_key {
179            sql.write_str(" PRIMARY KEY").unwrap();
180        }
181
182        if *auto_increment {
183            sql.write_str(self.column_spec_auto_increment_keyword())
184                .unwrap();
185        }
186
187        if *unique {
188            sql.write_str(" UNIQUE").unwrap();
189        }
190
191        if let Some(check) = check {
192            sql.write_str(" ").unwrap();
193            self.prepare_check_constraint(check, sql);
194        }
195
196        if let Some(extra) = extra {
197            sql.write_str(" ").unwrap();
198            sql.write_str(extra).unwrap();
199        }
200
201        if let Some(comment) = comment {
202            self.column_comment(comment, sql);
203        }
204    }
205
206    /// column comment
207    fn column_comment(&self, _comment: &str, _sql: &mut impl SqlWriter) {}
208
209    /// The keyword for setting a column to be auto increment.
210    fn column_spec_auto_increment_keyword(&self) -> &str;
211
212    /// Translate [`TableOpt`] into SQL statement.
213    fn prepare_table_opt(&self, create: &TableCreateStatement, sql: &mut impl SqlWriter) {
214        self.prepare_table_opt_def(create, sql)
215    }
216
217    /// Default function
218    fn prepare_table_opt_def(&self, create: &TableCreateStatement, sql: &mut impl SqlWriter) {
219        for table_opt in create.options.iter() {
220            sql.write_str(" ").unwrap();
221            match table_opt {
222                TableOpt::Engine(s) => {
223                    sql.write_str("ENGINE=").unwrap();
224                    sql.write_str(s).unwrap();
225                }
226                TableOpt::Collate(s) => {
227                    sql.write_str("COLLATE=").unwrap();
228                    sql.write_str(s).unwrap();
229                }
230                TableOpt::CharacterSet(s) => {
231                    sql.write_str("DEFAULT CHARSET=").unwrap();
232                    sql.write_str(s).unwrap();
233                }
234            }
235        }
236    }
237
238    /// Translate [`PartitionBy`] into SQL statement.
239    fn prepare_partition_by(&self, _partition_by: &PartitionBy, _sql: &mut impl SqlWriter) {}
240
241    /// Translate [`PartitionValues`] into SQL statement.
242    fn prepare_partition_values(
243        &self,
244        _partition_values: &PartitionValues,
245        _sql: &mut impl SqlWriter,
246    ) {
247    }
248
249    /// Translate a partition definition into SQL statement.
250    fn prepare_partition_definition(
251        &self,
252        _name: &DynIden,
253        _values: Option<&PartitionValues>,
254        _sql: &mut impl SqlWriter,
255    ) {
256    }
257
258    /// Translate [`TableDropStatement`] into SQL statement.
259    fn prepare_table_drop_statement(&self, drop: &TableDropStatement, sql: &mut impl SqlWriter) {
260        sql.write_str("DROP TABLE ").unwrap();
261
262        if drop.if_exists {
263            sql.write_str("IF EXISTS ").unwrap();
264        }
265
266        let mut tables = drop.tables.iter();
267        join_io!(
268            tables,
269            table,
270            join {
271                sql.write_str(", ").unwrap();
272            },
273            do {
274                self.prepare_table_ref_table_stmt(table, sql);
275            }
276        );
277
278        for drop_opt in drop.options.iter() {
279            self.prepare_table_drop_opt(drop_opt, sql);
280        }
281    }
282
283    /// Translate [`TableDropOpt`] into SQL statement.
284    fn prepare_table_drop_opt(&self, drop_opt: &TableDropOpt, sql: &mut impl SqlWriter) {
285        match drop_opt {
286            TableDropOpt::Restrict => sql.write_str(" RESTRICT").unwrap(),
287            TableDropOpt::Cascade => sql.write_str(" CASCADE").unwrap(),
288        }
289    }
290
291    /// Translate [`TableTruncateStatement`] into SQL statement.
292    fn prepare_table_truncate_statement(
293        &self,
294        truncate: &TableTruncateStatement,
295        sql: &mut impl SqlWriter,
296    ) {
297        sql.write_str("TRUNCATE TABLE ").unwrap();
298
299        if let Some(table) = &truncate.table {
300            self.prepare_table_ref_table_stmt(table, sql);
301        }
302    }
303
304    /// Translate the check constraint into SQL statement
305    fn prepare_check_constraint(&self, check: &Check, sql: &mut impl SqlWriter) {
306        if let Some(name) = &check.name {
307            sql.write_str("CONSTRAINT ").unwrap();
308            self.prepare_iden(name, sql);
309            sql.write_str(" ").unwrap();
310        }
311
312        sql.write_str("CHECK (").unwrap();
313        QueryBuilder::prepare_expr(self, &check.expr, sql);
314        sql.write_str(")").unwrap();
315    }
316
317    /// Translate the generated column into SQL statement
318    fn prepare_generated_column(&self, r#gen: &Expr, stored: bool, sql: &mut impl SqlWriter) {
319        sql.write_str(" GENERATED ALWAYS AS (").unwrap();
320        QueryBuilder::prepare_expr(self, r#gen, sql);
321        sql.write_str(")").unwrap();
322        if stored {
323            sql.write_str(" STORED").unwrap();
324        } else {
325            sql.write_str(" VIRTUAL").unwrap();
326        }
327    }
328
329    /// Translate IF NOT EXISTS expression in [`TableCreateStatement`].
330    fn prepare_create_table_if_not_exists(
331        &self,
332        create: &TableCreateStatement,
333        sql: &mut impl SqlWriter,
334    ) {
335        if create.if_not_exists {
336            sql.write_str("IF NOT EXISTS ").unwrap();
337        }
338    }
339
340    /// Translate TEMPORARY expression in [`TableCreateStatement`].
341    fn prepare_create_temporary_table(
342        &self,
343        create: &TableCreateStatement,
344        sql: &mut impl SqlWriter,
345    ) {
346        if create.temporary {
347            sql.write_str("TEMPORARY ").unwrap();
348        }
349    }
350
351    /// Translate [`TableAlterStatement`] into SQL statement.
352    fn prepare_table_alter_statement(&self, alter: &TableAlterStatement, sql: &mut impl SqlWriter);
353
354    /// Translate [`TableRenameStatement`] into SQL statement.
355    fn prepare_table_rename_statement(
356        &self,
357        rename: &TableRenameStatement,
358        sql: &mut impl SqlWriter,
359    );
360}