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