restq/
data_value.rs

1use crate::{
2    ast::{Expr, Value},
3    data_type::DataType,
4};
5use base64::{engine::general_purpose::URL_SAFE, Engine};
6use chrono::{DateTime, NaiveDate, NaiveDateTime, NaiveTime, Utc};
7use serde::{Deserialize, Serialize};
8use sqlparser::ast as sql;
9use std::fmt;
10use uuid::Uuid;
11
12/// strict data value
13/// where each has exact byte definitions, etc.
14#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
15pub enum DataValue {
16    Nil,
17    Bool(bool),
18    S8(u8),
19    S16(u16),
20    S32(u32),
21    S64(u64),
22    F32(f32),
23    F64(f64),
24    U8(u8),
25    U16(u16),
26    U32(u32),
27    U64(u64),
28    I8(i8),
29    I16(i16),
30    I32(i32),
31    I64(i64),
32    Uuid(Uuid),
33    UuidRand(Uuid),
34    UuidSlug(String),
35    Utc(DateTime<Utc>),
36    Text(String),
37    Ident(String),
38    Bytes(Vec<u8>),
39}
40
41impl DataValue {
42    pub fn get_data_type(&self) -> Option<DataType> {
43        let dt = match self {
44            DataValue::Nil => {
45                return None;
46            }
47            DataValue::Bool(_) => DataType::Bool,
48            DataValue::S8(_) => DataType::S8,
49            DataValue::S16(_) => DataType::S16,
50            DataValue::S32(_) => DataType::S32,
51            DataValue::S64(_) => DataType::S64,
52            DataValue::F32(_) => DataType::F32,
53            DataValue::F64(_) => DataType::F64,
54            DataValue::U8(_) => DataType::U8,
55            DataValue::U16(_) => DataType::U16,
56            DataValue::U32(_) => DataType::U32,
57            DataValue::U64(_) => DataType::U64,
58            DataValue::I8(_) => DataType::I8,
59            DataValue::I16(_) => DataType::I16,
60            DataValue::I32(_) => DataType::I32,
61            DataValue::I64(_) => DataType::I64,
62            DataValue::Uuid(_) => DataType::Uuid,
63            DataValue::UuidRand(_) => DataType::UuidRand,
64            DataValue::UuidSlug(_) => DataType::UuidSlug,
65            DataValue::Utc(_) => DataType::Utc,
66            DataValue::Text(_) => DataType::Text,
67            DataValue::Ident(_) => DataType::Ident,
68            DataValue::Bytes(_) => DataType::Bytes,
69        };
70        Some(dt)
71    }
72}
73
74fn naive_date_parser(v: &str) -> NaiveDateTime {
75    if let Ok(dt) = DateTime::parse_from_rfc3339(v) {
76        dt.naive_local()
77    } else if let Ok(ts) =
78        NaiveDateTime::parse_from_str(&v, "%Y-%m-%dT%H:%M:%S%z")
79    {
80        ts
81    } else if let Ok(ts) =
82        NaiveDateTime::parse_from_str(&v, "%Y-%m-%d %H:%M:%S")
83    {
84        ts
85    } else if let Ok(ts) =
86        NaiveDateTime::parse_from_str(&v, "%Y-%m-%d %H:%M:%S.%f")
87    {
88        ts
89    } else if let Ok(nd) = NaiveDate::parse_from_str(&v, "%Y-%m-%d") {
90        NaiveDateTime::new(
91            nd,
92            NaiveTime::from_hms_milli_opt(0, 0, 0, 0).unwrap(),
93        )
94    } else {
95        panic!("unable to parse timestamp: {:?}", v);
96    }
97}
98
99impl Into<u32> for DataValue {
100    fn into(self) -> u32 {
101        match self {
102            DataValue::U8(v) => v as u32,
103            DataValue::U16(v) => v as u32,
104            DataValue::U32(v) => v,
105            DataValue::U64(v) => v as u32,
106            DataValue::I8(v) => v as u32,
107            DataValue::I16(v) => v as u32,
108            DataValue::I32(v) => v as u32,
109            DataValue::I64(v) => v as u32,
110            DataValue::S8(v) => v as u32,
111            DataValue::S16(v) => v as u32,
112            DataValue::S32(v) => v,
113            DataValue::S64(v) => v as u32,
114            _ => {
115                panic!(
116                    "unsupported conversion: {:?} to u32",
117                    self.get_data_type()
118                )
119            }
120        }
121    }
122}
123
124impl Into<u64> for DataValue {
125    fn into(self) -> u64 {
126        match self {
127            DataValue::U8(v) => v as u64,
128            DataValue::U16(v) => v as u64,
129            DataValue::U32(v) => v as u64,
130            DataValue::U64(v) => v,
131            DataValue::I8(v) => v as u64,
132            DataValue::I16(v) => v as u64,
133            DataValue::I32(v) => v as u64,
134            DataValue::I64(v) => v as u64,
135            DataValue::S8(v) => v as u64,
136            DataValue::S16(v) => v as u64,
137            DataValue::S32(v) => v as u64,
138            DataValue::S64(v) => v,
139            _ => {
140                panic!(
141                    "unsupported conversion: {:?} to u64",
142                    self.get_data_type()
143                )
144            }
145        }
146    }
147}
148
149impl Into<i64> for DataValue {
150    fn into(self) -> i64 {
151        match self {
152            DataValue::U8(v) => v as i64,
153            DataValue::U16(v) => v as i64,
154            DataValue::U32(v) => v as i64,
155            DataValue::U64(v) => v as i64,
156            DataValue::I8(v) => v as i64,
157            DataValue::I16(v) => v as i64,
158            DataValue::I32(v) => v as i64,
159            DataValue::I64(v) => v,
160            DataValue::S8(v) => v as i64,
161            DataValue::S16(v) => v as i64,
162            DataValue::S32(v) => v as i64,
163            DataValue::S64(v) => v as i64,
164            _ => {
165                panic!(
166                    "unsupported conversion: {:?} to u64",
167                    self.get_data_type()
168                )
169            }
170        }
171    }
172}
173
174impl Into<f32> for DataValue {
175    fn into(self) -> f32 {
176        match self {
177            DataValue::U8(v) => v as f32,
178            DataValue::U16(v) => v as f32,
179            DataValue::U32(v) => v as f32,
180            DataValue::U64(v) => v as f32,
181            DataValue::I8(v) => v as f32,
182            DataValue::I16(v) => v as f32,
183            DataValue::I32(v) => v as f32,
184            DataValue::I64(v) => v as f32,
185            DataValue::F32(v) => v,
186            DataValue::F64(v) => v as f32,
187            DataValue::S8(v) => v as f32,
188            DataValue::S16(v) => v as f32,
189            DataValue::S32(v) => v as f32,
190            DataValue::S64(v) => v as f32,
191            _ => {
192                panic!(
193                    "unsupported conversion: {:?} to f32",
194                    self.get_data_type()
195                )
196            }
197        }
198    }
199}
200
201impl Into<String> for DataValue {
202    fn into(self) -> String {
203        match self {
204            DataValue::Text(v) => v,
205            _ => {
206                panic!(
207                    "unsupported conversion: {:?} to String",
208                    self.get_data_type()
209                )
210            }
211        }
212    }
213}
214
215impl<'a> Into<&'a str> for &'a DataValue {
216    fn into(self) -> &'a str {
217        match self {
218            DataValue::Text(ref v) => v,
219            _ => {
220                panic!(
221                    "unsupported conversion: {:?} to &str",
222                    self.get_data_type()
223                )
224            }
225        }
226    }
227}
228
229impl Into<Expr> for Value {
230    fn into(self) -> Expr {
231        Expr::Value(self)
232    }
233}
234
235impl Into<sql::Expr> for &Value {
236    fn into(self) -> sql::Expr {
237        let expr: Expr = Into::into(self.clone());
238        Into::into(&expr)
239    }
240}
241
242impl Into<sql::Value> for &DataValue {
243    fn into(self) -> sql::Value {
244        match self {
245            DataValue::Bool(v) => sql::Value::Boolean(*v),
246            DataValue::U8(v) => sql::Value::Number(v.to_string(), false),
247            DataValue::U16(v) => sql::Value::Number(v.to_string(), false),
248            DataValue::U32(v) => sql::Value::Number(v.to_string(), false),
249            DataValue::U64(v) => sql::Value::Number(v.to_string(), false),
250            DataValue::F32(v) => sql::Value::Number(v.to_string(), false),
251            DataValue::F64(v) => sql::Value::Number(v.to_string(), false),
252            _ => todo!(),
253        }
254    }
255}
256
257impl Into<Value> for &DataValue {
258    fn into(self) -> Value {
259        match self {
260            DataValue::Bool(v) => Value::Bool(*v),
261            DataValue::U8(v) => Value::Number(*v as f64),
262            DataValue::U16(v) => Value::Number(*v as f64),
263            DataValue::U32(v) => Value::Number(*v as f64),
264            DataValue::U64(v) => Value::Number(*v as f64),
265            DataValue::I8(v) => Value::Number(*v as f64),
266            DataValue::I16(v) => Value::Number(*v as f64),
267            DataValue::I32(v) => Value::Number(*v as f64),
268            DataValue::I64(v) => Value::Number(*v as f64),
269            DataValue::F32(v) => Value::Number(*v as f64),
270            DataValue::F64(v) => Value::Number(*v as f64),
271            DataValue::Text(v) => Value::String(v.clone()),
272            _ => panic!("todo for: {:?}", self),
273        }
274    }
275}
276
277impl Into<sql::Expr> for &DataValue {
278    fn into(self) -> sql::Expr {
279        sql::Expr::Value(Into::into(self))
280    }
281}
282
283/// cast the value into DataValue hinted by the data_type
284pub fn cast_data_value(value: &Value, required_type: &DataType) -> DataValue {
285    if *value == Value::Null {
286        DataValue::Nil
287    } else {
288        match *value {
289            Value::Bool(v) => match *required_type {
290                DataType::Bool => DataValue::Bool(v),
291                DataType::U8 => DataValue::U8(if v { 1 } else { 0 }),
292                DataType::U16 => DataValue::U16(if v { 1 } else { 0 }),
293                DataType::U32 => DataValue::U32(if v { 1 } else { 0 }),
294                DataType::U64 => DataValue::U64(if v { 1 } else { 0 }),
295                DataType::I8 => DataValue::I8(if v { 1 } else { 0 }),
296                DataType::I16 => DataValue::I16(if v { 1 } else { 0 }),
297                DataType::I32 => DataValue::I32(if v { 1 } else { 0 }),
298                DataType::I64 => DataValue::I64(if v { 1 } else { 0 }),
299                DataType::S8 => DataValue::S8(if v { 1 } else { 0 }),
300                DataType::S16 => DataValue::S16(if v { 1 } else { 0 }),
301                DataType::S32 => DataValue::S32(if v { 1 } else { 0 }),
302                DataType::S64 => DataValue::S64(if v { 1 } else { 0 }),
303                _ => {
304                    panic!(
305                        "unsupported conversion from {:?} to {:?}",
306                        value, required_type
307                    )
308                }
309            },
310            Value::Number(v) => match *required_type {
311                DataType::U8 => DataValue::U8(v as u8),
312                DataType::U16 => DataValue::U16(v as u16),
313                DataType::U32 => DataValue::U32(v as u32),
314                DataType::U64 => DataValue::U64(v as u64),
315                DataType::I8 => DataValue::I8(v as i8),
316                DataType::I16 => DataValue::I16(v as i16),
317                DataType::I32 => DataValue::I32(v as i32),
318                DataType::I64 => DataValue::I64(v as i64),
319                DataType::F32 => DataValue::F32(v as f32),
320                DataType::F64 => DataValue::F64(v as f64),
321                DataType::S8 => DataValue::S8(v as u8),
322                DataType::S16 => DataValue::S16(v as u16),
323                DataType::S32 => DataValue::S32(v as u32),
324                DataType::S64 => DataValue::S64(v as u64),
325                _ => {
326                    panic!(
327                        "unsupported conversion from {:?} to {:?}",
328                        value, required_type
329                    )
330                }
331            },
332            Value::String(ref v) => {
333                match *required_type {
334                    DataType::Text => DataValue::Text(v.to_string()),
335                    DataType::Bool => match v.as_ref() {
336                        "true" => DataValue::Bool(true),
337                        "false" => DataValue::Bool(false),
338                        "1" => DataValue::Bool(true),
339                        "0" => DataValue::Bool(false),
340                        _ => DataValue::Bool(false),
341                    },
342                    DataType::S8 => {
343                        if v.is_empty() {
344                            DataValue::Nil
345                        } else if let Ok(v) = v.parse::<u8>() {
346                            DataValue::S8(v)
347                        } else {
348                            panic!(
349                                "unsupported conversion from {:?} to {:?}",
350                                value, required_type
351                            );
352                        }
353                    }
354                    DataType::S16 => {
355                        if v.is_empty() {
356                            DataValue::Nil
357                        } else if let Ok(v) = v.parse::<u16>() {
358                            DataValue::S16(v)
359                        } else {
360                            panic!(
361                                "unsupported conversion from {:?} to {:?}",
362                                value, required_type
363                            );
364                        }
365                    }
366                    DataType::S32 => {
367                        if v.is_empty() {
368                            DataValue::Nil
369                        } else if let Ok(v) = v.parse::<u32>() {
370                            DataValue::S32(v)
371                        } else {
372                            panic!(
373                                "unsupported conversion from {:?} to {:?}",
374                                value, required_type
375                            );
376                        }
377                    }
378                    DataType::S64 => {
379                        if v.is_empty() {
380                            DataValue::Nil
381                        } else if let Ok(v) = v.parse::<u64>() {
382                            DataValue::S64(v)
383                        } else {
384                            panic!(
385                                "unsupported conversion from {:?} to {:?}",
386                                value, required_type
387                            );
388                        }
389                    }
390                    DataType::U8 => {
391                        if v.is_empty() {
392                            DataValue::Nil
393                        } else if v.is_empty() {
394                            DataValue::Nil
395                        } else if let Ok(v) = v.parse::<u8>() {
396                            DataValue::U8(v)
397                        } else {
398                            panic!(
399                                "unsupported conversion from {:?} to {:?}",
400                                value, required_type
401                            );
402                        }
403                    }
404                    DataType::U16 => {
405                        if v.is_empty() {
406                            DataValue::Nil
407                        } else if let Ok(v) = v.parse::<u16>() {
408                            DataValue::U16(v)
409                        } else {
410                            panic!(
411                                "unsupported conversion from {:?} to {:?}",
412                                value, required_type
413                            );
414                        }
415                    }
416                    DataType::U32 => {
417                        if v.is_empty() {
418                            DataValue::Nil
419                        } else if let Ok(v) = v.parse::<u32>() {
420                            DataValue::U32(v)
421                        } else {
422                            panic!(
423                                "unsupported conversion from {:?} to {:?}",
424                                value, required_type
425                            );
426                        }
427                    }
428                    DataType::U64 => {
429                        if v.is_empty() {
430                            DataValue::Nil
431                        } else if let Ok(v) = v.parse::<u64>() {
432                            DataValue::U64(v)
433                        } else {
434                            panic!(
435                                "unsupported conversion from {:?} to {:?}",
436                                value, required_type
437                            );
438                        }
439                    }
440                    DataType::I8 => {
441                        if v.is_empty() {
442                            DataValue::Nil
443                        } else if let Ok(v) = v.parse::<i8>() {
444                            DataValue::I8(v)
445                        } else {
446                            panic!(
447                                "unsupported conversion from {:?} to {:?}",
448                                value, required_type
449                            );
450                        }
451                    }
452                    DataType::I16 => {
453                        if v.is_empty() {
454                            DataValue::Nil
455                        } else if let Ok(v) = v.parse::<i16>() {
456                            DataValue::I16(v)
457                        } else {
458                            panic!(
459                                "unsupported conversion from {:?} to {:?}",
460                                value, required_type
461                            );
462                        }
463                    }
464                    DataType::I32 => {
465                        if v.is_empty() {
466                            DataValue::Nil
467                        } else if let Ok(v) = v.parse::<i32>() {
468                            DataValue::I32(v)
469                        } else {
470                            panic!(
471                                "unsupported conversion from {:?} to {:?}",
472                                value, required_type
473                            );
474                        }
475                    }
476                    DataType::I64 => {
477                        if v.is_empty() {
478                            DataValue::Nil
479                        } else if let Ok(v) = v.parse::<i64>() {
480                            DataValue::I64(v)
481                        } else {
482                            panic!(
483                                "unsupported conversion from {:?} to {:?}",
484                                value, required_type
485                            );
486                        }
487                    }
488                    DataType::F32 => {
489                        if v.is_empty() {
490                            DataValue::Nil
491                        } else if let Ok(v) = v.parse::<f32>() {
492                            DataValue::F32(v)
493                        } else {
494                            panic!(
495                                "unsupported conversion from {:?} to {:?}",
496                                value, required_type
497                            );
498                        }
499                    }
500                    DataType::F64 => {
501                        if v.is_empty() {
502                            DataValue::Nil
503                        } else if let Ok(v) = v.parse::<f64>() {
504                            DataValue::F64(v)
505                        } else {
506                            panic!(
507                                "unsupported conversion from {:?} to {:?}",
508                                value, required_type
509                            );
510                        }
511                    }
512                    DataType::Utc => {
513                        if v.is_empty() {
514                            DataValue::Nil
515                        } else {
516                            let ts = naive_date_parser(&v);
517                            if let Some(utc) =
518                                DateTime::<Utc>::from_timestamp_millis(
519                                    ts.and_utc().timestamp_millis(),
520                                )
521                            {
522                                DataValue::Utc(utc)
523                            } else {
524                                panic!("error converting datetime");
525                            }
526                        }
527                    }
528                    DataType::Uuid | DataType::UuidRand => {
529                        match Uuid::parse_str(&v) {
530                            Ok(v) => DataValue::Uuid(v),
531                            Err(_e) => DataValue::Nil,
532                        }
533                    }
534                    DataType::UuidSlug => DataValue::UuidSlug(v.to_string()),
535                    //TODO: validate identifier
536                    DataType::Ident => DataValue::Ident(v.to_string()),
537                    DataType::Bytes => {
538                        let bytes = URL_SAFE
539                            .decode(&v)
540                            .expect("must be a valid base64 bytes");
541                        DataValue::Bytes(bytes)
542                    }
543                    DataType::Json => DataValue::Text(v.to_string()),
544                    _ => {
545                        panic!(
546                            "unsupported conversion from {:?} to {:?}",
547                            value, required_type
548                        )
549                    }
550                }
551            }
552            _ => {
553                panic!(
554                    "unsupported conversion from {:?} to {:?}",
555                    value, required_type
556                )
557            }
558        }
559    }
560}
561
562impl fmt::Display for DataValue {
563    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
564        match self {
565            DataValue::Nil => write!(f, ""),
566            DataValue::Bool(v) => write!(f, "{}", v),
567            DataValue::S8(v) => write!(f, "{}", v),
568            DataValue::S16(v) => write!(f, "{}", v),
569            DataValue::S32(v) => write!(f, "{}", v),
570            DataValue::S64(v) => write!(f, "{}", v),
571            DataValue::F32(v) => write!(f, "{}", v),
572            DataValue::F64(v) => write!(f, "{}", v),
573            DataValue::U8(v) => write!(f, "{}", v),
574            DataValue::U16(v) => write!(f, "{}", v),
575            DataValue::U32(v) => write!(f, "{}", v),
576            DataValue::U64(v) => write!(f, "{}", v),
577            DataValue::I8(v) => write!(f, "{}", v),
578            DataValue::I16(v) => write!(f, "{}", v),
579            DataValue::I32(v) => write!(f, "{}", v),
580            DataValue::I64(v) => write!(f, "{}", v),
581            DataValue::Uuid(v) => write!(f, "{}", v),
582            DataValue::UuidRand(v) => write!(f, "{}", v),
583            DataValue::UuidSlug(v) => write!(f, "{}", v),
584            DataValue::Utc(v) => write!(f, "{}", v.to_rfc3339()),
585            DataValue::Text(v) => write!(f, "{}", v),
586            DataValue::Ident(v) => write!(f, "{}", v),
587            DataValue::Bytes(v) => {
588                let encoded = URL_SAFE.encode(&v);
589                write!(f, "{}", encoded)
590            }
591        }
592    }
593}
594
595#[cfg(test)]
596mod test {
597    use super::*;
598
599    #[test]
600    fn parse_simple_date() {
601        let date = "2006-02-14";
602
603        let parsed = NaiveDateTime::parse_from_str(date, "%Y-%m-%d");
604        println!("parsed: {:?}", parsed);
605
606        let res = naive_date_parser(date);
607        let naive_date = NaiveDate::from_ymd_opt(2006, 2, 14).unwrap();
608        let naive_time = NaiveTime::from_hms_milli_opt(0, 0, 0, 0).unwrap();
609        assert_eq!(res, NaiveDateTime::new(naive_date, naive_time));
610    }
611
612    #[test]
613    fn parse_dates() {
614        let date = "2006-02-15T09:34:33+00:00";
615        let res = naive_date_parser(date);
616        println!("res: {}", res);
617        let naive_date = NaiveDate::from_ymd_opt(2006, 2, 15).unwrap();
618        let naive_time = NaiveTime::from_hms_milli_opt(9, 34, 33, 0).unwrap();
619        assert_eq!(res, NaiveDateTime::new(naive_date, naive_time));
620    }
621}