1use crate::to_sql::{Dialect, ToSql};
2use anyhow::Result;
3use std::str::FromStr;
4
5use crate::util::SqlExtension;
6
7#[derive(Debug, Clone, PartialEq, Eq)]
8#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
9pub enum Type {
10 Boolean,
11 I16,
13 I32,
14 I64,
15 F32,
17 F64,
18 Decimal,
20 Numeric(u8, u8),
21 Bytes,
23 Time,
25 Date,
26 DateTime,
27 NaiveDateTime,
28 Duration,
29 Json,
31 Jsonb,
32 Uuid,
34 Text,
36 Array(Box<Type>),
38 Other(String),
39}
40
41impl Type {
42 pub fn lossy_eq(&self, other: &Type) -> bool {
43 use Type::*;
44 match (self, other) {
45 (Other(_), _) => true,
46 (a, b) => a == b,
47 }
48 }
49}
50
51impl FromStr for Type {
52 type Err = anyhow::Error;
53
54 fn from_str(s: &str) -> Result<Self> {
55 use Type::*;
56 let s = match s {
57 "numeric" => Decimal,
58 "bigint" => I64,
59 "int8" => I64,
60 "double precision" => F64,
61 "real" => F32,
62 "bool" => Boolean,
63 "boolean" => Boolean,
64 "date" => Date,
65 "bytea" => Bytes,
66 "timestamp with time zone" => DateTime,
67 "timestamp without time zone" => NaiveDateTime,
68 "interval" => Duration,
69 "json" => Json,
70 "jsonb" => Jsonb,
71 "uuid" => Uuid,
72 "smallint" => I16,
73 "text" => Text,
74 "character varying" => Text,
75 "varchar" => Text,
76 "integer" => I32,
77 "ARRAY" => panic!(
78 "Encountered `ARRAY` type when reading data schema from database. ARRAY must be handled separately."
79 ),
80 s => Other(s.to_string()),
81 };
82 Ok(s)
83 }
84}
85
86impl ToSql for Type {
87 fn write_sql(&self, buf: &mut String, dialect: Dialect) {
88 use self::Type::*;
89 let s = match self {
90 Boolean => "boolean",
91 I16 => "smallint",
92 I32 => "integer",
93 I64 => "bigint",
94 Bytes => "bytea",
95 Time => "time without time zone",
96 Date => "date",
97 DateTime => "timestamptz",
98 NaiveDateTime => "timestamp without time zone",
99 Duration => "interval",
100 Json => "json",
101 Jsonb => "jsonb",
102 F32 => "real",
103 F64 => "double precision",
104 Decimal => "numeric",
105 Numeric(p, s) => {
106 return buf.push_str(&format!("numeric({}, {})", p, s));
107 }
108 Uuid => "uuid",
109 Text => "character varying",
110 Array(inner) => {
111 buf.push_sql(inner.as_ref(), dialect);
112 if dialect == Dialect::Postgres {
113 buf.push_str("[]");
114 } else {
115 buf.push_str(" ARRAY")
116 }
117 return;
118 }
119 Other(z) => {
120 buf.push_str(z);
124 return;
126 }
127 };
128 buf.push_str(s);
129 }
130}
131
132#[cfg(test)]
133mod test {
134 use super::*;
135
136 #[test]
137 fn test_numeric() {
138 let s = "numeric";
139 let t = Type::from_str(s).unwrap();
140 assert_eq!(t, Type::Decimal);
141 }
142}