Skip to main content

sea_schema/postgres/query/
column.rs

1use super::{InformationSchema, SchemaQueryBuilder};
2use crate::sqlx_types::SqlxRow;
3use sea_query::{BinOper, DynIden, Expr, ExprTrait, Iden, Query, SelectStatement};
4
5#[derive(Debug, sea_query::Iden)]
6/// Ref: https://www.postgresql.org/docs/13/infoschema-columns.html
7pub enum ColumnsField {
8    TableCatalog,
9    TableSchema,
10    TableName,
11    ColumnName,
12    OrdinalPosition,
13    ColumnDefault,
14    IsNullable,
15    DataType,
16    CharacterMaximumLength,
17    CharacterOctetLength,
18    NumericPrecision,
19    NumericPrecisionRadix,
20    NumericScale,
21    DatetimePrecision,
22    IntervalType,
23    IntervalPrecision,
24    CollationCatalog,
25    CollationSchema,
26    CollationName,
27    DomainCatalog,
28    DomainSchema,
29    DomainName,
30    UdtCatalog,
31    UdtSchema,
32    UdtName,
33    DtdIdentifier,
34    IsIdentity,
35    IdentityGeneration,
36    IdentityStart,
37    IdentityIncrement,
38    IdentityMaximum,
39    IdentityMinimum,
40    IdentityCycle,
41    IsGenerated,
42    GenerationExpression,
43    IsUpdatable,
44}
45
46#[derive(Debug, Default)]
47pub struct ColumnQueryResult {
48    pub column_name: String,
49    pub column_type: String,
50    pub column_default: Option<String>,
51    pub column_generated: Option<String>,
52    pub is_nullable: String,
53    pub is_identity: String,
54
55    // Declared or implicit parameters of numeric types; null for other data types
56    pub numeric_precision: Option<i32>,
57    pub numeric_precision_radix: Option<i32>,
58    pub numeric_scale: Option<i32>,
59
60    pub character_maximum_length: Option<i32>,
61    pub character_octet_length: Option<i32>,
62
63    pub datetime_precision: Option<i32>,
64
65    pub interval_type: Option<String>,
66    pub interval_precision: Option<i32>,
67
68    pub udt_name: Option<String>,
69    pub udt_name_regtype: Option<String>,
70}
71
72impl SchemaQueryBuilder {
73    pub fn query_columns(&self, schema: DynIden, table: DynIden) -> SelectStatement {
74        Query::select()
75            .columns([
76                ColumnsField::ColumnName,
77                ColumnsField::DataType,
78                ColumnsField::ColumnDefault,
79                ColumnsField::GenerationExpression,
80                ColumnsField::IsNullable,
81                ColumnsField::IsIdentity,
82                ColumnsField::NumericPrecision,
83                ColumnsField::NumericPrecisionRadix,
84                ColumnsField::NumericScale,
85                ColumnsField::CharacterMaximumLength,
86                ColumnsField::CharacterOctetLength,
87                ColumnsField::DatetimePrecision,
88                ColumnsField::IntervalType,
89                ColumnsField::IntervalPrecision,
90                ColumnsField::UdtName,
91            ])
92            .expr(
93                // The double quotes are required to correctly handle user types containing
94                // upper case letters.
95                Expr::expr(Expr::cust("CONCAT('\"', udt_name, '\"')::regtype").cast_as(Text))
96                    .binary(BinOper::As, Expr::col(UdtNameRegtype)),
97            )
98            .from((InformationSchema::Schema, InformationSchema::Columns))
99            .and_where(Expr::col(ColumnsField::TableSchema).eq(schema.to_string()))
100            .and_where(Expr::col(ColumnsField::TableName).eq(table.to_string()))
101            .take()
102    }
103}
104
105#[cfg(feature = "sqlx-postgres")]
106impl From<SqlxRow> for ColumnQueryResult {
107    fn from(row: SqlxRow) -> Self {
108        use crate::sqlx_types::Row;
109        let row = row.postgres();
110        Self {
111            column_name: row.get(0),
112            column_type: row.get(1),
113            column_default: row.get(2),
114            column_generated: row.get(3),
115            is_nullable: row.get(4),
116            is_identity: row.get(5),
117            numeric_precision: row.get(6),
118            numeric_precision_radix: row.get(7),
119            numeric_scale: row.get(8),
120            character_maximum_length: row.get(9),
121            character_octet_length: row.get(10),
122            datetime_precision: row.get(11),
123            interval_type: row.get(12),
124            interval_precision: row.get(13),
125            udt_name: row.get(14),
126            udt_name_regtype: row.get(15),
127        }
128    }
129}
130
131#[cfg(not(feature = "sqlx-postgres"))]
132impl From<SqlxRow> for ColumnQueryResult {
133    fn from(_: SqlxRow) -> Self {
134        Self::default()
135    }
136}
137
138#[derive(Iden)]
139struct Text;
140#[derive(Iden)]
141struct UdtNameRegtype;