1use std::borrow::Cow;
6use std::fmt;
7
8use serde::{Deserialize, Serialize};
9
10#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
12#[non_exhaustive]
13pub enum Value {
14 #[default]
16 Null,
17
18 Bool(bool),
20
21 I8(i8),
23
24 I16(i16),
26
27 I32(i32),
29
30 I64(i64),
32
33 U8(u8),
35
36 U16(u16),
38
39 U32(u32),
41
42 U64(u64),
44
45 F32(f32),
47
48 F64(f64),
50
51 Decimal(String),
53
54 String(String),
56
57 Bytes(Vec<u8>),
59
60 Uuid(String),
62
63 Date(String),
65
66 DateTime(String),
68
69 Time(String),
71
72 Json(String),
74
75 Array(Vec<Value>),
77
78 Object(std::collections::HashMap<String, Value>),
80}
81
82impl Value {
83 pub fn is_null(&self) -> bool {
85 matches!(self, Value::Null)
86 }
87
88 pub fn is_bool(&self) -> bool {
90 matches!(self, Value::Bool(_))
91 }
92
93 pub fn is_i64(&self) -> bool {
95 matches!(self, Value::I64(_))
96 }
97
98 pub fn is_f64(&self) -> bool {
100 matches!(self, Value::F64(_))
101 }
102
103 pub fn is_string(&self) -> bool {
105 matches!(self, Value::String(_))
106 }
107
108 pub fn is_bytes(&self) -> bool {
110 matches!(self, Value::Bytes(_))
111 }
112
113 pub fn is_object(&self) -> bool {
115 matches!(self, Value::Object(_))
116 }
117
118 pub fn from_map(map: std::collections::HashMap<String, Value>) -> Self {
120 Value::Object(map)
121 }
122
123 pub fn as_str(&self) -> Option<&str> {
125 match self {
126 Value::String(s) => Some(s),
127 Value::Decimal(s) => Some(s),
128 _ => None,
129 }
130 }
131
132 pub fn as_i64(&self) -> Option<i64> {
136 match self {
137 Value::I8(v) => Some(*v as i64),
138 Value::I16(v) => Some(*v as i64),
139 Value::I32(v) => Some(*v as i64),
140 Value::I64(v) => Some(*v),
141 Value::U8(v) => Some(*v as i64),
142 Value::U16(v) => Some(*v as i64),
143 Value::U32(v) => Some(*v as i64),
144 Value::U64(v) => i64::try_from(*v).ok(),
145 Value::F32(v) => Some(*v as i64),
146 Value::F64(v) => Some(*v as i64),
147 Value::Bool(v) => Some(if *v { 1 } else { 0 }),
148 Value::String(s) => s.parse::<i64>().ok(),
149 Value::Decimal(s) => s.parse::<i64>().ok(),
150 _ => None,
151 }
152 }
153
154 pub fn as_f64(&self) -> Option<f64> {
157 match self {
158 Value::F32(v) => Some(*v as f64),
159 Value::F64(v) => Some(*v),
160 Value::I8(v) => Some(*v as f64),
161 Value::I16(v) => Some(*v as f64),
162 Value::I32(v) => Some(*v as f64),
163 Value::I64(v) => Some(*v as f64),
164 Value::U8(v) => Some(*v as f64),
165 Value::U16(v) => Some(*v as f64),
166 Value::U32(v) => Some(*v as f64),
167 Value::U64(v) => Some(*v as f64),
168 Value::Bool(v) => Some(if *v { 1.0 } else { 0.0 }),
169 Value::Decimal(s) => s.parse::<f64>().ok(),
170 _ => None,
171 }
172 }
173
174 pub fn as_bool(&self) -> Option<bool> {
177 match self {
178 Value::Bool(v) => Some(*v),
179 Value::I8(v) => Some(*v != 0),
180 Value::I16(v) => Some(*v != 0),
181 Value::I32(v) => Some(*v != 0),
182 Value::I64(v) => Some(*v != 0),
183 Value::U8(v) => Some(*v != 0),
184 Value::U16(v) => Some(*v != 0),
185 Value::U32(v) => Some(*v != 0),
186 Value::U64(v) => Some(*v != 0),
187 Value::F32(v) => Some(*v != 0.0),
188 Value::F64(v) => Some(*v != 0.0),
189 Value::String(s) => match s.to_lowercase().as_str() {
190 "1" | "true" | "yes" | "on" => Some(true),
191 "0" | "false" | "no" | "off" => Some(false),
192 _ => None,
193 },
194 Value::Null => Some(false),
195 _ => None,
196 }
197 }
198
199 pub fn as_bytes(&self) -> Option<&[u8]> {
202 match self {
203 Value::Bytes(v) => Some(v),
204 Value::String(s) => Some(s.as_bytes()),
205 _ => None,
206 }
207 }
208
209 pub fn to_param(&self) -> Cow<'_, str> {
219 match self {
220 Value::Null => Cow::Borrowed("NULL"),
221 Value::Bool(b) => Cow::Owned(if *b { "TRUE" } else { "FALSE" }.to_string()),
222 Value::I8(v) => Cow::Owned(v.to_string()),
223 Value::I16(v) => Cow::Owned(v.to_string()),
224 Value::I32(v) => Cow::Owned(v.to_string()),
225 Value::I64(v) => Cow::Owned(v.to_string()),
226 Value::U8(v) => Cow::Owned(v.to_string()),
227 Value::U16(v) => Cow::Owned(v.to_string()),
228 Value::U32(v) => Cow::Owned(v.to_string()),
229 Value::U64(v) => Cow::Owned(v.to_string()),
230 Value::F32(v) => Cow::Owned(v.to_string()),
231 Value::F64(v) => Cow::Owned(v.to_string()),
232 Value::Decimal(s) => Cow::Owned(s.clone()),
233 Value::String(s) => Cow::Owned(format!("'{}'", escape_string(s))),
234 Value::Bytes(b) => Cow::Owned(format!("X'{}'", hex_encode(b))),
235 Value::Uuid(s) => Cow::Owned(format!("'{}'", escape_string(s))),
236 Value::Date(s) => Cow::Owned(format!("'{}'", escape_string(s))),
237 Value::DateTime(s) => Cow::Owned(format!("'{}'", escape_string(s))),
238 Value::Time(s) => Cow::Owned(format!("'{}'", escape_string(s))),
239 Value::Json(s) => Cow::Owned(format!("'{}'", escape_string(s))),
240 Value::Array(arr) => {
241 let params: Vec<String> = arr.iter().map(|v| v.to_param().into_owned()).collect();
242 Cow::Owned(format!("({})", params.join(", ")))
243 }
244 Value::Object(_) => Cow::Borrowed("NULL"),
245 }
246 }
247
248 pub fn to_param_with_dialect(&self, dialect: &dyn crate::dialect::Dialect) -> Cow<'_, str> {
266 match self {
267 Value::Null => Cow::Borrowed("NULL"),
268 Value::Bool(b) => Cow::Owned(if *b { "TRUE" } else { "FALSE" }.to_string()),
269 Value::I8(v) => Cow::Owned(v.to_string()),
270 Value::I16(v) => Cow::Owned(v.to_string()),
271 Value::I32(v) => Cow::Owned(v.to_string()),
272 Value::I64(v) => Cow::Owned(v.to_string()),
273 Value::U8(v) => Cow::Owned(v.to_string()),
274 Value::U16(v) => Cow::Owned(v.to_string()),
275 Value::U32(v) => Cow::Owned(v.to_string()),
276 Value::U64(v) => Cow::Owned(v.to_string()),
277 Value::F32(v) => Cow::Owned(v.to_string()),
278 Value::F64(v) => Cow::Owned(v.to_string()),
279 Value::Decimal(s) => Cow::Owned(s.clone()),
280 Value::String(s) => Cow::Owned(format!("'{}'", dialect.escape_string(s))),
281 Value::Bytes(b) => Cow::Owned(format!("X'{}'", hex_encode(b))),
282 Value::Uuid(s) => Cow::Owned(format!("'{}'", dialect.escape_string(s))),
283 Value::Date(s) => Cow::Owned(format!("'{}'", dialect.escape_string(s))),
284 Value::DateTime(s) => Cow::Owned(format!("'{}'", dialect.escape_string(s))),
285 Value::Time(s) => Cow::Owned(format!("'{}'", dialect.escape_string(s))),
286 Value::Json(s) => Cow::Owned(format!("'{}'", dialect.escape_string(s))),
287 Value::Array(arr) => {
288 let params: Vec<String> = arr
289 .iter()
290 .map(|v| v.to_param_with_dialect(dialect).into_owned())
291 .collect();
292 Cow::Owned(format!("({})", params.join(", ")))
293 }
294 Value::Object(_) => Cow::Borrowed("NULL"),
295 }
296 }
297
298 pub fn from<T: Into<Value>>(v: T) -> Self {
300 v.into()
301 }
302}
303
304impl fmt::Display for Value {
305 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
306 match self {
307 Value::Null => write!(f, "NULL"),
308 Value::Bool(b) => write!(f, "{}", b),
309 Value::I8(v) => write!(f, "{}", v),
310 Value::I16(v) => write!(f, "{}", v),
311 Value::I32(v) => write!(f, "{}", v),
312 Value::I64(v) => write!(f, "{}", v),
313 Value::U8(v) => write!(f, "{}", v),
314 Value::U16(v) => write!(f, "{}", v),
315 Value::U32(v) => write!(f, "{}", v),
316 Value::U64(v) => write!(f, "{}", v),
317 Value::F32(v) => write!(f, "{}", v),
318 Value::F64(v) => write!(f, "{}", v),
319 Value::Decimal(v) => write!(f, "{}", v),
320 Value::String(v) => write!(f, "'{}'", v),
321 Value::Bytes(v) => write!(f, "X'{}'", hex_encode(v)),
322 Value::Uuid(v) => write!(f, "'{}'", v),
323 Value::Date(v) => write!(f, "'{}'", v),
324 Value::DateTime(v) => write!(f, "'{}'", v),
325 Value::Time(v) => write!(f, "'{}'", v),
326 Value::Json(v) => write!(f, "'{}'", v),
327 Value::Array(v) => {
328 let items: Vec<String> = v.iter().map(|i| format!("{}", i)).collect();
329 write!(f, "({})", items.join(", "))
330 }
331 Value::Object(map) => {
332 let items: Vec<String> = map.iter().map(|(k, v)| format!("{}: {}", k, v)).collect();
333 write!(f, "{{{}}}", items.join(", "))
334 }
335 }
336 }
337}
338
339impl From<()> for Value {
340 fn from(_: ()) -> Self {
341 Value::Null
342 }
343}
344
345impl From<bool> for Value {
346 fn from(v: bool) -> Self {
347 Value::Bool(v)
348 }
349}
350
351impl From<i8> for Value {
352 fn from(v: i8) -> Self {
353 Value::I8(v)
354 }
355}
356
357impl From<i16> for Value {
358 fn from(v: i16) -> Self {
359 Value::I16(v)
360 }
361}
362
363impl From<i32> for Value {
364 fn from(v: i32) -> Self {
365 Value::I32(v)
366 }
367}
368
369impl From<i64> for Value {
370 fn from(v: i64) -> Self {
371 Value::I64(v)
372 }
373}
374
375impl From<u8> for Value {
376 fn from(v: u8) -> Self {
377 Value::U8(v)
378 }
379}
380
381impl From<u16> for Value {
382 fn from(v: u16) -> Self {
383 Value::U16(v)
384 }
385}
386
387impl From<u32> for Value {
388 fn from(v: u32) -> Self {
389 Value::U32(v)
390 }
391}
392
393impl From<u64> for Value {
394 fn from(v: u64) -> Self {
395 Value::U64(v)
396 }
397}
398
399impl From<f32> for Value {
400 fn from(v: f32) -> Self {
401 Value::F32(v)
402 }
403}
404
405impl From<f64> for Value {
406 fn from(v: f64) -> Self {
407 Value::F64(v)
408 }
409}
410
411impl From<String> for Value {
412 fn from(v: String) -> Self {
413 Value::String(v)
414 }
415}
416
417impl From<&str> for Value {
418 fn from(v: &str) -> Self {
419 Value::String(v.to_string())
420 }
421}
422
423impl From<Vec<u8>> for Value {
424 fn from(v: Vec<u8>) -> Self {
425 Value::Bytes(v)
426 }
427}
428
429impl From<&[u8]> for Value {
430 fn from(v: &[u8]) -> Self {
431 Value::Bytes(v.to_vec())
432 }
433}
434
435impl From<Vec<Value>> for Value {
436 fn from(v: Vec<Value>) -> Self {
437 Value::Array(v)
438 }
439}
440
441fn escape_string(s: &str) -> String {
463 let mut escaped = String::with_capacity(s.len() + s.chars().filter(|&c| c == '\'').count());
464 for c in s.chars() {
465 if c == '\'' {
466 escaped.push_str("''");
467 } else {
468 escaped.push(c);
469 }
470 }
471 escaped
472}
473
474fn hex_encode(bytes: &[u8]) -> String {
475 bytes.iter().map(|b| format!("{:02x}", b)).collect()
476}
477
478#[derive(Debug, Clone, Copy, PartialEq, Eq)]
489#[non_exhaustive]
490pub enum ColType {
491 Bool,
493 I8,
495 I16,
497 I32,
499 I64,
501 U8,
503 U16,
505 U32,
507 U64,
509 F32,
511 F64,
513 Decimal,
515 String,
517 Bytes,
519 Date,
521 DateTime,
523 Time,
525 Json,
527 Uuid,
529 Unknown,
531}
532
533impl ColType {
534 pub fn from_type_name(type_name: &str) -> Self {
546 match type_name {
547 "BOOLEAN" | "BOOL" => Self::Bool,
548 "TINYINT" => Self::I8,
549 "SMALLINT" | "INT2" => Self::I16,
550 "INT" | "INT4" | "OID" | "MEDIUMINT" | "INTEGER" => Self::I32,
551 "BIGINT" | "INT8" => Self::I64,
552 "TINYINT UNSIGNED" => Self::U8,
553 "SMALLINT UNSIGNED" => Self::U16,
554 "INT UNSIGNED" | "MEDIUMINT UNSIGNED" => Self::U32,
555 "BIGINT UNSIGNED" => Self::U64,
556 "FLOAT" | "FLOAT4" | "REAL" => Self::F32,
557 "DOUBLE" | "FLOAT8" => Self::F64,
558 "DECIMAL" | "NUMERIC" | "NEWDECIMAL" | "MONEY" => Self::Decimal,
559 "TEXT" | "VARCHAR" | "CHAR" | "NAME" => Self::String,
560 "BLOB" | "BYTEA" => Self::Bytes,
561 "DATE" => Self::Date,
562 "DATETIME" | "TIMESTAMP" => Self::DateTime,
563 "TIME" => Self::Time,
564 "JSON" => Self::Json,
565 "UUID" => Self::Uuid,
566 _ => Self::Unknown,
567 }
568 }
569
570 pub fn parse_sqlite(type_name: &str) -> Self {
586 if type_name.is_empty() {
588 return Self::Unknown;
589 }
590 match type_name.to_uppercase().as_str() {
591 "INTEGER" | "INT" | "BIGINT" | "INT8" | "INT4" | "INT2" | "TINYINT" | "SMALLINT"
593 | "MEDIUMINT" => Self::I64,
594 "BOOLEAN" | "BOOL" => Self::Bool,
595 "REAL" | "FLOAT" | "DOUBLE" | "FLOAT8" | "DOUBLE PRECISION" => Self::F64,
596 "DECIMAL" | "NUMERIC" => Self::Decimal,
597 "TEXT" | "CLOB" | "VARCHAR" | "CHAR" | "NAME" => Self::String,
598 "BLOB" => Self::Bytes,
599 "DATE" => Self::Date,
600 "DATETIME" | "TIMESTAMP" => Self::DateTime,
601 "TIME" => Self::Time,
602 "JSON" => Self::Json,
603 _ => Self::Unknown,
604 }
605 }
606
607 pub fn parse_mysql(type_name: &str) -> Self {
611 match type_name.to_uppercase().as_str() {
612 "TINYINT" => Self::I8,
613 "SMALLINT" => Self::I16,
614 "INT" | "INTEGER" | "MEDIUMINT" => Self::I32,
615 "BIGINT" => Self::I64,
616 "TINYINT UNSIGNED" => Self::U8,
617 "SMALLINT UNSIGNED" => Self::U16,
618 "INT UNSIGNED" | "MEDIUMINT UNSIGNED" => Self::U32,
619 "BIGINT UNSIGNED" => Self::U64,
620 "FLOAT" => Self::F32,
621 "DOUBLE" => Self::F64,
622 "DECIMAL" | "NUMERIC" | "NEWDECIMAL" => Self::Decimal,
623 "VARCHAR" | "CHAR" | "TEXT" | "TINYTEXT" | "MEDIUMTEXT" | "LONGTEXT" | "ENUM"
624 | "SET" => Self::String,
625 "BLOB" | "TINYBLOB" | "MEDIUMBLOB" | "LONGBLOB" | "BINARY" | "VARBINARY" => Self::Bytes,
626 "DATE" => Self::Date,
627 "DATETIME" | "TIMESTAMP" => Self::DateTime,
628 "TIME" => Self::Time,
629 "YEAR" => Self::I16,
630 "JSON" => Self::Json,
631 "BOOLEAN" | "BOOL" => Self::Bool,
632 _ => Self::from_type_name(type_name),
633 }
634 }
635
636 pub fn parse_postgres(type_name: &str) -> Self {
640 match type_name.to_uppercase().as_str() {
641 "BOOL" => Self::Bool,
642 "INT2" | "SMALLINT" => Self::I16,
643 "INT4" | "INTEGER" | "INT" => Self::I32,
644 "INT8" | "BIGINT" => Self::I64,
645 "FLOAT4" | "REAL" => Self::F32,
646 "FLOAT8" | "DOUBLE PRECISION" => Self::F64,
647 "NUMERIC" | "DECIMAL" | "MONEY" => Self::Decimal,
648 "TEXT" | "VARCHAR" | "CHAR" | "BPCHAR" | "NAME" | "CITEXT" => Self::String,
649 "BYTEA" => Self::Bytes,
650 "DATE" => Self::Date,
651 "TIMESTAMP" | "TIMESTAMPTZ" => Self::DateTime,
652 "TIME" | "TIMETZ" => Self::Time,
653 "JSON" | "JSONB" => Self::Json,
654 "UUID" => Self::Uuid,
655 "OID" => Self::I32,
656 _ => Self::from_type_name(type_name),
657 }
658 }
659}
660
661pub type QueryValues = (Vec<String>, Vec<Vec<Value>>);
681
682#[cfg(test)]
683mod tests {
684 use super::*;
685
686 #[test]
687 fn test_value_is_null() {
688 assert!(Value::Null.is_null());
689 assert!(!Value::I64(0).is_null());
690 }
691
692 #[test]
693 fn test_col_type_from_type_name() {
694 assert_eq!(ColType::from_type_name("BOOLEAN"), ColType::Bool);
696 assert_eq!(ColType::from_type_name("TINYINT"), ColType::I8);
697 assert_eq!(ColType::from_type_name("SMALLINT"), ColType::I16);
698 assert_eq!(ColType::from_type_name("INT"), ColType::I32);
699 assert_eq!(ColType::from_type_name("BIGINT"), ColType::I64);
700 assert_eq!(ColType::from_type_name("INT UNSIGNED"), ColType::U32);
701 assert_eq!(ColType::from_type_name("FLOAT"), ColType::F32);
702 assert_eq!(ColType::from_type_name("DOUBLE"), ColType::F64);
703 assert_eq!(ColType::from_type_name("TEXT"), ColType::String);
704 assert_eq!(ColType::from_type_name("BLOB"), ColType::Bytes);
705 assert_eq!(ColType::from_type_name("DATE"), ColType::Date);
706 assert_eq!(ColType::from_type_name("TIMESTAMP"), ColType::DateTime);
707 assert_eq!(ColType::from_type_name("JSON"), ColType::Json);
708 assert_eq!(ColType::from_type_name("INT2"), ColType::I16);
710 assert_eq!(ColType::from_type_name("INT4"), ColType::I32);
711 assert_eq!(ColType::from_type_name("INT8"), ColType::I64);
712 assert_eq!(ColType::from_type_name("FLOAT4"), ColType::F32);
713 assert_eq!(ColType::from_type_name("FLOAT8"), ColType::F64);
714 assert_eq!(ColType::from_type_name("BYTEA"), ColType::Bytes);
715 assert_eq!(ColType::from_type_name("UNKNOWN_TYPE"), ColType::Unknown);
717 assert_eq!(ColType::from_type_name(""), ColType::Unknown);
718 }
719
720 #[test]
721 fn test_value_as_i64() {
722 assert_eq!(Value::I64(42).as_i64(), Some(42));
723 assert_eq!(Value::I32(42).as_i64(), Some(42));
724 assert_eq!(Value::Bool(true).as_i64(), Some(1));
725 assert!(Value::String("test".to_string()).as_i64().is_none());
726 }
727
728 #[test]
729 fn test_value_as_f64() {
730 assert_eq!(Value::F64(2.5).as_f64(), Some(2.5));
731 assert_eq!(Value::I64(42).as_f64(), Some(42.0));
732 }
733
734 #[test]
735 fn test_value_as_str() {
736 assert_eq!(Value::String("hello".to_string()).as_str(), Some("hello"));
737 }
738
739 #[test]
740 fn test_value_to_param() {
741 assert_eq!(Value::Null.to_param(), "NULL");
742 assert_eq!(Value::Bool(true).to_param(), "TRUE");
743 assert_eq!(Value::I64(42).to_param(), "42");
744 assert_eq!(Value::String("test".to_string()).to_param(), "'test'");
745 assert_eq!(Value::String("it's".to_string()).to_param(), "'it''s'");
746 }
747
748 #[test]
749 fn test_value_into() {
750 let v: Value = 42i64.into();
751 assert_eq!(v, Value::I64(42));
752
753 let v: Value = "hello".into();
754 assert_eq!(v, Value::String("hello".to_string()));
755
756 let arr: Vec<Value> = vec![Value::I64(1), Value::I64(2)];
757 let v: Value = arr.into();
758 assert_eq!(v, Value::Array(vec![Value::I64(1), Value::I64(2)]));
759 }
760
761 #[test]
762 fn test_value_display() {
763 assert_eq!(format!("{}", Value::Null), "NULL");
764 assert_eq!(format!("{}", Value::Bool(true)), "true");
765 assert_eq!(format!("{}", Value::I64(42)), "42");
766 assert_eq!(format!("{}", Value::String("test".to_string())), "'test'");
767 }
768}