sea_schema/postgres/def/
types.rs

1use sea_query::RcOrArc;
2#[cfg(feature = "with-serde")]
3use serde::{Deserialize, Serialize};
4
5#[derive(Clone, Debug, PartialEq)]
6#[cfg_attr(feature = "with-serde", derive(Serialize, Deserialize))]
7/// All built-in types of PostgreSQL, excluding synonyms
8pub enum Type {
9    // Numeric types
10    /// 16 bit integer
11    SmallInt,
12    /// 32 bit integer
13    Integer,
14    /// 64 bit integer
15    BigInt,
16    /// User-specified precision number
17    Decimal(ArbitraryPrecisionNumericAttr),
18    /// User-specified precision number
19    Numeric(ArbitraryPrecisionNumericAttr),
20    /// 32 bit floating-point
21    Real,
22    /// 64 bit floating-point
23    DoublePrecision,
24    /// 16 bit autoincrementing integer
25    SmallSerial,
26    /// 32 bit autoincrementing integer
27    Serial,
28    /// 64 bit autoincrementing integer
29    BigSerial,
30
31    /// Currency amount; 64 bits with a fractional precision determined by the database's lc_monetary
32    /// setting
33    Money,
34
35    // Character types
36    /// Variable-length character array with limit
37    Varchar(StringAttr),
38    /// Fixed-length character array; blank padded
39    Char(StringAttr),
40    /// Variable, unlimited length character array
41    Text,
42
43    /// Variable length binary string
44    Bytea,
45
46    // Date/Time types
47    /// Date and time
48    Timestamp(TimeAttr),
49    TimestampWithTimeZone(TimeAttr),
50    /// Date without time of day
51    Date,
52    /// Time without date
53    Time(TimeAttr),
54    TimeWithTimeZone(TimeAttr),
55    /// Time interval
56    Interval(IntervalAttr),
57
58    /// One byte boolean value
59    Boolean,
60
61    // TODO:
62    // /// A type comprised of a static, ordered set of values
63    // Enum,
64
65    // Geometric types
66    /// Point on a plane
67    Point,
68    /// Infinite line
69    Line,
70    /// Finite line segment
71    Lseg,
72    /// Rectangular box
73    Box,
74    /// Closed or open path
75    Path,
76    /// Polygon (similar to a closed path)
77    Polygon,
78    /// Circle composed of a center point and radius
79    Circle,
80
81    // Network address types
82    /// IPv4 and IPv6 networks
83    Cidr,
84    /// IPPv4 and IPv6 hosts and networks
85    Inet,
86    /// 6 byte MAC address
87    MacAddr,
88    /// 8 byte MAC address in EUI-64 format
89    MacAddr8,
90
91    /// Fixed length bit string
92    Bit(BitAttr),
93
94    /// Variable length bit string
95    VarBit(BitAttr),
96
97    // Text search types
98    /// A sorted list of distinct lexemes which are words that have been normalized to merge different
99    /// variants of the same word
100    TsVector,
101    /// A list of lexemes that are to be searched for, and can be combined using Boolean operators AND,
102    /// OR, and NOT, as well as a phrase search operation
103    TsQuery,
104
105    /// A universally unique identifier as defined by RFC 4122, ISO 9834-8:2005, and related standards
106    Uuid,
107
108    /// XML data checked for well-formedness and with additional support functions
109    Xml,
110
111    /// JSON data checked for validity and with additional functions
112    Json,
113    /// JSON data stored in a decomposed binary format that can be subscripted and used in indexes
114    JsonBinary,
115
116    /// Variable-length multidimensional array
117    Array(ArrayDef),
118
119    #[cfg(feature = "postgres-vector")]
120    /// The postgres vector type introduced by the vector extension.
121    Vector(VectorDef),
122
123    // TODO:
124    // /// The structure of a row or record; a list of field names and types
125    // Composite,
126
127    // Range types
128    /// Range of an integer
129    Int4Range,
130    /// Range of a bigint
131    Int8Range,
132    /// Range of a numeric
133    NumRange,
134    /// Range of a timestamp without time zone
135    TsRange,
136    /// Range of a timestamp with time zone
137    TsTzRange,
138    /// Range of a date
139    DateRange,
140
141    // TODO:
142    // /// A user-defined data type that is based on another underlying type with optional constraints
143    // /// that restrict valid values
144    // Domain,
145
146    // TODO: Object identifier types
147    /// A log sequence number
148    PgLsn,
149    // TODO: Pseudo-types
150    Unknown(String),
151    /// Defines an PostgreSQL
152    Enum(EnumDef),
153}
154
155impl Type {
156    // TODO: Support more types
157    #[allow(clippy::should_implement_trait)]
158    pub fn from_str(column_type: &str, udt_name: Option<&str>, is_enum: bool) -> Type {
159        match column_type.to_lowercase().as_str() {
160            "smallint" | "int2" => Type::SmallInt,
161            "integer" | "int" | "int4" => Type::Integer,
162            "bigint" | "int8" => Type::BigInt,
163            "decimal" => Type::Decimal(ArbitraryPrecisionNumericAttr::default()),
164            "numeric" => Type::Numeric(ArbitraryPrecisionNumericAttr::default()),
165            "real" | "float4" => Type::Real,
166            "double precision" | "double" | "float8" => Type::DoublePrecision,
167            "smallserial" | "serial2" => Type::SmallSerial,
168            "serial" | "serial4" => Type::Serial,
169            "bigserial" | "serial8" => Type::BigSerial,
170            "money" => Type::Money,
171            "character varying" | "varchar" => Type::Varchar(StringAttr::default()),
172            "character" | "char" => Type::Char(StringAttr::default()),
173            "text" => Type::Text,
174            "bytea" => Type::Bytea,
175            "timestamp" | "timestamp without time zone" => Type::Timestamp(TimeAttr::default()),
176            "timestamp with time zone" => Type::TimestampWithTimeZone(TimeAttr::default()),
177            "date" => Type::Date,
178            "time" | "time without time zone" => Type::Time(TimeAttr::default()),
179            "time with time zone" => Type::TimeWithTimeZone(TimeAttr::default()),
180            "interval" => Type::Interval(IntervalAttr::default()),
181            "boolean" | "bool" => Type::Boolean,
182            "point" => Type::Point,
183            "line" => Type::Line,
184            "lseg" => Type::Lseg,
185            "box" => Type::Box,
186            "path" => Type::Path,
187            "polygon" => Type::Polygon,
188            "circle" => Type::Circle,
189            "cidr" => Type::Cidr,
190            "inet" => Type::Inet,
191            "macaddr" => Type::MacAddr,
192            "macaddr8" => Type::MacAddr8,
193            "bit" => Type::Bit(BitAttr::default()),
194            "bit varying" | "varbit" => Type::VarBit(BitAttr::default()),
195            "tsvector" => Type::TsVector,
196            "tsquery" => Type::TsQuery,
197            "uuid" => Type::Uuid,
198            "xml" => Type::Xml,
199            "json" => Type::Json,
200            "jsonb" => Type::JsonBinary,
201            // "" => Type::Composite,
202            "int4range" => Type::Int4Range,
203            "int8range" => Type::Int8Range,
204            "numrange" => Type::NumRange,
205            "tsrange" => Type::TsRange,
206            "tstzrange" => Type::TsTzRange,
207            "daterange" => Type::DateRange,
208            // "" => Type::Domain,
209            "pg_lsn" => Type::PgLsn,
210            "user-defined" => match (is_enum, udt_name) {
211                (true, _) => Type::Enum(EnumDef::default()),
212                #[cfg(feature = "postgres-vector")]
213                (false, Some("vector")) => Type::Vector(VectorDef::default()),
214                (false, Some(other_name)) => Type::Unknown(other_name.to_owned()),
215                _ => Type::Unknown("user-defined".to_owned()),
216            },
217            "array" => Type::Array(ArrayDef::default()),
218            _ => Type::Unknown(column_type.to_owned()),
219        }
220    }
221}
222
223#[derive(Clone, Debug, PartialEq, Default)]
224#[cfg_attr(feature = "with-serde", derive(Serialize, Deserialize))]
225/// The precision (number of significan digits) and scale (the number of digits in the fractional
226/// portion) of an arbitrary precision number (numeric or decimal). When both the precision and
227/// scale are not set, any precision or scale up to the implementation limit may be stored.
228pub struct ArbitraryPrecisionNumericAttr {
229    /// The number of significant digits in the number; a maximum of 1000 when specified
230    pub precision: Option<u16>,
231    /// The count of decimal digits in the fractional part; integers have a scale of 0
232    pub scale: Option<u16>,
233}
234
235#[derive(Clone, Debug, PartialEq, Default)]
236#[cfg_attr(feature = "with-serde", derive(Serialize, Deserialize))]
237pub struct StringAttr {
238    pub length: Option<u16>,
239}
240
241#[derive(Clone, Debug, PartialEq, Default)]
242#[cfg_attr(feature = "with-serde", derive(Serialize, Deserialize))]
243pub struct TimeAttr {
244    pub precision: Option<u16>,
245}
246
247#[derive(Clone, Debug, PartialEq, Default)]
248#[cfg_attr(feature = "with-serde", derive(Serialize, Deserialize))]
249pub struct IntervalAttr {
250    pub field: Option<String>,
251    pub precision: Option<u16>,
252}
253
254#[derive(Clone, Debug, PartialEq, Default)]
255#[cfg_attr(feature = "with-serde", derive(Serialize, Deserialize))]
256pub struct BitAttr {
257    pub length: Option<u16>,
258}
259
260/// Defines an enum for the PostgreSQL module
261#[derive(Clone, Debug, PartialEq, Default)]
262#[cfg_attr(feature = "with-serde", derive(Serialize, Deserialize))]
263pub struct EnumDef {
264    /// Holds the fields of the `ENUM`
265    pub values: Vec<String>,
266    /// Defines the name of the PostgreSQL enum identifier
267    pub typename: String,
268}
269
270/// Defines an enum for the PostgreSQL module
271#[derive(Clone, Debug, PartialEq, Default)]
272#[cfg_attr(feature = "with-serde", derive(Serialize, Deserialize))]
273pub struct ArrayDef {
274    /// Array type
275    pub col_type: Option<RcOrArc<Type>>,
276}
277
278#[cfg(feature = "postgres-vector")]
279/// Defines an enum for the PostgreSQL module
280#[derive(Clone, Debug, PartialEq, Default)]
281#[cfg_attr(feature = "with-serde", derive(Serialize, Deserialize))]
282pub struct VectorDef {
283    pub length: Option<u32>,
284}
285
286impl Type {
287    pub fn has_numeric_attr(&self) -> bool {
288        matches!(self, Type::Numeric(_) | Type::Decimal(_))
289    }
290
291    pub fn has_string_attr(&self) -> bool {
292        matches!(self, Type::Varchar(_) | Type::Char(_))
293    }
294
295    pub fn has_time_attr(&self) -> bool {
296        matches!(
297            self,
298            Type::Timestamp(_)
299                | Type::TimestampWithTimeZone(_)
300                | Type::Time(_)
301                | Type::TimeWithTimeZone(_)
302        )
303    }
304
305    pub fn has_interval_attr(&self) -> bool {
306        matches!(self, Type::Interval(_))
307    }
308
309    pub fn has_bit_attr(&self) -> bool {
310        matches!(self, Type::Bit(_) | Type::VarBit(_))
311    }
312
313    pub fn has_enum_attr(&self) -> bool {
314        matches!(self, Type::Enum(_))
315    }
316
317    pub fn has_array_attr(&self) -> bool {
318        matches!(self, Type::Array(_))
319    }
320
321    #[cfg(feature = "postgres-vector")]
322    pub fn has_vector_attr(&self) -> bool {
323        matches!(self, Type::Vector(_))
324    }
325}
326
327#[cfg(test)]
328mod tests {
329    use super::*;
330
331    #[test]
332    fn parses_user_defined_enum_and_vector() {
333        assert_eq!(
334            Type::from_str("user-defined", None, true),
335            Type::Enum(EnumDef::default())
336        );
337
338        #[cfg(feature = "postgres-vector")]
339        assert_eq!(
340            Type::from_str("user-defined", Some("vector"), false),
341            Type::Vector(VectorDef::default())
342        );
343
344        #[cfg(not(feature = "postgres-vector"))]
345        assert_eq!(
346            Type::from_str("user-defined", Some("vector"), false),
347            Type::Unknown("vector".into())
348        );
349
350        assert_eq!(
351            Type::from_str("user-defined", Some("foo_bar"), false),
352            Type::Unknown("foo_bar".into())
353        );
354    }
355}