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
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
#[cfg(feature = "with-serde")]
use serde::{Deserialize, Serialize};

#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "with-serde", derive(Serialize, Deserialize))]
/// All built-in types of PostgreSQL, excluding synonyms
pub enum Type {
    // Numeric types
    /// 16 bit integer
    SmallInt,
    /// 32 bit integer
    Integer,
    /// 64 bit integer
    BigInt,
    /// User-specified precision number
    Decimal(ArbitraryPrecisionNumericAttr),
    /// User-specified precision number
    Numeric(ArbitraryPrecisionNumericAttr),
    /// 32 bit floating-point
    Real,
    /// 64 bit floating-point
    DoublePrecision,
    /// 16 bit autoincrementing integer
    SmallSerial,
    /// 32 bit autoincrementing integer
    Serial,
    /// 64 bit autoincrementing integer
    BigSerial,

    /// Currency amount; 64 bits with a fractional precision determined by the database's lc_monetary
    /// setting
    Money,

    // Character types
    /// Variable-length character array with limit
    Varchar(StringAttr),
    /// Fixed-length character array; blank padded
    Char(StringAttr),
    /// Variable, unlimited length character array
    Text,

    /// Variable length binary string
    Bytea,

    // Date/Time types
    /// Date and time
    Timestamp(TimeAttr),
    TimestampWithTimeZone(TimeAttr),
    /// Date without time of day
    Date,
    /// Time without date
    Time(TimeAttr),
    TimeWithTimeZone(TimeAttr),
    /// Time interval
    Interval(IntervalAttr),

    /// One byte boolean value
    Boolean,

    // TODO:
    // /// A type comprised of a static, ordered set of values
    // Enum,

    // Geometric types
    /// Point on a plane
    Point,
    /// Infinite line
    Line,
    /// Finite line segment
    Lseg,
    /// Rectangular box
    Box,
    /// Closed or open path
    Path,
    /// Polygon (similar to a closed path)
    Polygon,
    /// Circle composed of a center point and radius
    Circle,

    // Network address types
    /// IPv4 and IPv6 networks
    Cidr,
    /// IPPv4 and IPv6 hosts and networks
    Inet,
    /// 6 byte MAC address
    MacAddr,
    /// 8 byte MAC address in EUI-64 format
    MacAddr8,

    /// Fixed length bit string
    Bit(BitAttr),

    // Text search types
    /// A sorted list of distincp lexemes which are words that have been normalized to merge different
    /// variants of the same word
    TsVector,
    /// A list of lexemes that are to be searched for, and can be combined using Boolean operators AND,
    /// OR, and NOT, as well as a phrase search operation
    TsQuery,

    /// A universally unique identifier as defined by RFC 4122, ISO 9834-8:2005, and related standards
    Uuid,

    /// XML data checked for well-formedness and with additonal support functions
    Xml,

    /// JSON data checked for validity and with additional functions
    Json,

    /// Variable-length multidimensional array
    Array,

    // TODO:
    // /// The structure of a row or record; a list of field names and types
    // Composite,

    // Range types
    /// Range of an integer
    Int4Range,
    /// Range of a bigint
    Int8Range,
    /// Range of a numeric
    NumRange,
    /// Range of a timestamp without time zone
    TsRange,
    /// Range of a timestamp with time zone
    TsTzRange,
    /// Range of a date
    DateRange,

    // TODO:
    // /// A user-defined data type that is based on another underlying type with optional constraints
    // /// that restrict valid values
    // Domain,

    // TODO: Object identifier types
    /// A log sequence number
    PgLsn,
    // TODO: Pseudo-types
    Unknown(String),
}

