1use {
2 super::ValueError::ValueToExprConversionFailure,
3 crate::{
4 ast::{AstLiteral, DateTimeField, Expr},
5 chrono::{TimeZone, Utc},
6 data::Interval,
7 prelude::{DataType, Value},
8 result::{Error, Result},
9 },
10 bigdecimal::{BigDecimal, FromPrimitive},
11 serde_json::{Map as JsonMap, Value as JsonValue},
12 uuid::Uuid,
13};
14
15impl TryFrom<Value> for Expr {
16 type Error = Error;
17
18 fn try_from(value: Value) -> Result<Self> {
19 const SECOND: i64 = 1_000_000;
20
21 let expr = match value {
22 Value::Bool(v) => Expr::Literal(AstLiteral::Boolean(v)),
23 Value::I8(v) => Expr::Literal(AstLiteral::Number(
24 BigDecimal::from_i8(v).ok_or(ValueToExprConversionFailure)?,
25 )),
26 Value::I16(v) => Expr::Literal(AstLiteral::Number(
27 BigDecimal::from_i16(v).ok_or(ValueToExprConversionFailure)?,
28 )),
29 Value::I32(v) => Expr::Literal(AstLiteral::Number(
30 BigDecimal::from_i32(v).ok_or(ValueToExprConversionFailure)?,
31 )),
32 Value::I64(v) => Expr::Literal(AstLiteral::Number(
33 BigDecimal::from_i64(v).ok_or(ValueToExprConversionFailure)?,
34 )),
35 Value::I128(v) => Expr::Literal(AstLiteral::Number(
36 BigDecimal::from_i128(v).ok_or(ValueToExprConversionFailure)?,
37 )),
38 Value::U8(v) => Expr::Literal(AstLiteral::Number(
39 BigDecimal::from_u8(v).ok_or(ValueToExprConversionFailure)?,
40 )),
41 Value::U16(v) => Expr::Literal(AstLiteral::Number(
42 BigDecimal::from_u16(v).ok_or(ValueToExprConversionFailure)?,
43 )),
44 Value::U32(v) => Expr::Literal(AstLiteral::Number(
45 BigDecimal::from_u32(v).ok_or(ValueToExprConversionFailure)?,
46 )),
47 Value::U64(v) => Expr::Literal(AstLiteral::Number(
48 BigDecimal::from_u64(v).ok_or(ValueToExprConversionFailure)?,
49 )),
50 Value::U128(v) => Expr::Literal(AstLiteral::Number(
51 BigDecimal::from_u128(v).ok_or(ValueToExprConversionFailure)?,
52 )),
53 Value::F32(v) => Expr::Literal(AstLiteral::Number(
54 BigDecimal::from_f32(v).ok_or(ValueToExprConversionFailure)?,
55 )),
56 Value::F64(v) => Expr::Literal(AstLiteral::Number(
57 BigDecimal::from_f64(v).ok_or(ValueToExprConversionFailure)?,
58 )),
59 Value::Decimal(v) => Expr::Literal(AstLiteral::Number(
60 BigDecimal::from_f64(v.try_into().map_err(|_| ValueToExprConversionFailure)?)
61 .ok_or(ValueToExprConversionFailure)?,
62 )),
63 Value::Str(v) => Expr::Literal(AstLiteral::QuotedString(v)),
64 Value::Bytea(v) => Expr::Literal(AstLiteral::HexString(hex::encode(v))),
65 Value::Inet(v) => Expr::Literal(AstLiteral::QuotedString(v.to_string())),
66 Value::Date(v) => Expr::TypedString {
67 data_type: DataType::Date,
68 value: v.to_string(),
69 },
70 Value::Timestamp(v) => Expr::TypedString {
71 data_type: DataType::Timestamp,
72 value: Utc.from_utc_datetime(&v).to_string(),
73 },
74 Value::Time(v) => Expr::TypedString {
75 data_type: DataType::Time,
76 value: v.to_string(),
77 },
78 Value::Interval(v) => match v {
79 Interval::Month(v) => Expr::Interval {
80 expr: Box::new(Expr::Literal(AstLiteral::Number(
81 BigDecimal::from_i32(v).ok_or(ValueToExprConversionFailure)?,
82 ))),
83 leading_field: Some(DateTimeField::Month),
84 last_field: None,
85 },
86 Interval::Microsecond(v) => Expr::Interval {
87 expr: Box::new(Expr::Literal(AstLiteral::Number(
88 BigDecimal::from_i64(v / SECOND).ok_or(ValueToExprConversionFailure)?,
89 ))),
90 leading_field: Some(DateTimeField::Second),
91 last_field: None,
92 },
93 },
94 Value::Uuid(v) => Expr::Literal(AstLiteral::QuotedString(
95 Uuid::from_u128(v).hyphenated().to_string(),
96 )),
97 Value::Map(v) => {
98 let json: JsonValue = v
99 .into_iter()
100 .map(|(key, value)| value.try_into().map(|value| (key, value)))
101 .collect::<Result<Vec<(String, JsonValue)>>>()
102 .map(|v| JsonMap::from_iter(v).into())
103 .map_err(|_| ValueToExprConversionFailure)?;
104
105 Expr::Literal(AstLiteral::QuotedString(json.to_string()))
106 }
107 Value::List(v) => {
108 let json: JsonValue = v
109 .into_iter()
110 .map(|value| value.try_into())
111 .collect::<Result<Vec<JsonValue>>>()
112 .map(|v| v.into())
113 .map_err(|_| ValueToExprConversionFailure)?;
114
115 Expr::Literal(AstLiteral::QuotedString(json.to_string()))
116 }
117 Value::Point(v) => Expr::Literal(AstLiteral::QuotedString(v.to_string())),
118 Value::Null => Expr::Literal(AstLiteral::Null),
119 };
120
121 Ok(expr)
122 }
123}
124
125#[cfg(test)]
126mod tests {
127 use {
128 crate::{
129 ast::{AstLiteral, DateTimeField, Expr},
130 data::{Interval, Point},
131 prelude::{DataType, Value},
132 },
133 bigdecimal::{BigDecimal, FromPrimitive},
134 chrono::{NaiveDate, NaiveTime},
135 rust_decimal::Decimal,
136 std::collections::BTreeMap,
137 };
138
139 #[test]
140 fn value_to_expr() {
141 assert_eq!(
142 Value::Bool(true).try_into(),
143 Ok(Expr::Literal(AstLiteral::Boolean(true)))
144 );
145
146 assert_eq!(
147 Value::I8(127).try_into(),
148 Ok(Expr::Literal(AstLiteral::Number(
149 BigDecimal::from_i8(127).unwrap()
150 )))
151 );
152 assert_eq!(
153 Value::I16(32767).try_into(),
154 Ok(Expr::Literal(AstLiteral::Number(
155 BigDecimal::from_i16(32767).unwrap()
156 )))
157 );
158 assert_eq!(
159 Value::I32(2147483647).try_into(),
160 Ok(Expr::Literal(AstLiteral::Number(
161 BigDecimal::from_i32(2147483647).unwrap()
162 )))
163 );
164 assert_eq!(
165 Value::I64(64).try_into(),
166 Ok(Expr::Literal(AstLiteral::Number(
167 BigDecimal::from_i64(64).unwrap()
168 )))
169 );
170 assert_eq!(
171 Value::I128(128).try_into(),
172 Ok(Expr::Literal(AstLiteral::Number(
173 BigDecimal::from_i128(128).unwrap()
174 )))
175 );
176 assert_eq!(
177 Value::U8(8).try_into(),
178 Ok(Expr::Literal(AstLiteral::Number(
179 BigDecimal::from_u8(8).unwrap()
180 )))
181 );
182 assert_eq!(
183 Value::U16(16).try_into(),
184 Ok(Expr::Literal(AstLiteral::Number(
185 BigDecimal::from_u16(16).unwrap()
186 )))
187 );
188 assert_eq!(
189 Value::U32(32).try_into(),
190 Ok(Expr::Literal(AstLiteral::Number(
191 BigDecimal::from_u32(32).unwrap()
192 )))
193 );
194 assert_eq!(
195 Value::U64(64).try_into(),
196 Ok(Expr::Literal(AstLiteral::Number(
197 BigDecimal::from_u64(64).unwrap()
198 )))
199 );
200 assert_eq!(
201 Value::U128(128).try_into(),
202 Ok(Expr::Literal(AstLiteral::Number(
203 BigDecimal::from_u128(128).unwrap()
204 )))
205 );
206
207 assert_eq!(
208 Value::F32(64.4_f32).try_into(),
209 Ok(Expr::Literal(AstLiteral::Number(
210 BigDecimal::from_f32(64.4).unwrap()
211 )))
212 );
213 assert_eq!(
214 Value::F64(64.4).try_into(),
215 Ok(Expr::Literal(AstLiteral::Number(
216 BigDecimal::from_f64(64.4).unwrap()
217 )))
218 );
219 assert_eq!(
220 Value::Decimal(Decimal::new(315, 2)).try_into(),
221 Ok(Expr::Literal(AstLiteral::Number(
222 BigDecimal::from_f64(3.15).unwrap()
223 )))
224 );
225 assert_eq!(
226 Value::Str("data".to_owned()).try_into(),
227 Ok(Expr::Literal(AstLiteral::QuotedString("data".to_owned())))
228 );
229 assert_eq!(
230 Value::Bytea(hex::decode("1234").unwrap()).try_into(),
231 Ok(Expr::Literal(AstLiteral::HexString("1234".to_owned())))
232 );
233 assert_eq!(
234 Value::Date(NaiveDate::from_ymd_opt(2022, 11, 3).unwrap()).try_into(),
235 Ok(Expr::TypedString {
236 data_type: DataType::Date,
237 value: "2022-11-03".to_owned(),
238 })
239 );
240 assert_eq!(
241 Value::Timestamp(
242 NaiveDate::from_ymd_opt(2022, 11, 3)
243 .unwrap()
244 .and_hms_milli_opt(8, 5, 30, 900)
245 .unwrap()
246 )
247 .try_into(),
248 Ok(Expr::TypedString {
249 data_type: DataType::Timestamp,
250 value: "2022-11-03 08:05:30.900 UTC".to_owned(),
251 }),
252 );
253 assert_eq!(
254 Value::Time(NaiveTime::from_hms_opt(20, 11, 59).unwrap()).try_into(),
255 Ok(Expr::TypedString {
256 data_type: DataType::Time,
257 value: "20:11:59".to_owned()
258 }),
259 );
260 assert_eq!(
261 Value::Interval(Interval::Month(1)).try_into(),
262 Ok(Expr::Interval {
263 expr: Box::new(Expr::Literal(AstLiteral::Number(
264 BigDecimal::from_i64(1).unwrap()
265 ))),
266 leading_field: Some(DateTimeField::Month),
267 last_field: None
268 })
269 );
270 assert_eq!(
271 Value::Uuid(195965723427462096757863453463987888808).try_into(),
272 Ok(Expr::Literal(AstLiteral::QuotedString(
273 "936da01f-9abd-4d9d-80c7-02af85c822a8".to_owned()
274 )))
275 );
276 assert_eq!(
277 Value::Map(BTreeMap::from([("a".to_owned(), Value::Bool(true))])).try_into(),
278 Ok(Expr::Literal(AstLiteral::QuotedString(
279 "{\"a\":true}".to_owned()
280 )))
281 );
282 assert_eq!(
283 Value::List(vec![
284 Value::I64(1),
285 Value::Bool(true),
286 Value::Str("a".to_owned())
287 ])
288 .try_into(),
289 Ok(Expr::Literal(AstLiteral::QuotedString(
290 "[1,true,\"a\"]".to_owned()
291 )))
292 );
293 assert_eq!(Value::Null.try_into(), Ok(Expr::Literal(AstLiteral::Null)));
294 assert_eq!(
295 Value::Point(Point::new(0.31413, 0.3415)).try_into(),
296 Ok(Expr::Literal(AstLiteral::QuotedString(
297 "POINT(0.31413 0.3415)".to_owned()
298 )))
299 );
300 }
301}