1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
use crate::{
    parser::Parser,
    postgres::{
        def::*,
        parser::yes_or_no_to_bool,
        query::{constraints, ColumnQueryResult},
    },
    Name,
};

use std::convert::{TryFrom, TryInto};

impl ColumnQueryResult {
    pub fn parse(self) -> ColumnInfo {
        parse_column_query_result(self)
    }
}

pub fn parse_column_query_result(result: ColumnQueryResult) -> ColumnInfo {
    ColumnInfo {
        name: result.column_name.clone(),
        col_type: parse_column_type(&result),
        default: ColumnExpression::from_option_string(result.column_default),
        generated: ColumnExpression::from_option_string(result.column_generated),
        not_null: NotNull::from_bool(!yes_or_no_to_bool(&result.is_nullable)),
        is_identity: yes_or_no_to_bool(&result.is_identity),
    }
}

pub fn parse_column_type(result: &ColumnQueryResult) -> ColumnType {
    let mut ctype = Type::from_str(result.column_type.as_str());

    if ctype.has_numeric_attr() {
        ctype = parse_numeric_attributes(
            result.numeric_precision,
            result.numeric_precision_radix,
            result.numeric_scale,
            ctype,
        );
    }
    if ctype.has_string_attr() {
        ctype = parse_string_attributes(result.character_maximum_length, ctype);
    }
    if ctype.has_time_attr() {
        ctype = parse_time_attributes(result.datetime_precision, ctype);
    }
    if ctype.has_interval_attr() {
        ctype = parse_interval_attributes(&result.interval_type, result.interval_precision, ctype);
    }
    if ctype.has_bit_attr() {
        ctype = parse_bit_attributes(result.character_maximum_length, ctype);
    }

    ctype
}

pub fn parse_numeric_attributes(
    num_precision: Option<i32>,
    num_precision_radix: Option<i32>,
    num_scale: Option<i32>,
    mut ctype: ColumnType,
) -> ColumnType {
    let numeric_precision: Option<u16> = match num_precision {
        None => None,
        Some(num) => match u16::try_from(num) {
            Ok(num) => Some(num),
            Err(e) => None,
        },
    };
    let numeric_precision_radix: Option<u16> = match num_precision_radix {
        None => None,
        Some(num) => match u16::try_from(num) {
            Ok(num) => Some(num),
            Err(e) => None,
        },
    };
    let numeric_scale: Option<u16> = match num_scale {
        None => None,
        Some(num) => match u16::try_from(num) {
            Ok(num) => Some(num),
            Err(e) => None,
        },
    };

    match ctype {
        Type::Decimal(ref mut attr) | Type::Numeric(ref mut attr) => {
            attr.precision = numeric_precision;
            attr.scale = numeric_scale;
        }
        _ => panic!("parse_numeric_attributes(_) received a type other than Decimal or Numeric"),
    };

    ctype
}

pub fn parse_string_attributes(
    character_maximum_length: Option<i32>,
    mut ctype: ColumnType,
) -> ColumnType {
    match ctype {
        Type::Varchar(ref mut attr) | Type::Char(ref mut attr) => {
            attr.length = match character_maximum_length {
                None => None,
                Some(num) => match u16::try_from(num) {
                    Ok(num) => Some(num),
                    Err(e) => None,
                },
            };
        }
        _ => panic!("parse_string_attributes(_) received a type that does not have StringAttr"),
    };

    ctype
}

pub fn parse_time_attributes(datetime_precision: Option<i32>, mut ctype: ColumnType) -> ColumnType {
    match ctype {
        Type::Timestamp(ref mut attr)
        | Type::TimestampWithTimeZone(ref mut attr)
        | Type::Time(ref mut attr)
        | Type::TimeWithTimeZone(ref mut attr) => {
            attr.precision = match datetime_precision {
                None => None,
                Some(num) => match u16::try_from(num) {
                    Ok(num) => Some(num),
                    Err(e) => None,
                },
            };
        }
        _ => panic!("parse_time_attributes(_) received a type that does not have TimeAttr"),
    };

    ctype
}

pub fn parse_interval_attributes(
    interval_type: &Option<String>,
    interval_precision: Option<i32>,
    mut ctype: ColumnType,
) -> ColumnType {
    match ctype {
        Type::Interval(ref mut attr) => {
            attr.field = interval_type.clone();
            attr.precision = match interval_precision {
                None => None,
                Some(num) => match u16::try_from(num) {
                    Ok(num) => Some(num),
                    Err(e) => None,
                },
            };
        }
        _ => panic!("parse_interval_attributes(_) received a type that does not have IntervalAttr"),
    };

    ctype
}

pub fn parse_bit_attributes(
    character_maximum_length: Option<i32>,
    mut ctype: ColumnType,
) -> ColumnType {
    match ctype {
        Type::Bit(ref mut attr) => {
            attr.length = match character_maximum_length {
                None => None,
                Some(num) => match u16::try_from(num) {
                    Ok(num) => Some(num),
                    Err(e) => None,
                },
            };
        }
        _ => panic!("parse_bit_attributes(_) received a type that does not have BitAttr"),
    };

    ctype
}