1use crate::{ast::ToSql, data::Value};
2
3impl ToSql for Value {
4 fn to_sql(&self) -> String {
5 match self {
6 Value::Bool(b) => b.to_string().to_uppercase(),
7 Value::I8(n) => n.to_string(),
8 Value::I16(n) => n.to_string(),
9 Value::I32(n) => n.to_string(),
10 Value::I64(n) => n.to_string(),
11 Value::I128(n) => n.to_string(),
12 Value::U8(n) => n.to_string(),
13 Value::U16(n) => n.to_string(),
14 Value::U32(n) => n.to_string(),
15 Value::U64(n) => n.to_string(),
16 Value::U128(n) => n.to_string(),
17 Value::F32(n) => n.to_string(),
18 Value::F64(n) => n.to_string(),
19 Value::Decimal(n) => n.to_string(),
20 Value::Str(s) => {
21 let escaped = s.replace('\'', "''");
22 format!("'{escaped}'")
23 }
24 Value::Bytea(bytes) => format!("X'{}'", hex::encode(bytes)),
25 Value::Inet(addr) => format!("'{addr}'"),
26 Value::Date(d) => format!("DATE '{d}'"),
27 Value::Timestamp(ts) => format!("TIMESTAMP '{ts}'"),
28 Value::Time(t) => format!("TIME '{t}'"),
29 Value::Interval(i) => format!("INTERVAL {}", i.to_sql_str()),
30 Value::Uuid(u) => format!("'{}'", uuid::Uuid::from_u128(*u).hyphenated()),
31 Value::Map(_) | Value::List(_) => {
32 let json: serde_json::Value =
33 self.clone().try_into().unwrap_or(serde_json::Value::Null);
34 let escaped = json.to_string().replace('\'', "''");
35 format!("'{escaped}'")
36 }
37 Value::Point(p) => format!("POINT({} {})", p.x, p.y),
38 Value::Null => "NULL".to_owned(),
39 }
40 }
41}
42
43#[cfg(test)]
44mod tests {
45 use {
46 crate::{
47 ast::ToSql,
48 data::{Interval, Point, Value},
49 },
50 chrono::{NaiveDate, NaiveTime},
51 rust_decimal::Decimal,
52 std::{collections::BTreeMap, net::IpAddr, str::FromStr},
53 };
54
55 #[test]
56 fn to_sql() {
57 assert_eq!(Value::Bool(true).to_sql(), "TRUE");
59 assert_eq!(Value::Bool(false).to_sql(), "FALSE");
60
61 assert_eq!(Value::I8(127).to_sql(), "127");
63 assert_eq!(Value::I16(32767).to_sql(), "32767");
64 assert_eq!(Value::I32(2_147_483_647).to_sql(), "2147483647");
65 assert_eq!(Value::I64(64).to_sql(), "64");
66 assert_eq!(Value::I128(128).to_sql(), "128");
67
68 assert_eq!(Value::U8(255).to_sql(), "255");
70 assert_eq!(Value::U16(65535).to_sql(), "65535");
71 assert_eq!(Value::U32(32).to_sql(), "32");
72 assert_eq!(Value::U64(64).to_sql(), "64");
73 assert_eq!(Value::U128(128).to_sql(), "128");
74
75 assert_eq!(Value::F32(1.5).to_sql(), "1.5");
77 assert_eq!(Value::F64(2.5).to_sql(), "2.5");
78
79 assert_eq!(Value::Decimal(Decimal::new(314, 2)).to_sql(), "3.14");
81
82 assert_eq!(Value::Str("hello".to_owned()).to_sql(), "'hello'");
84 assert_eq!(Value::Str("it's".to_owned()).to_sql(), "'it''s'");
85
86 assert_eq!(
88 Value::Bytea(vec![0x48, 0x65, 0x6c, 0x6c, 0x6f]).to_sql(),
89 "X'48656c6c6f'"
90 );
91
92 assert_eq!(
94 Value::Inet(IpAddr::from_str("192.168.1.1").unwrap()).to_sql(),
95 "'192.168.1.1'"
96 );
97 assert_eq!(
98 Value::Inet(IpAddr::from_str("::1").unwrap()).to_sql(),
99 "'::1'"
100 );
101
102 assert_eq!(
104 Value::Date(NaiveDate::from_ymd_opt(2024, 1, 15).unwrap()).to_sql(),
105 "DATE '2024-01-15'"
106 );
107
108 assert_eq!(
110 Value::Timestamp(
111 NaiveDate::from_ymd_opt(2024, 1, 15)
112 .unwrap()
113 .and_hms_opt(13, 30, 45)
114 .unwrap()
115 )
116 .to_sql(),
117 "TIMESTAMP '2024-01-15 13:30:45'"
118 );
119
120 assert_eq!(
122 Value::Time(NaiveTime::from_hms_opt(13, 30, 45).unwrap()).to_sql(),
123 "TIME '13:30:45'"
124 );
125
126 assert_eq!(
128 Value::Interval(Interval::Month(14)).to_sql(),
129 "INTERVAL '1-2' YEAR TO MONTH"
130 );
131
132 assert_eq!(
134 Value::Uuid(0x936d_a01f_9abd_4d9d_80c7_02af_85c8_22a8_u128).to_sql(),
135 "'936da01f-9abd-4d9d-80c7-02af85c822a8'"
136 );
137
138 let map = BTreeMap::from([
140 ("a".to_owned(), Value::I64(1)),
141 ("b".to_owned(), Value::Bool(true)),
142 ]);
143 assert_eq!(Value::Map(map).to_sql(), "'{\"a\":1,\"b\":true}'");
144
145 let list = vec![Value::I64(1), Value::I64(2), Value::I64(3)];
147 assert_eq!(Value::List(list).to_sql(), "'[1,2,3]'");
148
149 assert_eq!(
151 Value::Point(Point::new(1.5, 2.5)).to_sql(),
152 "POINT(1.5 2.5)"
153 );
154
155 assert_eq!(Value::Null.to_sql(), "NULL");
157 }
158}