1#![allow(clippy::cast_lossless)]
2use crate::{
3 interval::Interval,
4 ConvertError,
5};
6use bigdecimal::{
7 BigDecimal,
8 ToPrimitive,
9};
10use chrono::{
11 DateTime,
12 NaiveDate,
13 NaiveDateTime,
14 NaiveTime,
15 Utc,
16};
17use geo_types::Point;
18use serde_derive::{
19 Deserialize,
20 Serialize,
21};
22use std::fmt;
23use uuid::Uuid;
24
25#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
29pub enum Value {
30 Nil, Bool(bool),
32
33 Tinyint(i8),
34 Smallint(i16),
35 Int(i32),
36 Bigint(i64),
37
38 Float(f32),
39 Double(f64),
40 BigDecimal(BigDecimal),
41
42 Blob(Vec<u8>),
43 Char(char),
44 Text(String),
45 Json(String),
46
47 Uuid(Uuid),
48 Date(NaiveDate),
49 Time(NaiveTime),
50 DateTime(NaiveDateTime),
51 Timestamp(DateTime<Utc>),
52 Interval(Interval),
53
54 Point(Point<f64>),
55
56 Array(Array),
57}
58
59impl Value {
60 pub fn is_nil(&self) -> bool { *self == Value::Nil }
61}
62
63impl fmt::Display for Value {
64 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
65 match self {
66 Value::Nil => write!(f, ""),
67 Value::Bool(v) => write!(f, "{}", v),
68 Value::Tinyint(v) => write!(f, "{}", v),
69 Value::Smallint(v) => write!(f, "{}", v),
70 Value::Int(v) => write!(f, "{}", v),
71 Value::Bigint(v) => write!(f, "{}", v),
72 Value::Float(v) => write!(f, "{}", v),
73 Value::Double(v) => write!(f, "{}", v),
74 Value::BigDecimal(v) => write!(f, "{}", v),
75 Value::Char(v) => write!(f, "{}", v),
76 Value::Text(v) => write!(f, "{}", v),
77 Value::Json(v) => write!(f, "{}", v),
78 Value::Uuid(v) => write!(f, "{}", v),
79 Value::Date(v) => write!(f, "{}", v),
80 Value::Time(v) => write!(f, "{}", v),
81 Value::DateTime(v) => write!(f, "{}", v.format("%Y-%m-%d %H:%M:%S").to_string()),
82 Value::Timestamp(v) => write!(f, "{}", v.to_rfc3339()),
83 Value::Array(array) => array.fmt(f),
84 Value::Blob(v) => {
85 let encoded = base64::encode_config(&v, base64::STANDARD);
86 write!(f, "{}", encoded)
87 }
88 _ => panic!("not yet implemented: {:?}", self),
89 }
90 }
91}
92
93#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
94pub enum Array {
95 Int(Vec<i32>),
102 Float(Vec<f32>),
103 Text(Vec<String>),
110 }
117
118impl fmt::Display for Array {
119 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
120 match self {
121 Array::Text(texts) => {
122 let json_arr = serde_json::to_string(texts).expect("must serialize");
123 write!(f, "{}", json_arr)
124 }
125 Array::Float(floats) => {
126 let json_arr = serde_json::to_string(floats).expect("must serialize");
127 write!(f, "{}", json_arr)
128 }
129 _ => panic!("not yet implemented: {:?}", self),
130 }
131 }
132}
133
134pub trait ToValue {
137 fn to_value(&self) -> Value;
138}
139
140macro_rules! impl_to_value {
141 ($ty:ty, $variant:ident) => {
142 impl ToValue for $ty {
143 fn to_value(&self) -> Value { Value::$variant(self.to_owned()) }
144 }
145 };
146}
147
148impl_to_value!(bool, Bool);
149impl_to_value!(i8, Tinyint);
150impl_to_value!(i16, Smallint);
151impl_to_value!(i32, Int);
152impl_to_value!(i64, Bigint);
153impl_to_value!(f32, Float);
154impl_to_value!(f64, Double);
155impl_to_value!(Vec<u8>, Blob);
156impl_to_value!(char, Char);
157impl_to_value!(String, Text);
158impl_to_value!(Uuid, Uuid);
159impl_to_value!(NaiveDate, Date);
160impl_to_value!(NaiveTime, Time);
161impl_to_value!(DateTime<Utc>, Timestamp);
162impl_to_value!(NaiveDateTime, DateTime);
163
164impl ToValue for &str {
165 fn to_value(&self) -> Value { Value::Text(self.to_string()) }
166}
167
168impl ToValue for Vec<String> {
169 fn to_value(&self) -> Value { Value::Array(Array::Text(self.to_owned())) }
170}
171
172impl<T> ToValue for Option<T>
173where
174 T: ToValue,
175{
176 fn to_value(&self) -> Value {
177 match self {
178 Some(v) => v.to_value(),
179 None => Value::Nil,
180 }
181 }
182}
183
184impl<T> ToValue for &T
185where
186 T: ToValue,
187{
188 fn to_value(&self) -> Value { (*self).to_value() }
189}
190
191impl<T> From<T> for Value
192where
193 T: ToValue,
194{
195 fn from(v: T) -> Value { v.to_value() }
196}
197
198pub trait FromValue: Sized {
199 fn from_value(v: &Value) -> Result<Self, ConvertError>;
200}
201
202macro_rules! impl_from_value {
203 ($ty: ty, $ty_name: tt, $($variant: ident),*) => {
204 impl FromValue for $ty {
206 fn from_value(v: &Value) -> Result<Self, ConvertError> {
207 match *v {
208 $(Value::$variant(ref v) => Ok(v.to_owned() as $ty),
209 )*
210 _ => Err(ConvertError::NotSupported(format!("{:?}",v), $ty_name.into())),
211 }
212 }
213 }
214 }
215}
216
217macro_rules! impl_from_value_numeric {
218 ($ty: ty, $method:ident, $ty_name: tt, $($variant: ident),*) => {
219 impl FromValue for $ty {
220 fn from_value(v: &Value) -> Result<Self, ConvertError> {
221 match *v {
222 $(Value::$variant(ref v) => Ok(v.to_owned() as $ty),
223 )*
224 Value::BigDecimal(ref v) => Ok(v.$method().unwrap()),
225 _ => Err(ConvertError::NotSupported(format!("{:?}", v), $ty_name.into())),
226 }
227 }
228 }
229 }
230}
231
232impl_from_value!(Vec<u8>, "Vec<u8>", Blob);
233impl_from_value!(char, "char", Char);
234impl_from_value!(Uuid, "Uuid", Uuid);
235impl_from_value!(NaiveDate, "NaiveDate", Date);
236impl_from_value_numeric!(i8, to_i8, "i8", Tinyint);
237impl_from_value_numeric!(i16, to_i16, "i16", Tinyint, Smallint);
238impl_from_value_numeric!(i32, to_i32, "i32", Tinyint, Smallint, Int, Bigint);
239impl_from_value_numeric!(i64, to_i64, "i64", Tinyint, Smallint, Int, Bigint);
240impl_from_value_numeric!(f32, to_f32, "f32", Float);
241impl_from_value_numeric!(f64, to_f64, "f64", Float, Double);
242
243impl FromValue for String {
246 fn from_value(v: &Value) -> Result<Self, ConvertError> {
247 match *v {
248 Value::Text(ref v) => Ok(v.to_owned()),
249 Value::Char(ref v) => {
250 let mut s = String::new();
251 s.push(*v);
252 Ok(s)
253 }
254 Value::Blob(ref v) => {
255 String::from_utf8(v.to_owned()).map_err(|e| {
256 ConvertError::NotSupported(format!("{:?}", v), format!("String: {}", e))
257 })
258 }
259 _ => {
260 Err(ConvertError::NotSupported(
261 format!("{:?}", v),
262 "String".to_string(),
263 ))
264 }
265 }
266 }
267}
268
269impl FromValue for Vec<String> {
270 fn from_value(v: &Value) -> Result<Self, ConvertError> {
271 match *v {
272 Value::Array(Array::Text(ref t)) => Ok(t.to_owned()),
273 _ => {
274 Err(ConvertError::NotSupported(
275 format!("{:?}", v),
276 "Vec<String>".to_string(),
277 ))
278 }
279 }
280 }
281}
282
283impl FromValue for bool {
284 fn from_value(v: &Value) -> Result<Self, ConvertError> {
285 match *v {
286 Value::Bool(v) => Ok(v),
287 Value::Tinyint(v) => Ok(v == 1),
288 Value::Smallint(v) => Ok(v == 1),
289 Value::Int(v) => Ok(v == 1),
290 Value::Bigint(v) => Ok(v == 1),
291 _ => {
292 Err(ConvertError::NotSupported(
293 format!("{:?}", v),
294 "bool".to_string(),
295 ))
296 }
297 }
298 }
299}
300
301impl FromValue for DateTime<Utc> {
302 fn from_value(v: &Value) -> Result<Self, ConvertError> {
303 match *v {
304 Value::Text(ref v) => Ok(DateTime::<Utc>::from_utc(parse_naive_date_time(v), Utc)),
305 Value::DateTime(v) => Ok(DateTime::<Utc>::from_utc(v, Utc)),
306 Value::Timestamp(v) => Ok(v),
307 _ => {
308 Err(ConvertError::NotSupported(
309 format!("{:?}", v),
310 "DateTime".to_string(),
311 ))
312 }
313 }
314 }
315}
316
317impl FromValue for NaiveDateTime {
318 fn from_value(v: &Value) -> Result<Self, ConvertError> {
319 match *v {
320 Value::Text(ref v) => Ok(parse_naive_date_time(v)),
321 Value::DateTime(v) => Ok(v),
322 _ => {
323 Err(ConvertError::NotSupported(
324 format!("{:?}", v),
325 "NaiveDateTime".to_string(),
326 ))
327 }
328 }
329 }
330}
331
332impl<T> FromValue for Option<T>
333where
334 T: FromValue,
335{
336 fn from_value(v: &Value) -> Result<Self, ConvertError> {
337 match *v {
338 Value::Nil => Ok(None),
339 _ => FromValue::from_value(v).map(Some),
340 }
341 }
342}
343
344fn parse_naive_date_time(v: &str) -> NaiveDateTime {
345 let ts = NaiveDateTime::parse_from_str(&v, "%Y-%m-%d %H:%M:%S");
346 if let Ok(ts) = ts {
347 ts
348 } else {
349 let ts = NaiveDateTime::parse_from_str(&v, "%Y-%m-%d %H:%M:%S%.3f");
350 if let Ok(ts) = ts {
351 ts
352 } else {
353 panic!("unable to parse timestamp: {}", v);
354 }
355 }
356}
357
358#[cfg(test)]
359mod tests {
360 use super::*;
361 use chrono::offset::Utc;
362 use std::mem::size_of;
363
364 #[test]
365 fn data_sizes() {
366 assert_eq!(48, size_of::<Value>()); assert_eq!(24, size_of::<Vec<u8>>());
368 assert_eq!(24, size_of::<String>());
369 assert_eq!(12, size_of::<DateTime<Utc>>());
370 assert_eq!(4, size_of::<NaiveDate>());
371 assert_eq!(16, size_of::<Uuid>());
372 }
373
374 #[test]
375 fn test_types() {
376 let _: Value = 127i8.to_value();
377 let _: Value = 2222i16.to_value();
378 let _: Value = 4444i32.to_value();
379 let _: Value = 10000i64.to_value();
380 let _v1: Value = 1.0f32.to_value();
381 let _v2: Value = 100.0f64.to_value();
382 let _v3: Value = Utc::now().to_value();
383 let _v7: Value = Utc::today().naive_utc().to_value();
384 let _v4: Value = "hello world!".to_value();
385 let _v5: Value = "hello world!".to_string().to_value();
386 let _v6: Value = vec![1u8, 2, 255, 3].to_value();
387 }
388
389 #[test]
390 fn naive_date_parse() {
391 let v = "2018-01-29";
392 let ts = NaiveDate::parse_from_str(v, "%Y-%m-%d");
393 println!("{:?}", ts);
394 assert!(ts.is_ok());
395 }
396
397 #[test]
398 fn naive_date_time_parse() {
399 let v = "2018-01-29 09:58:20";
400 let ts = NaiveDateTime::parse_from_str(v, "%Y-%m-%d %H:%M:%S");
401 println!("{:?}", ts);
402 assert!(ts.is_ok());
403 }
404
405 #[test]
406 fn date_time_conversion() {
407 let v = "2018-01-29 09:58:20";
408 let ts = NaiveDateTime::parse_from_str(v, "%Y-%m-%d %H:%M:%S");
409 println!("{:?}", ts);
410 assert!(ts.is_ok());
411 DateTime::<Utc>::from_utc(ts.unwrap(), Utc);
412 }
413}