sea_schema/postgres/query/
pg_indexes.rs1use super::SchemaQueryBuilder;
2use crate::sqlx_types::SqlxRow;
3use sea_query::{
4 Condition, DynIden, Expr, ExprTrait, Iden, JoinType, Order, Query, SelectStatement,
5};
6
7#[derive(Debug, Iden)]
8pub enum PgIndexes {
9 Table,
10 #[iden = "tablename"]
11 TableName,
12 #[iden = "schemaname"]
13 SchemaName,
14 #[iden = "indexname"]
15 IndexName,
16}
17
18#[derive(Debug, Iden)]
19pub enum PgIndex {
20 Table,
21 #[iden = "indexrelid"]
22 IndexRelId,
23 #[iden = "indrelid"]
24 IndRelId,
25 #[iden = "indisunique"]
26 IndIsUnique,
27 #[iden = "indisprimary"]
28 IndIsPrimary,
29 #[iden = "indpred"]
30 IndPred,
31 #[iden = "indkey"]
32 IndKey,
33}
34
35#[derive(Debug, Iden)]
36pub enum PgClass {
37 Table,
38 Oid,
39 #[iden = "relnamespace"]
40 RelNamespace,
41 #[iden = "relname"]
42 RelName,
43}
44
45#[derive(Debug, Iden)]
46pub enum PgNamespace {
47 Table,
48 Oid,
49 #[iden = "nspname"]
50 NspName,
51}
52
53#[derive(Debug, Iden)]
54pub enum PgAttribute {
55 Table,
56 Oid,
57 #[iden = "attrelid"]
58 AttRelId,
59 #[iden = "attname"]
60 AttName,
61 #[iden = "attnum"]
62 AttNum,
63}
64
65#[derive(Debug, Default)]
66pub struct UniqueIndexQueryResult {
67 pub index_name: String,
68 pub table_schema: String,
69 pub table_name: String,
70 pub column_name: String,
71 pub is_partial: bool,
72}
73
74impl SchemaQueryBuilder {
75 pub fn query_table_unique_indexes(&self, schema: DynIden, table: DynIden) -> SelectStatement {
76 let idx = "idx";
77 let insp = "insp";
78 let tbl = "tbl";
79 let tnsp = "tnsp";
80 let col = "col";
81 let partially = "partially";
82
83 Query::select()
84 .column((idx, PgClass::RelName))
85 .column((insp, PgNamespace::NspName))
86 .column((tbl, PgClass::RelName))
87 .column((col, PgAttribute::AttName))
88 .expr_as(Expr::col(PgIndex::IndPred).is_not_null(), partially)
89 .from(PgIndex::Table)
90 .join_as(
91 JoinType::Join,
92 PgClass::Table,
93 idx,
94 Expr::col((idx, PgClass::Oid)).equals((PgIndex::Table, PgIndex::IndexRelId)),
95 )
96 .join_as(
97 JoinType::Join,
98 PgNamespace::Table,
99 insp,
100 Expr::col((insp, PgNamespace::Oid)).equals((idx, PgClass::RelNamespace)),
101 )
102 .join_as(
103 JoinType::Join,
104 PgClass::Table,
105 tbl,
106 Expr::col((tbl, PgClass::Oid)).equals((PgIndex::Table, PgIndex::IndRelId)),
107 )
108 .join_as(
109 JoinType::Join,
110 PgNamespace::Table,
111 tnsp,
112 Expr::col((tnsp, PgNamespace::Oid)).equals((tbl, PgClass::RelNamespace)),
113 )
114 .join_as(
115 JoinType::Join,
116 PgAttribute::Table,
117 col,
118 Expr::col((col, PgAttribute::AttRelId)).equals((tbl, PgAttribute::Oid)),
119 )
120 .join_lateral(
121 JoinType::Join,
122 Query::select()
123 .expr_as(
124 Expr::cust("generate_subscripts(pg_index.indkey, 1)"),
125 "subscript",
126 )
127 .take(),
128 "sub",
129 Expr::col((col, PgAttribute::AttNum))
130 .eq(Expr::cust("pg_index.indkey[sub.subscript]")),
131 )
132 .cond_where(
133 Condition::all()
134 .add(Expr::col((PgIndex::Table, PgIndex::IndIsUnique)).eq(true))
135 .add(Expr::col((PgIndex::Table, PgIndex::IndIsPrimary)).eq(false))
136 .add(Expr::col((tbl, PgClass::RelName)).eq(table.to_string()))
137 .add(Expr::col((tnsp, PgNamespace::NspName)).eq(schema.to_string())),
138 )
139 .order_by((PgIndex::Table, PgIndex::IndexRelId), Order::Asc)
140 .order_by(("sub", "subscript"), Order::Asc)
141 .take()
142 }
143}
144
145#[cfg(feature = "sqlx-postgres")]
146impl From<SqlxRow> for UniqueIndexQueryResult {
147 fn from(row: SqlxRow) -> Self {
148 use crate::sqlx_types::Row;
149 let row = row.postgres();
150 Self {
151 index_name: row.get(0),
152 table_schema: row.get(1),
153 table_name: row.get(2),
154 column_name: row.get(3),
155 is_partial: row.get(4),
156 }
157 }
158}
159
160#[cfg(not(feature = "sqlx-postgres"))]
161impl From<SqlxRow> for UniqueIndexQueryResult {
162 fn from(_: SqlxRow) -> Self {
163 Self::default()
164 }
165}