sea_query/backend/postgres/
table.rs

1use super::*;
2use crate::write_int;
3
4impl TableBuilder for PostgresQueryBuilder {
5    fn prepare_column_def(&self, column_def: &ColumnDef, sql: &mut impl SqlWriter) {
6        fn f(this: &PostgresQueryBuilder, column_def: &ColumnDef, sql: &mut impl SqlWriter) {
7            this.prepare_column_type_check_auto_increment(column_def, sql);
8        }
9
10        self.prepare_column_def_common(column_def, sql, |column_def, sql| f(self, column_def, sql));
11    }
12
13    fn prepare_column_type(&self, column_type: &ColumnType, sql: &mut impl SqlWriter) {
14        match column_type {
15            ColumnType::Char(length) => match length {
16                Some(length) => {
17                    sql.write_str("char(").unwrap();
18                    write_int(sql, *length);
19                    sql.write_char(')')
20                }
21                None => sql.write_str("char"),
22            },
23            ColumnType::String(length) => match length {
24                StringLen::N(length) => {
25                    sql.write_str("varchar(").unwrap();
26                    write_int(sql, *length);
27                    sql.write_char(')')
28                }
29                _ => sql.write_str("varchar"),
30            },
31            ColumnType::Text => sql.write_str("text"),
32            ColumnType::TinyInteger | ColumnType::TinyUnsigned => sql.write_str("smallint"),
33            ColumnType::SmallInteger | ColumnType::SmallUnsigned => sql.write_str("smallint"),
34            ColumnType::Integer | ColumnType::Unsigned => sql.write_str("integer"),
35            ColumnType::BigInteger | ColumnType::BigUnsigned => sql.write_str("bigint"),
36            ColumnType::Float => sql.write_str("real"),
37            ColumnType::Double => sql.write_str("double precision"),
38            ColumnType::Decimal(precision) => match precision {
39                Some((precision, scale)) => {
40                    sql.write_str("decimal(").unwrap();
41                    write_int(sql, *precision);
42                    sql.write_str(", ").unwrap();
43                    write_int(sql, *scale);
44                    sql.write_char(')')
45                }
46                None => sql.write_str("decimal"),
47            },
48            ColumnType::DateTime => sql.write_str("timestamp without time zone"),
49            ColumnType::Timestamp => sql.write_str("timestamp"),
50            ColumnType::TimestampWithTimeZone => sql.write_str("timestamp with time zone"),
51            ColumnType::Time => sql.write_str("time"),
52            ColumnType::Date => sql.write_str("date"),
53            ColumnType::Interval(fields, precision) => {
54                sql.write_str("interval").unwrap();
55
56                if let Some(fields) = fields {
57                    write!(sql, " {fields}").unwrap();
58                }
59
60                if let Some(precision) = precision {
61                    sql.write_char('(').unwrap();
62                    write_int(sql, *precision);
63                    sql.write_char(')').unwrap();
64                }
65                Ok(())
66            }
67            ColumnType::Binary(_) | ColumnType::VarBinary(_) | ColumnType::Blob => {
68                sql.write_str("bytea")
69            }
70            ColumnType::Bit(length) => match length {
71                Some(length) => {
72                    sql.write_str("bit(").unwrap();
73                    write_int(sql, *length);
74                    sql.write_char(')')
75                }
76                None => sql.write_str("bit"),
77            },
78            ColumnType::VarBit(length) => {
79                sql.write_str("varbit(").unwrap();
80                write_int(sql, *length);
81                sql.write_char(')')
82            }
83            ColumnType::Boolean => sql.write_str("bool"),
84            ColumnType::Money(precision) => match precision {
85                Some((precision, scale)) => {
86                    sql.write_str("money(").unwrap();
87                    write_int(sql, *precision);
88                    sql.write_str(", ").unwrap();
89                    write_int(sql, *scale);
90                    sql.write_char(')')
91                }
92                None => sql.write_str("money"),
93            },
94            ColumnType::Json => sql.write_str("json"),
95            ColumnType::JsonBinary => sql.write_str("jsonb"),
96            ColumnType::Uuid => sql.write_str("uuid"),
97            ColumnType::Array(elem_type) => {
98                self.prepare_column_type(elem_type, sql);
99                sql.write_str("[]")
100            }
101            ColumnType::Vector(size) => match size {
102                Some(size) => {
103                    sql.write_str("vector(").unwrap();
104                    write_int(sql, *size);
105                    sql.write_str(")")
106                }
107                None => sql.write_str("vector"),
108            },
109            ColumnType::Custom(iden) => sql.write_str(&iden.0),
110            ColumnType::Enum { name, .. } => sql.write_str(&name.0),
111            ColumnType::Cidr => sql.write_str("cidr"),
112            ColumnType::Inet => sql.write_str("inet"),
113            ColumnType::MacAddr => sql.write_str("macaddr"),
114            ColumnType::Year => unimplemented!("Year is not available in Postgres."),
115            ColumnType::LTree => sql.write_str("ltree"),
116        }
117        .unwrap()
118    }
119
120    fn column_spec_auto_increment_keyword(&self) -> &str {
121        ""
122    }
123
124    fn prepare_table_alter_statement(&self, alter: &TableAlterStatement, sql: &mut impl SqlWriter) {
125        if alter.options.is_empty() {
126            panic!("No alter option found")
127        };
128        sql.write_str("ALTER TABLE ").unwrap();
129        if let Some(table) = &alter.table {
130            self.prepare_table_ref_table_stmt(table, sql);
131            sql.write_str(" ").unwrap();
132        }
133
134        let mut opts = alter.options.iter();
135
136        join_io!(
137            opts,
138            opt,
139            join {
140                sql.write_str(", ").unwrap();
141            },
142            do {
143                match opt {
144                    TableAlterOption::AddColumn(AddColumnOption {
145                        column,
146                        if_not_exists,
147                    }) => {
148                        sql.write_str("ADD COLUMN ").unwrap();
149                        if *if_not_exists {
150                            sql.write_str("IF NOT EXISTS ").unwrap();
151                        }
152
153                        self.prepare_column_def_common(column, sql, |column_def, sql| {
154                            if let Some(column_type) = &column_def.types {
155                                write!(sql, " ").unwrap();
156                                if column_def.spec.auto_increment {
157                                    self.prepare_column_auto_increment(column_type, sql);
158                                } else {
159                                    self.prepare_column_type(column_type, sql);
160                                }
161                            }
162                        });
163                    }
164                    TableAlterOption::ModifyColumn(column_def) => {
165                        self.prepare_modify_column(sql, column_def);
166                    }
167                    TableAlterOption::RenameColumn(from_name, to_name) => {
168                        sql.write_str("RENAME COLUMN ").unwrap();
169                        self.prepare_iden(from_name, sql);
170                        sql.write_str(" TO ").unwrap();
171                        self.prepare_iden(to_name, sql);
172                    }
173                    TableAlterOption::DropColumn(column_name) => {
174                        sql.write_str("DROP COLUMN ").unwrap();
175                        self.prepare_iden(column_name, sql);
176                    }
177                    TableAlterOption::DropForeignKey(name) => {
178                        let mut foreign_key = TableForeignKey::new();
179                        foreign_key.name(name.to_string());
180                        let drop = ForeignKeyDropStatement {
181                            foreign_key,
182                            table: None,
183                        };
184                        self.prepare_foreign_key_drop_statement_internal(
185                            &drop,
186                            sql,
187                            Mode::TableAlter,
188                        );
189                    }
190                    TableAlterOption::AddForeignKey(foreign_key) => {
191                        let create = ForeignKeyCreateStatement {
192                            foreign_key: foreign_key.to_owned(),
193                        };
194                        self.prepare_foreign_key_create_statement_internal(
195                            &create,
196                            sql,
197                            Mode::TableAlter,
198                        );
199                    }
200                }
201            }
202        );
203    }
204
205    fn prepare_table_rename_statement(
206        &self,
207        rename: &TableRenameStatement,
208        sql: &mut impl SqlWriter,
209    ) {
210        sql.write_str("ALTER TABLE ").unwrap();
211        if let Some(from_name) = &rename.from_name {
212            self.prepare_table_ref_table_stmt(from_name, sql);
213        }
214        sql.write_str(" RENAME TO ").unwrap();
215        if let Some(to_name) = &rename.to_name {
216            self.prepare_table_ref_table_stmt(to_name, sql);
217        }
218    }
219}
220
221impl PostgresQueryBuilder {
222    fn prepare_column_auto_increment(&self, column_type: &ColumnType, sql: &mut impl SqlWriter) {
223        let num_ty = match column_type {
224            ColumnType::SmallInteger => "smallint GENERATED BY DEFAULT AS IDENTITY",
225            ColumnType::Integer => "integer GENERATED BY DEFAULT AS IDENTITY",
226            ColumnType::BigInteger => "bigint GENERATED BY DEFAULT AS IDENTITY",
227            _ => unimplemented!("{:?} doesn't support auto increment", column_type),
228        };
229
230        sql.write_str(num_ty).unwrap();
231    }
232
233    fn prepare_column_type_check_auto_increment(
234        &self,
235        column_def: &ColumnDef,
236        sql: &mut impl SqlWriter,
237    ) {
238        if let Some(column_type) = &column_def.types {
239            let is_auto_increment = column_def.spec.auto_increment;
240
241            sql.write_str(" ").unwrap();
242
243            if is_auto_increment {
244                self.prepare_column_auto_increment(column_type, sql);
245            } else {
246                self.prepare_column_type(column_type, sql);
247            }
248        }
249    }
250
251    fn prepare_column_def_common<F, W>(&self, column_def: &ColumnDef, sql: &mut W, f: F)
252    where
253        F: Fn(&ColumnDef, &mut W),
254        W: SqlWriter,
255    {
256        self.prepare_iden(&column_def.name, sql);
257
258        f(column_def, sql);
259
260        self.prepare_column_spec(&column_def.spec, sql);
261    }
262
263    fn prepare_modify_column(&self, sql: &mut impl SqlWriter, column_def: &ColumnDef) {
264        let mut is_first = true;
265
266        macro_rules! write_comma_if_not_first {
267            () => {
268                if !is_first {
269                    write!(sql, ", ").unwrap();
270                } else {
271                    is_first = false
272                }
273            };
274        }
275
276        if let Some(column_type) = &column_def.types {
277            write!(sql, "ALTER COLUMN ").unwrap();
278            self.prepare_iden(&column_def.name, sql);
279            write!(sql, " TYPE ").unwrap();
280            self.prepare_column_type(column_type, sql);
281            is_first = false;
282        }
283
284        if column_def.spec.auto_increment {
285            //
286        }
287
288        if let Some(nullable) = column_def.spec.nullable {
289            write_comma_if_not_first!();
290            write!(sql, "ALTER COLUMN ").unwrap();
291            self.prepare_iden(&column_def.name, sql);
292            if nullable {
293                write!(sql, " DROP NOT NULL").unwrap();
294            } else {
295                write!(sql, " SET NOT NULL").unwrap();
296            }
297        }
298
299        if let Some(default) = &column_def.spec.default {
300            write_comma_if_not_first!();
301            write!(sql, "ALTER COLUMN ").unwrap();
302            self.prepare_iden(&column_def.name, sql);
303            write!(sql, " SET DEFAULT ").unwrap();
304            QueryBuilder::prepare_expr(self, default, sql);
305        }
306        if column_def.spec.unique {
307            write_comma_if_not_first!();
308            write!(sql, "ADD UNIQUE (").unwrap();
309            self.prepare_iden(&column_def.name, sql);
310            write!(sql, ")").unwrap();
311        }
312        if column_def.spec.primary_key {
313            write_comma_if_not_first!();
314            write!(sql, "ADD PRIMARY KEY (").unwrap();
315            self.prepare_iden(&column_def.name, sql);
316            write!(sql, ")").unwrap();
317        }
318        if let Some(check) = &column_def.spec.check {
319            write_comma_if_not_first!();
320            self.prepare_check_constraint(check, sql);
321        }
322
323        if let Some(x) = &column_def.spec.generated {
324            let _ = x;
325        }
326
327        if let Some(x) = &column_def.spec.comment {
328            let _ = x;
329        }
330
331        if let Some(expr) = &column_def.spec.using {
332            write!(sql, " USING ").unwrap();
333            QueryBuilder::prepare_expr(self, expr, sql);
334        }
335
336        if let Some(extra) = &column_def.spec.extra {
337            write!(sql, "{extra}").unwrap()
338        }
339
340        let _ = is_first;
341    }
342}