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
use std::str::FromStr;
use anyhow::{anyhow, Result};
use crate::to_sql::{Dialect, ToSql};
use lazy_static::lazy_static;
use regex::Regex;
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Type {
Boolean,
SmallInt,
BigInt,
Integer,
Float64,
Numeric(u8, u8),
Bytes,
Date,
DateTime,
NaiveDateTime,
Duration,
Json,
Jsonb,
Uuid,
Text,
}
impl FromStr for Type {
type Err = anyhow::Error;
fn from_str(s: &str) -> Result<Self> {
use Type::*;
if s.starts_with("numeric") {
println!("Parsing type: {}", s);
}
lazy_static! {
static ref NUMERIC_RE: Regex = Regex::new(r"numeric\((\d+),\s*(\d+)\)").unwrap();
}
let cap = NUMERIC_RE.captures(s);
if let Some(cap) = cap {
let p = cap.get(1).unwrap().as_str().parse()?;
let s = cap.get(2).unwrap().as_str().parse()?;
return Ok(Numeric(p, s));
}
let s = match s {
"bigint" => BigInt,
"boolean" => Boolean,
"date" => Date,
"bytea" => Bytes,
"timestamp with time zone" => DateTime,
"timestamp without time zone" => NaiveDateTime,
"interval" => Duration,
"json" => Json,
"jsonb" => Jsonb,
"numeric" => Float64,
"uuid" => Uuid,
"smallint" => SmallInt,
"text" => Text,
"character varying" => Text,
"integer" => Integer,
_ => return Err(anyhow!("Unknown type: {}", s)),
};
Ok(s)
}
}
impl ToSql for Type {
fn write_sql(&self, buf: &mut String, _: Dialect) {
use self::Type::*;
let s = match self {
BigInt => "bigint",
Boolean => "boolean",
Bytes => "bytea",
Date => "date",
DateTime => "timestamptz",
NaiveDateTime => "timestamp without time zone",
Duration => "interval",
Json => "json",
Jsonb => "jsonb",
Float64 => "numeric",
Numeric(p, s) => return buf.push_str(&format!("numeric({}, {})", p, s)),
SmallInt => "smallint",
Uuid => "uuid",
Integer => "integer",
Text => "character varying",
};
buf.push_str(s);
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_numeric() {
let s = "numeric(15, 2)";
let t = Type::from_str(s).unwrap();
assert_eq!(t, Type::Numeric(15, 2));
}
#[test]
fn test_eq() {
let s = "numeric(15, 2)";
let t = Type::from_str(s).unwrap();
assert_eq!(t, Type::Numeric(15, 2));
}
}