sea_query/backend/postgres/
index.rs

1use super::*;
2
3impl IndexBuilder for PostgresQueryBuilder {
4    // Overriden due to different "NULLS NOT UNIQUE" position in table index expression
5    // (as opposed to the regular index expression)
6    fn prepare_table_index_expression(
7        &self,
8        create: &IndexCreateStatement,
9        sql: &mut impl SqlWriter,
10    ) {
11        if let Some(name) = &create.index.name {
12            sql.write_str("CONSTRAINT ").unwrap();
13            sql.write_char(self.quote().left()).unwrap();
14            sql.write_str(name).unwrap();
15            sql.write_char(self.quote().right()).unwrap();
16            sql.write_str(" ").unwrap();
17        }
18
19        self.prepare_index_prefix(create, sql);
20
21        if create.nulls_not_distinct {
22            sql.write_str("NULLS NOT DISTINCT ").unwrap();
23        }
24
25        self.prepare_index_columns(&create.index.columns, sql);
26
27        if !create.include_columns.is_empty() {
28            sql.write_str(" ").unwrap();
29            self.prepare_include_columns(&create.include_columns, sql);
30        }
31    }
32
33    fn prepare_index_create_statement(
34        &self,
35        create: &IndexCreateStatement,
36        sql: &mut impl SqlWriter,
37    ) {
38        sql.write_str("CREATE ").unwrap();
39        self.prepare_index_prefix(create, sql);
40        sql.write_str("INDEX ").unwrap();
41
42        if create.concurrently {
43            write!(sql, "CONCURRENTLY ").unwrap();
44        }
45
46        if create.if_not_exists {
47            sql.write_str("IF NOT EXISTS ").unwrap();
48        }
49
50        if let Some(name) = &create.index.name {
51            sql.write_char(self.quote().left()).unwrap();
52            sql.write_str(name).unwrap();
53            sql.write_char(self.quote().right()).unwrap();
54        }
55
56        sql.write_str(" ON ").unwrap();
57        if let Some(table) = &create.table {
58            self.prepare_table_ref_index_stmt(table, sql);
59        }
60
61        self.prepare_index_type(&create.index_type, sql);
62        sql.write_str(" ").unwrap();
63        self.prepare_index_columns(&create.index.columns, sql);
64
65        if !create.include_columns.is_empty() {
66            sql.write_str(" ").unwrap();
67            self.prepare_include_columns(&create.include_columns, sql);
68        }
69
70        if create.nulls_not_distinct {
71            sql.write_str(" NULLS NOT DISTINCT").unwrap();
72        }
73        self.prepare_filter(&create.r#where, sql);
74    }
75
76    fn prepare_table_ref_index_stmt(&self, table_ref: &TableRef, sql: &mut impl SqlWriter) {
77        // Support only `table` and `schema.table` forms.
78        // No `database.schema.table` or aliases.
79        let TableRef::Table(table_name, None) = table_ref else {
80            panic!("Not supported");
81        };
82        match table_name.as_iden_tuple() {
83            (Some(_db), _schema, _table) => panic!("Not supported"),
84            (None, _schema, _table) => self.prepare_table_ref_iden(table_ref, sql),
85        }
86    }
87
88    fn prepare_index_drop_statement(&self, drop: &IndexDropStatement, sql: &mut impl SqlWriter) {
89        sql.write_str("DROP INDEX ").unwrap();
90
91        if drop.concurrently {
92            write!(sql, "CONCURRENTLY ").unwrap();
93        }
94
95        if drop.if_exists {
96            sql.write_str("IF EXISTS ").unwrap();
97        }
98
99        if let Some(table) = &drop.table {
100            // Support only `table` and `schema.table` forms.
101            // No `database.schema.table` or aliases.
102            let TableRef::Table(table_name, None) = table else {
103                panic!("Not supported");
104            };
105            match table_name.as_iden_tuple() {
106                (None, None, _table) => {}
107                (None, Some(schema), _table) => {
108                    self.prepare_iden(schema, sql);
109                    sql.write_str(".").unwrap();
110                }
111                (Some(_db), _schema, _table) => panic!("Not supported"),
112            }
113        }
114        if let Some(name) = &drop.index.name {
115            sql.write_char(self.quote().left()).unwrap();
116            sql.write_str(name).unwrap();
117            sql.write_char(self.quote().right()).unwrap();
118        }
119    }
120
121    fn prepare_index_type(&self, col_index_type: &Option<IndexType>, sql: &mut impl SqlWriter) {
122        if let Some(index_type) = col_index_type {
123            sql.write_str(" USING ").unwrap();
124            match index_type {
125                IndexType::BTree => sql.write_str("BTREE"),
126                IndexType::FullText => sql.write_str("GIN"),
127                IndexType::Hash => sql.write_str("HASH"),
128                IndexType::Custom(custom) => sql.write_str(&custom.0),
129            }
130            .unwrap()
131        }
132    }
133
134    fn prepare_index_prefix(&self, create: &IndexCreateStatement, sql: &mut impl SqlWriter) {
135        if create.primary {
136            sql.write_str("PRIMARY KEY ").unwrap();
137        }
138        if create.unique {
139            sql.write_str("UNIQUE ").unwrap();
140        }
141    }
142
143    fn prepare_index_columns(&self, columns: &[IndexColumn], sql: &mut impl SqlWriter) {
144        sql.write_str("(").unwrap();
145
146        let mut cols = columns.iter();
147        join_io!(
148            cols,
149            col,
150            join {
151                sql.write_str(", ").unwrap();
152            },
153            do {
154                match col {
155                    IndexColumn::TableColumn(column) => {
156                        self.prepare_index_column_with_table_column(column, sql);
157                    }
158                    IndexColumn::Expr(column) => {
159                        sql.write_str("(").unwrap();
160                        self.prepare_expr(&column.expr, sql);
161                        sql.write_str(")").unwrap();
162                        if let Some(order) = &column.order {
163                            match order {
164                                IndexOrder::Asc => sql.write_str(" ASC").unwrap(),
165                                IndexOrder::Desc => sql.write_str(" DESC").unwrap(),
166                            }
167                        }
168                    }
169                }
170            }
171        );
172
173        sql.write_str(")").unwrap();
174    }
175
176    fn prepare_filter(&self, condition: &ConditionHolder, sql: &mut impl SqlWriter) {
177        self.prepare_condition(condition, "WHERE", sql);
178    }
179}
180
181impl PostgresQueryBuilder {
182    fn prepare_include_columns(&self, columns: &[DynIden], sql: &mut impl SqlWriter) {
183        sql.write_str("INCLUDE (").unwrap();
184
185        let mut cols = columns.iter();
186        join_io!(
187            cols,
188            col,
189            join {
190                sql.write_str(", ").unwrap();
191            },
192            do {
193                self.prepare_iden(col, sql);
194            }
195        );
196
197        sql.write_str(")").unwrap();
198    }
199}