sea_query/backend/postgres/
table.rs

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