impl Type {
    // TODO: Support more types
    pub fn from_str(name: &str) -> Type {
        match name.to_lowercase().as_str() {
            "smallint" | "int2" => Type::SmallInt,
            "integer" | "int" | "int4" => Type::Integer,
            "bigint" | "int8" => Type::BigInt,
            "decimal" => Type::Decimal(ArbitraryPrecisionNumericAttr::default()),
            "numeric" => Type::Numeric(ArbitraryPrecisionNumericAttr::default()),
            "real" | "float4" => Type::Real,
            "double precision" | "double" | "float8" => Type::DoublePrecision,
            "smallserial" | "serial2" => Type::SmallSerial,
            "serial" | "serial4" => Type::Serial,
            "bigserial" | "serial8" => Type::BigSerial,
            "money" => Type::Money,
            "character varying" | "varchar" => Type::Varchar(StringAttr::default()),
            "character" | "char" => Type::Char(StringAttr::default()),
            "text" => Type::Text,
            "bytea" => Type::Bytea,
            "timestamp" | "timestamp without time zone" => Type::Timestamp(TimeAttr::default()),
            "timestamp with time zone" => Type::TimestampWithTimeZone(TimeAttr::default()),
            "date" => Type::Date,
            "time" | "time without time zone" => Type::Time(TimeAttr::default()),
            "time with time zone" => Type::TimeWithTimeZone(TimeAttr::default()),
            "interval" => Type::Interval(IntervalAttr::default()),
            "boolean" => Type::Boolean,
            // "" => Type::Enum,
            "point" => Type::Point,
            "line" => Type::Line,
            "lseg" => Type::Lseg,
            "box" => Type::Box,
            "path" => Type::Path,
            "polygon" => Type::Polygon,
            "circle" => Type::Circle,
            "cidr" => Type::Cidr,
            "inet" => Type::Inet,
            "macaddr" => Type::MacAddr,
            "macaddr8" => Type::MacAddr8,
            "bit" => Type::Bit(BitAttr::default()),
            "tsvector" => Type::TsVector,
            "tsquery" => Type::TsQuery,
            "uuid" => Type::Uuid,
            "xml" => Type::Xml,
            "json" => Type::Json,
            "array" => Type::Array,
            // "" => Type::Composite,
            "int4range" => Type::Int4Range,
            "int8range" => Type::Int8Range,
            "numrange" => Type::NumRange,
            "tsrange" => Type::TsRange,
            "tstzrange" => Type::TsTzRange,
            "daterange" => Type::DateRange,
            // "" => Type::Domain,
            "pg_lsn" => Type::PgLsn,

            _ => Type::Unknown(name.to_owned()),
        }
    }
}

#[derive(Clone, Debug, PartialEq, Default)]
#[cfg_attr(feature = "with-serde", derive(Serialize, Deserialize))]
/// The precision (number of significan digits) and scale (the number of digits in the fractional
/// portion) of an arbitrary precision number (numeric or decimal). When both the precision and
/// scale are not set, any precision or scale up to the implementation limit may be stored.
pub struct ArbitraryPrecisionNumericAttr {
    /// The number of significant digits in the number; a maximum of 1000 when specified
    pub precision: Option<u16>,
    /// The count of decimal digits in the fractional part; integers have a scale of 0
    pub scale: Option<u16>,
}

#[derive(Clone, Debug, PartialEq, Default)]
#[cfg_attr(feature = "with-serde", derive(Serialize, Deserialize))]
pub struct StringAttr {
    pub length: Option<u16>,
}

#[derive(Clone, Debug, PartialEq, Default)]
#[cfg_attr(feature = "with-serde", derive(Serialize, Deserialize))]
pub struct TimeAttr {
    pub precision: Option<u16>,
}

#[derive(Clone, Debug, PartialEq, Default)]
#[cfg_attr(feature = "with-serde", derive(Serialize, Deserialize))]
pub struct IntervalAttr {
    pub field: Option<String>,
    pub precision: Option<u16>,
}

#[derive(Clone, Debug, PartialEq, Default)]
#[cfg_attr(feature = "with-serde", derive(Serialize, Deserialize))]
pub struct BitAttr {
    pub length: Option<u16>,
}

impl Type {
    pub fn has_numeric_attr(&self) -> bool {
        matches!(self, Type::Numeric(_) | Type::Decimal(_))
    }

    pub fn has_string_attr(&self) -> bool {
        matches!(self, Type::Varchar(_) | Type::Char(_))
    }

    pub fn has_time_attr(&self) -> bool {
        matches!(
            self,
            Type::Timestamp(_)
                | Type::TimestampWithTimeZone(_)
                | Type::Time(_)
                | Type::TimeWithTimeZone(_)
        )
    }

    pub fn has_interval_attr(&self) -> bool {
        matches!(self, Type::Interval(_))
    }

    pub fn has_bit_attr(&self) -> bool {
        matches!(self, Type::Bit(_))
    }
}