sea_schema/postgres/parser/
column.rs

1use crate::postgres::{
2    def::*, discovery::EnumVariantMap, parser::yes_or_no_to_bool, query::ColumnQueryResult,
3};
4use sea_query::RcOrArc;
5
6impl ColumnQueryResult {
7    pub fn parse(self, enums: &EnumVariantMap) -> ColumnInfo {
8        parse_column_query_result(self, enums)
9    }
10}
11
12pub fn parse_column_query_result(result: ColumnQueryResult, enums: &EnumVariantMap) -> ColumnInfo {
13    ColumnInfo {
14        name: result.column_name.clone(),
15        col_type: parse_column_type(&result, enums),
16        default: ColumnExpression::from_option_string(result.column_default),
17        generated: ColumnExpression::from_option_string(result.column_generated),
18        not_null: NotNull::from_bool(!yes_or_no_to_bool(&result.is_nullable)),
19        is_identity: yes_or_no_to_bool(&result.is_identity),
20    }
21}
22
23pub fn parse_column_type(result: &ColumnQueryResult, enums: &EnumVariantMap) -> ColumnType {
24    let is_enum = result
25        .udt_name
26        .as_ref()
27        .map_or(false, |udt_name| enums.contains_key(udt_name));
28    let mut ctype = Type::from_str(
29        result.column_type.as_str(),
30        result.udt_name.as_deref(),
31        is_enum,
32    );
33
34    if ctype.has_numeric_attr() {
35        ctype = parse_numeric_attributes(
36            result.numeric_precision,
37            result.numeric_precision_radix,
38            result.numeric_scale,
39            ctype,
40        );
41    }
42    if ctype.has_string_attr() {
43        ctype = parse_string_attributes(result.character_maximum_length, ctype);
44    }
45    if ctype.has_time_attr() {
46        ctype = parse_time_attributes(result.datetime_precision, ctype);
47    }
48    if ctype.has_interval_attr() {
49        ctype = parse_interval_attributes(&result.interval_type, result.interval_precision, ctype);
50    }
51    if ctype.has_bit_attr() {
52        ctype = parse_bit_attributes(result.character_maximum_length, ctype);
53    }
54    if ctype.has_enum_attr() {
55        ctype = parse_enum_attributes(result.udt_name.as_deref(), ctype, enums);
56    }
57    if ctype.has_array_attr() {
58        ctype = parse_array_attributes(result.udt_name_regtype.as_deref(), ctype, enums);
59    }
60    #[cfg(feature = "postgres-vector")]
61    if ctype.has_vector_attr() {
62        ctype = parse_vector_attributes(result.character_maximum_length, ctype);
63    }
64
65    ctype
66}
67
68pub fn parse_numeric_attributes(
69    num_precision: Option<i32>,
70    num_precision_radix: Option<i32>,
71    num_scale: Option<i32>,
72    mut ctype: ColumnType,
73) -> ColumnType {
74    let numeric_precision: Option<u16> = match num_precision {
75        None => None,
76        Some(num) => u16::try_from(num).ok(),
77    };
78    let _numeric_precision_radix: Option<u16> = match num_precision_radix {
79        None => None,
80        Some(num) => u16::try_from(num).ok(),
81    };
82    let numeric_scale: Option<u16> = match num_scale {
83        None => None,
84        Some(num) => u16::try_from(num).ok(),
85    };
86
87    match ctype {
88        Type::Decimal(ref mut attr) | Type::Numeric(ref mut attr) => {
89            attr.precision = numeric_precision;
90            attr.scale = numeric_scale;
91        }
92        _ => panic!("parse_numeric_attributes(_) received a type other than Decimal or Numeric"),
93    };
94
95    ctype
96}
97
98pub fn parse_string_attributes(
99    character_maximum_length: Option<i32>,
100    mut ctype: ColumnType,
101) -> ColumnType {
102    match ctype {
103        Type::Varchar(ref mut attr) | Type::Char(ref mut attr) => {
104            attr.length = match character_maximum_length {
105                None => None,
106                Some(num) => u16::try_from(num).ok(),
107            };
108        }
109        _ => panic!("parse_string_attributes(_) received a type that does not have StringAttr"),
110    };
111
112    ctype
113}
114
115pub fn parse_time_attributes(datetime_precision: Option<i32>, mut ctype: ColumnType) -> ColumnType {
116    match ctype {
117        Type::Timestamp(ref mut attr)
118        | Type::TimestampWithTimeZone(ref mut attr)
119        | Type::Time(ref mut attr)
120        | Type::TimeWithTimeZone(ref mut attr) => {
121            attr.precision = match datetime_precision {
122                None => None,
123                Some(num) => u16::try_from(num).ok(),
124            };
125        }
126        _ => panic!("parse_time_attributes(_) received a type that does not have TimeAttr"),
127    };
128
129    ctype
130}
131
132pub fn parse_interval_attributes(
133    interval_type: &Option<String>,
134    interval_precision: Option<i32>,
135    mut ctype: ColumnType,
136) -> ColumnType {
137    match ctype {
138        Type::Interval(ref mut attr) => {
139            attr.field.clone_from(interval_type);
140            attr.precision = match interval_precision {
141                None => None,
142                Some(num) => u16::try_from(num).ok(),
143            };
144        }
145        _ => panic!("parse_interval_attributes(_) received a type that does not have IntervalAttr"),
146    };
147
148    ctype
149}
150
151pub fn parse_bit_attributes(
152    character_maximum_length: Option<i32>,
153    mut ctype: ColumnType,
154) -> ColumnType {
155    match ctype {
156        Type::Bit(ref mut attr) => {
157            attr.length = match character_maximum_length {
158                None => None,
159                Some(num) => u16::try_from(num).ok(),
160            };
161        }
162        Type::VarBit(ref mut attr) => {
163            attr.length = match character_maximum_length {
164                None => None,
165                Some(num) => u16::try_from(num).ok(),
166            };
167        }
168        _ => panic!("parse_bit_attributes(_) received a type that does not have BitAttr"),
169    };
170
171    ctype
172}
173
174pub fn parse_enum_attributes(
175    udt_name: Option<&str>,
176    mut ctype: ColumnType,
177    enums: &EnumVariantMap,
178) -> ColumnType {
179    match ctype {
180        Type::Enum(ref mut def) => {
181            def.typename = match udt_name {
182                None => panic!("parse_enum_attributes(_) received an empty udt_name"),
183                Some(typename) => typename.to_string(),
184            };
185            if let Some(variants) = enums.get(&def.typename) {
186                def.values.clone_from(variants);
187            }
188        }
189        _ => panic!("parse_enum_attributes(_) received a type that does not have EnumDef"),
190    };
191
192    ctype
193}
194
195pub fn parse_array_attributes(
196    udt_name_regtype: Option<&str>,
197    mut ctype: ColumnType,
198    enums: &EnumVariantMap,
199) -> ColumnType {
200    match ctype {
201        Type::Array(ref mut def) => {
202            def.col_type = match udt_name_regtype {
203                None => panic!("parse_array_attributes(_) received an empty udt_name_regtype"),
204                Some(typename) => {
205                    let typename = &typename.replacen('"', "", 2).replacen("[]", "", 1);
206                    let arr_col_type = if let Some(variants) = enums.get(typename) {
207                        Type::Enum(EnumDef {
208                            typename: typename.to_string(),
209                            values: variants.clone(),
210                        })
211                    } else {
212                        Type::from_str(typename, Some(typename), false)
213                    };
214                    Some(RcOrArc::new(arr_col_type))
215                }
216            };
217        }
218        _ => panic!("parse_array_attributes(_) received a type that does not have EnumDef"),
219    };
220
221    ctype
222}
223
224#[cfg(feature = "postgres-vector")]
225pub fn parse_vector_attributes(
226    character_maximum_length: Option<i32>,
227    mut ctype: ColumnType,
228) -> ColumnType {
229    match ctype {
230        Type::Vector(ref mut attr) => {
231            attr.length = match character_maximum_length {
232                None => None,
233                Some(num) => match u32::try_from(num) {
234                    Ok(num) => Some(num),
235                    Err(_) => None,
236                },
237            };
238        }
239        _ => panic!("parse_vector_attributes(_) received a type that does not have StringAttr"),
240    };
241
242    ctype
243}