drizzle_types/postgres/sql_type.rs
1//! `PostgreSQL` column type definitions
2//!
3//! Defines the core `PostgreSQL` data types for schema definition.
4
5#[cfg(feature = "serde")]
6use crate::alloc_prelude::String;
7
8/// Enum representing supported `PostgreSQL` column types.
9///
10/// These correspond to `PostgreSQL` data types.
11/// See: <https://www.postgresql.org/docs/current/datatype.html>
12///
13/// # Examples
14///
15/// ```
16/// use drizzle_types::postgres::PostgreSQLType;
17///
18/// let int_type = PostgreSQLType::Integer;
19/// assert_eq!(int_type.to_sql_type(), "INTEGER");
20///
21/// let serial = PostgreSQLType::Serial;
22/// assert!(serial.is_serial());
23/// ```
24#[derive(Default, Debug, Clone, PartialEq, Eq, Hash)]
25#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
26pub enum PostgreSQLType {
27 /// `PostgreSQL` INTEGER type - 32-bit signed integer
28 ///
29 /// See: <https://www.postgresql.org/docs/current/datatype-numeric.html#DATATYPE-INT>
30 Integer,
31
32 /// `PostgreSQL` BIGINT type - 64-bit signed integer
33 ///
34 /// See: <https://www.postgresql.org/docs/current/datatype-numeric.html#DATATYPE-INT>
35 Bigint,
36
37 /// `PostgreSQL` SMALLINT type - 16-bit signed integer
38 ///
39 /// See: <https://www.postgresql.org/docs/current/datatype-numeric.html#DATATYPE-INT>
40 Smallint,
41
42 /// `PostgreSQL` SERIAL type - auto-incrementing 32-bit integer
43 ///
44 /// See: <https://www.postgresql.org/docs/current/datatype-numeric.html#DATATYPE-SERIAL>
45 Serial,
46
47 /// `PostgreSQL` SMALLSERIAL type - auto-incrementing 16-bit integer
48 ///
49 /// See: <https://www.postgresql.org/docs/current/datatype-numeric.html#DATATYPE-SERIAL>
50 Smallserial,
51
52 /// `PostgreSQL` BIGSERIAL type - auto-incrementing 64-bit integer
53 ///
54 /// See: <https://www.postgresql.org/docs/current/datatype-numeric.html#DATATYPE-SERIAL>
55 Bigserial,
56
57 /// `PostgreSQL` TEXT type - variable-length character string
58 ///
59 /// See: <https://www.postgresql.org/docs/current/datatype-character.html>
60 #[default]
61 Text,
62
63 /// `PostgreSQL` VARCHAR type - variable-length character string with limit
64 ///
65 /// See: <https://www.postgresql.org/docs/current/datatype-character.html>
66 Varchar,
67
68 /// `PostgreSQL` CHAR type - fixed-length character string
69 ///
70 /// See: <https://www.postgresql.org/docs/current/datatype-character.html>
71 Char,
72
73 /// `PostgreSQL` REAL type - single precision floating-point number
74 ///
75 /// See: <https://www.postgresql.org/docs/current/datatype-numeric.html#DATATYPE-FLOAT>
76 Real,
77
78 /// `PostgreSQL` DOUBLE PRECISION type - double precision floating-point number
79 ///
80 /// See: <https://www.postgresql.org/docs/current/datatype-numeric.html#DATATYPE-FLOAT>
81 DoublePrecision,
82
83 /// `PostgreSQL` NUMERIC type - exact numeric with selectable precision
84 ///
85 /// See: <https://www.postgresql.org/docs/current/datatype-numeric.html#DATATYPE-NUMERIC-DECIMAL>
86 Numeric,
87
88 /// `PostgreSQL` BOOLEAN type - true/false
89 ///
90 /// See: <https://www.postgresql.org/docs/current/datatype-boolean.html>
91 Boolean,
92
93 /// `PostgreSQL` BYTEA type - binary data
94 ///
95 /// See: <https://www.postgresql.org/docs/current/datatype-binary.html>
96 Bytea,
97
98 /// `PostgreSQL` UUID type - universally unique identifier
99 ///
100 /// See: <https://www.postgresql.org/docs/current/datatype-uuid.html>
101 #[cfg(feature = "uuid")]
102 Uuid,
103
104 /// `PostgreSQL` JSON type - JSON data
105 ///
106 /// See: <https://www.postgresql.org/docs/current/datatype-json.html>
107 #[cfg(feature = "serde")]
108 Json,
109
110 /// `PostgreSQL` JSONB type - binary JSON data
111 ///
112 /// See: <https://www.postgresql.org/docs/current/datatype-json.html>
113 #[cfg(feature = "serde")]
114 Jsonb,
115
116 /// `PostgreSQL` TIMESTAMP type - date and time
117 ///
118 /// See: <https://www.postgresql.org/docs/current/datatype-datetime.html>
119 Timestamp,
120
121 /// `PostgreSQL` TIMESTAMPTZ type - date and time with time zone
122 ///
123 /// See: <https://www.postgresql.org/docs/current/datatype-datetime.html>
124 Timestamptz,
125
126 /// `PostgreSQL` DATE type - calendar date
127 ///
128 /// See: <https://www.postgresql.org/docs/current/datatype-datetime.html>
129 Date,
130
131 /// `PostgreSQL` TIME type - time of day
132 ///
133 /// See: <https://www.postgresql.org/docs/current/datatype-datetime.html>
134 Time,
135
136 /// `PostgreSQL` TIMETZ type - time of day with time zone
137 ///
138 /// See: <https://www.postgresql.org/docs/current/datatype-datetime.html>
139 Timetz,
140
141 /// `PostgreSQL` INTERVAL type - time interval
142 ///
143 /// See: <https://www.postgresql.org/docs/current/datatype-datetime.html>
144 #[cfg(feature = "chrono")]
145 Interval,
146
147 /// `PostgreSQL` INET type - IPv4 or IPv6 host address
148 ///
149 /// See: <https://www.postgresql.org/docs/current/datatype-net-types.html>
150 #[cfg(feature = "cidr")]
151 Inet,
152
153 /// `PostgreSQL` CIDR type - IPv4 or IPv6 network address
154 ///
155 /// See: <https://www.postgresql.org/docs/current/datatype-net-types.html>
156 #[cfg(feature = "cidr")]
157 Cidr,
158
159 /// `PostgreSQL` MACADDR type - MAC address
160 ///
161 /// See: <https://www.postgresql.org/docs/current/datatype-net-types.html>
162 #[cfg(feature = "cidr")]
163 MacAddr,
164
165 /// `PostgreSQL` MACADDR8 type - EUI-64 MAC address
166 ///
167 /// See: <https://www.postgresql.org/docs/current/datatype-net-types.html>
168 #[cfg(feature = "cidr")]
169 MacAddr8,
170
171 /// `PostgreSQL` POINT type - geometric point
172 ///
173 /// See: <https://www.postgresql.org/docs/current/datatype-geometric.html>
174 #[cfg(feature = "geo-types")]
175 Point,
176
177 /// `PostgreSQL` LINE type - geometric line (infinite)
178 ///
179 /// See: <https://www.postgresql.org/docs/current/datatype-geometric.html>
180 #[cfg(feature = "geo-types")]
181 Line,
182
183 /// `PostgreSQL` LSEG type - geometric line segment
184 ///
185 /// See: <https://www.postgresql.org/docs/current/datatype-geometric.html>
186 #[cfg(feature = "geo-types")]
187 Lseg,
188
189 /// `PostgreSQL` BOX type - geometric box
190 ///
191 /// See: <https://www.postgresql.org/docs/current/datatype-geometric.html>
192 #[cfg(feature = "geo-types")]
193 Box,
194
195 /// `PostgreSQL` PATH type - geometric path
196 ///
197 /// See: <https://www.postgresql.org/docs/current/datatype-geometric.html>
198 #[cfg(feature = "geo-types")]
199 Path,
200
201 /// `PostgreSQL` POLYGON type - geometric polygon
202 ///
203 /// See: <https://www.postgresql.org/docs/current/datatype-geometric.html>
204 #[cfg(feature = "geo-types")]
205 Polygon,
206
207 /// `PostgreSQL` CIRCLE type - geometric circle
208 ///
209 /// See: <https://www.postgresql.org/docs/current/datatype-geometric.html>
210 #[cfg(feature = "geo-types")]
211 Circle,
212
213 /// `PostgreSQL` BIT type - fixed-length bit string
214 ///
215 /// See: <https://www.postgresql.org/docs/current/datatype-bit.html>
216 #[cfg(feature = "bit-vec")]
217 Bit,
218
219 /// `PostgreSQL` BIT VARYING type - variable-length bit string
220 ///
221 /// See: <https://www.postgresql.org/docs/current/datatype-bit.html>
222 #[cfg(feature = "bit-vec")]
223 Varbit,
224
225 /// `PostgreSQL` custom ENUM type - user-defined enumerated type
226 ///
227 /// See: <https://www.postgresql.org/docs/current/datatype-enum.html>
228 #[cfg(feature = "serde")]
229 Enum(String),
230}
231
232impl PostgreSQLType {
233 /// Convert from attribute name to enum variant
234 ///
235 /// For native enums, use [`Self::from_enum_attribute`] instead.
236 #[must_use]
237 pub fn from_attribute_name(name: &str) -> Option<Self> {
238 match name {
239 // Integer types and aliases
240 "integer" | "int" | "int4" => Some(Self::Integer),
241 "bigint" | "int8" => Some(Self::Bigint),
242 "smallint" | "int2" => Some(Self::Smallint),
243 "smallserial" | "serial2" => Some(Self::Smallserial),
244 "serial" | "serial4" => Some(Self::Serial),
245 "bigserial" | "serial8" => Some(Self::Bigserial),
246
247 // Text types and aliases
248 "text" => Some(Self::Text),
249 "varchar" | "character_varying" => Some(Self::Varchar),
250 "char" | "character" => Some(Self::Char),
251
252 // Float types and aliases
253 "real" | "float4" => Some(Self::Real),
254 "double_precision" | "float8" | "double" => Some(Self::DoublePrecision),
255 "numeric" | "decimal" => Some(Self::Numeric),
256
257 // Other basic types
258 "boolean" | "bool" => Some(Self::Boolean),
259 "bytea" => Some(Self::Bytea),
260
261 // UUID
262 #[cfg(feature = "uuid")]
263 "uuid" => Some(Self::Uuid),
264
265 // JSON types
266 #[cfg(feature = "serde")]
267 "json" => Some(Self::Json),
268 #[cfg(feature = "serde")]
269 "jsonb" => Some(Self::Jsonb),
270
271 // Date/time types and aliases
272 "timestamp" | "timestamp_without_time_zone" => Some(Self::Timestamp),
273 "timestamptz" | "timestamp_with_time_zone" => Some(Self::Timestamptz),
274 "date" => Some(Self::Date),
275 "time" | "time_without_time_zone" => Some(Self::Time),
276 "timetz" | "time_with_time_zone" => Some(Self::Timetz),
277 #[cfg(feature = "chrono")]
278 "interval" => Some(Self::Interval),
279
280 // Network address types
281 #[cfg(feature = "cidr")]
282 "inet" => Some(Self::Inet),
283 #[cfg(feature = "cidr")]
284 "cidr" => Some(Self::Cidr),
285 #[cfg(feature = "cidr")]
286 "macaddr" => Some(Self::MacAddr),
287 #[cfg(feature = "cidr")]
288 "macaddr8" => Some(Self::MacAddr8),
289
290 // Geometric types
291 #[cfg(feature = "geo-types")]
292 "point" => Some(Self::Point),
293 #[cfg(feature = "geo-types")]
294 "line" => Some(Self::Line),
295 #[cfg(feature = "geo-types")]
296 "lseg" => Some(Self::Lseg),
297 #[cfg(feature = "geo-types")]
298 "box" => Some(Self::Box),
299 #[cfg(feature = "geo-types")]
300 "path" => Some(Self::Path),
301 #[cfg(feature = "geo-types")]
302 "polygon" => Some(Self::Polygon),
303 #[cfg(feature = "geo-types")]
304 "circle" => Some(Self::Circle),
305
306 // Bit string types
307 #[cfg(feature = "bit-vec")]
308 "bit" => Some(Self::Bit),
309 #[cfg(feature = "bit-vec")]
310 "varbit" | "bit_varying" => Some(Self::Varbit),
311
312 "enum" => None, // enum() requires a parameter, handled separately
313 _ => None,
314 }
315 }
316
317 /// Create a native `PostgreSQL` enum type from enum attribute
318 ///
319 /// Used for `#[enum(MyEnum)]` syntax.
320 #[cfg(feature = "serde")]
321 #[must_use]
322 pub fn from_enum_attribute(enum_name: &str) -> Self {
323 Self::Enum(String::from(enum_name))
324 }
325
326 /// Get the SQL type string for this type
327 #[must_use]
328 pub const fn to_sql_type(&self) -> &str {
329 match self {
330 Self::Integer => "INTEGER",
331 Self::Bigint => "BIGINT",
332 Self::Smallint => "SMALLINT",
333 Self::Smallserial => "SMALLSERIAL",
334 Self::Serial => "SERIAL",
335 Self::Bigserial => "BIGSERIAL",
336 Self::Text => "TEXT",
337 Self::Varchar => "VARCHAR",
338 Self::Char => "CHAR",
339 Self::Real => "REAL",
340 Self::DoublePrecision => "DOUBLE PRECISION",
341 Self::Numeric => "NUMERIC",
342 Self::Boolean => "BOOLEAN",
343 Self::Bytea => "BYTEA",
344 #[cfg(feature = "uuid")]
345 Self::Uuid => "UUID",
346 #[cfg(feature = "serde")]
347 Self::Json => "JSON",
348 #[cfg(feature = "serde")]
349 Self::Jsonb => "JSONB",
350 Self::Timestamp => "TIMESTAMP",
351 Self::Timestamptz => "TIMESTAMPTZ",
352 Self::Date => "DATE",
353 Self::Time => "TIME",
354 Self::Timetz => "TIMETZ",
355 #[cfg(feature = "chrono")]
356 Self::Interval => "INTERVAL",
357 #[cfg(feature = "cidr")]
358 Self::Inet => "INET",
359 #[cfg(feature = "cidr")]
360 Self::Cidr => "CIDR",
361 #[cfg(feature = "cidr")]
362 Self::MacAddr => "MACADDR",
363 #[cfg(feature = "cidr")]
364 Self::MacAddr8 => "MACADDR8",
365 #[cfg(feature = "geo-types")]
366 Self::Point => "POINT",
367 #[cfg(feature = "geo-types")]
368 Self::Line => "LINE",
369 #[cfg(feature = "geo-types")]
370 Self::Lseg => "LSEG",
371 #[cfg(feature = "geo-types")]
372 Self::Box => "BOX",
373 #[cfg(feature = "geo-types")]
374 Self::Path => "PATH",
375 #[cfg(feature = "geo-types")]
376 Self::Polygon => "POLYGON",
377 #[cfg(feature = "geo-types")]
378 Self::Circle => "CIRCLE",
379 #[cfg(feature = "bit-vec")]
380 Self::Bit => "BIT",
381 #[cfg(feature = "bit-vec")]
382 Self::Varbit => "VARBIT",
383 #[cfg(feature = "serde")]
384 Self::Enum(name) => name.as_str(), // Custom enum type name
385 }
386 }
387
388 /// Check if this type is an auto-incrementing type
389 #[must_use]
390 pub const fn is_serial(&self) -> bool {
391 matches!(self, Self::Smallserial | Self::Serial | Self::Bigserial)
392 }
393
394 /// Check if this type supports primary keys
395 #[must_use]
396 pub const fn supports_primary_key(&self) -> bool {
397 core::cfg_select! {
398 feature = "serde" => !matches!(self, Self::Json | Self::Jsonb),
399 _ => true,
400 }
401 }
402
403 /// Check if a flag is valid for this column type
404 #[must_use]
405 pub fn is_valid_flag(&self, flag: &str) -> bool {
406 match (self, flag) {
407 (Self::Smallserial | Self::Serial | Self::Bigserial, "identity") => true,
408 (Self::Text | Self::Bytea, "json") => true,
409 #[cfg(feature = "serde")]
410 (Self::Json | Self::Jsonb, "json") => true,
411 (Self::Text | Self::Integer | Self::Smallint | Self::Bigint, "enum") => true,
412 #[cfg(feature = "serde")]
413 (Self::Enum(_), "enum") => true,
414 (_, "primary" | "primary_key" | "unique" | "not_null" | "check") => true,
415 _ => false,
416 }
417 }
418}
419
420impl core::fmt::Display for PostgreSQLType {
421 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
422 f.write_str(self.to_sql_type())
423 }
424}
425
426#[cfg(test)]
427mod tests {
428 use super::*;
429
430 #[test]
431 fn test_from_attribute_name() {
432 assert_eq!(
433 PostgreSQLType::from_attribute_name("integer"),
434 Some(PostgreSQLType::Integer)
435 );
436 assert_eq!(
437 PostgreSQLType::from_attribute_name("int"),
438 Some(PostgreSQLType::Integer)
439 );
440 assert_eq!(
441 PostgreSQLType::from_attribute_name("text"),
442 Some(PostgreSQLType::Text)
443 );
444 assert_eq!(
445 PostgreSQLType::from_attribute_name("varchar"),
446 Some(PostgreSQLType::Varchar)
447 );
448 assert_eq!(
449 PostgreSQLType::from_attribute_name("serial"),
450 Some(PostgreSQLType::Serial)
451 );
452 assert_eq!(
453 PostgreSQLType::from_attribute_name("smallserial"),
454 Some(PostgreSQLType::Smallserial)
455 );
456 assert_eq!(PostgreSQLType::from_attribute_name("unknown"), None);
457 }
458
459 #[test]
460 fn test_to_sql_type() {
461 assert_eq!(PostgreSQLType::Integer.to_sql_type(), "INTEGER");
462 assert_eq!(PostgreSQLType::Smallserial.to_sql_type(), "SMALLSERIAL");
463 assert_eq!(PostgreSQLType::Bigint.to_sql_type(), "BIGINT");
464 assert_eq!(PostgreSQLType::Text.to_sql_type(), "TEXT");
465 assert_eq!(
466 PostgreSQLType::DoublePrecision.to_sql_type(),
467 "DOUBLE PRECISION"
468 );
469 assert_eq!(PostgreSQLType::Boolean.to_sql_type(), "BOOLEAN");
470 }
471
472 #[test]
473 fn test_is_serial() {
474 assert!(PostgreSQLType::Smallserial.is_serial());
475 assert!(PostgreSQLType::Serial.is_serial());
476 assert!(PostgreSQLType::Bigserial.is_serial());
477 assert!(!PostgreSQLType::Integer.is_serial());
478 assert!(!PostgreSQLType::Text.is_serial());
479 }
480}