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 String(String),
53
54 Bytes(Vec<u8>),
56
57 Uuid(String),
59
60 Date(String),
62
63 DateTime(String),
65
66 Time(String),
68
69 Json(String),
71
72 Array(Vec<Value>),
74
75 Object(std::collections::HashMap<String, Value>),
77}
78
79impl Value {
80 pub fn is_null(&self) -> bool {
82 matches!(self, Value::Null)
83 }
84
85 pub fn is_bool(&self) -> bool {
87 matches!(self, Value::Bool(_))
88 }
89
90 pub fn is_i64(&self) -> bool {
92 matches!(self, Value::I64(_))
93 }
94
95 pub fn is_f64(&self) -> bool {
97 matches!(self, Value::F64(_))
98 }
99
100 pub fn is_string(&self) -> bool {
102 matches!(self, Value::String(_))
103 }
104
105 pub fn is_bytes(&self) -> bool {
107 matches!(self, Value::Bytes(_))
108 }
109
110 pub fn is_object(&self) -> bool {
112 matches!(self, Value::Object(_))
113 }
114
115 pub fn from_map(map: std::collections::HashMap<String, Value>) -> Self {
117 Value::Object(map)
118 }
119
120 pub fn as_str(&self) -> Option<&str> {
122 match self {
123 Value::String(s) => Some(s),
124 _ => None,
125 }
126 }
127
128 pub fn as_i64(&self) -> Option<i64> {
132 match self {
133 Value::I8(v) => Some(*v as i64),
134 Value::I16(v) => Some(*v as i64),
135 Value::I32(v) => Some(*v as i64),
136 Value::I64(v) => Some(*v),
137 Value::U8(v) => Some(*v as i64),
138 Value::U16(v) => Some(*v as i64),
139 Value::U32(v) => Some(*v as i64),
140 Value::U64(v) => i64::try_from(*v).ok(),
141 Value::F32(v) => Some(*v as i64),
142 Value::F64(v) => Some(*v as i64),
143 Value::Bool(v) => Some(if *v { 1 } else { 0 }),
144 Value::String(s) => s.parse::<i64>().ok(),
145 _ => None,
146 }
147 }
148
149 pub fn as_f64(&self) -> Option<f64> {
152 match self {
153 Value::F32(v) => Some(*v as f64),
154 Value::F64(v) => Some(*v),
155 Value::I8(v) => Some(*v as f64),
156 Value::I16(v) => Some(*v as f64),
157 Value::I32(v) => Some(*v as f64),
158 Value::I64(v) => Some(*v as f64),
159 Value::U8(v) => Some(*v as f64),
160 Value::U16(v) => Some(*v as f64),
161 Value::U32(v) => Some(*v as f64),
162 Value::U64(v) => Some(*v as f64),
163 Value::Bool(v) => Some(if *v { 1.0 } else { 0.0 }),
164 _ => None,
165 }
166 }
167
168 pub fn as_bool(&self) -> Option<bool> {
171 match self {
172 Value::Bool(v) => Some(*v),
173 Value::I8(v) => Some(*v != 0),
174 Value::I16(v) => Some(*v != 0),
175 Value::I32(v) => Some(*v != 0),
176 Value::I64(v) => Some(*v != 0),
177 Value::U8(v) => Some(*v != 0),
178 Value::U16(v) => Some(*v != 0),
179 Value::U32(v) => Some(*v != 0),
180 Value::U64(v) => Some(*v != 0),
181 Value::F32(v) => Some(*v != 0.0),
182 Value::F64(v) => Some(*v != 0.0),
183 Value::String(s) => match s.to_lowercase().as_str() {
184 "1" | "true" | "yes" | "on" => Some(true),
185 "0" | "false" | "no" | "off" => Some(false),
186 _ => None,
187 },
188 Value::Null => Some(false),
189 _ => None,
190 }
191 }
192
193 pub fn as_bytes(&self) -> Option<&[u8]> {
196 match self {
197 Value::Bytes(v) => Some(v),
198 Value::String(s) => Some(s.as_bytes()),
199 _ => None,
200 }
201 }
202
203 pub fn to_param(&self) -> Cow<'_, str> {
213 match self {
214 Value::Null => Cow::Borrowed("NULL"),
215 Value::Bool(b) => Cow::Owned(if *b { "TRUE" } else { "FALSE" }.to_string()),
216 Value::I8(v) => Cow::Owned(v.to_string()),
217 Value::I16(v) => Cow::Owned(v.to_string()),
218 Value::I32(v) => Cow::Owned(v.to_string()),
219 Value::I64(v) => Cow::Owned(v.to_string()),
220 Value::U8(v) => Cow::Owned(v.to_string()),
221 Value::U16(v) => Cow::Owned(v.to_string()),
222 Value::U32(v) => Cow::Owned(v.to_string()),
223 Value::U64(v) => Cow::Owned(v.to_string()),
224 Value::F32(v) => Cow::Owned(v.to_string()),
225 Value::F64(v) => Cow::Owned(v.to_string()),
226 Value::String(s) => Cow::Owned(format!("'{}'", escape_string(s))),
227 Value::Bytes(b) => Cow::Owned(format!("X'{}'", hex_encode(b))),
228 Value::Uuid(s) => Cow::Owned(format!("'{}'", escape_string(s))),
229 Value::Date(s) => Cow::Owned(format!("'{}'", escape_string(s))),
230 Value::DateTime(s) => Cow::Owned(format!("'{}'", escape_string(s))),
231 Value::Time(s) => Cow::Owned(format!("'{}'", escape_string(s))),
232 Value::Json(s) => Cow::Owned(format!("'{}'", escape_string(s))),
233 Value::Array(arr) => {
234 let params: Vec<String> = arr.iter().map(|v| v.to_param().into_owned()).collect();
235 Cow::Owned(format!("({})", params.join(", ")))
236 }
237 Value::Object(_) => Cow::Borrowed("NULL"),
238 }
239 }
240
241 pub fn to_param_with_dialect(&self, dialect: &dyn crate::dialect::Dialect) -> Cow<'_, str> {
259 match self {
260 Value::Null => Cow::Borrowed("NULL"),
261 Value::Bool(b) => Cow::Owned(if *b { "TRUE" } else { "FALSE" }.to_string()),
262 Value::I8(v) => Cow::Owned(v.to_string()),
263 Value::I16(v) => Cow::Owned(v.to_string()),
264 Value::I32(v) => Cow::Owned(v.to_string()),
265 Value::I64(v) => Cow::Owned(v.to_string()),
266 Value::U8(v) => Cow::Owned(v.to_string()),
267 Value::U16(v) => Cow::Owned(v.to_string()),
268 Value::U32(v) => Cow::Owned(v.to_string()),
269 Value::U64(v) => Cow::Owned(v.to_string()),
270 Value::F32(v) => Cow::Owned(v.to_string()),
271 Value::F64(v) => Cow::Owned(v.to_string()),
272 Value::String(s) => Cow::Owned(format!("'{}'", dialect.escape_string(s))),
273 Value::Bytes(b) => Cow::Owned(format!("X'{}'", hex_encode(b))),
274 Value::Uuid(s) => Cow::Owned(format!("'{}'", dialect.escape_string(s))),
275 Value::Date(s) => Cow::Owned(format!("'{}'", dialect.escape_string(s))),
276 Value::DateTime(s) => Cow::Owned(format!("'{}'", dialect.escape_string(s))),
277 Value::Time(s) => Cow::Owned(format!("'{}'", dialect.escape_string(s))),
278 Value::Json(s) => Cow::Owned(format!("'{}'", dialect.escape_string(s))),
279 Value::Array(arr) => {
280 let params: Vec<String> = arr
281 .iter()
282 .map(|v| v.to_param_with_dialect(dialect).into_owned())
283 .collect();
284 Cow::Owned(format!("({})", params.join(", ")))
285 }
286 Value::Object(_) => Cow::Borrowed("NULL"),
287 }
288 }
289
290 pub fn from<T: Into<Value>>(v: T) -> Self {
292 v.into()
293 }
294}
295
296impl fmt::Display for Value {
297 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
298 match self {
299 Value::Null => write!(f, "NULL"),
300 Value::Bool(b) => write!(f, "{}", b),
301 Value::I8(v) => write!(f, "{}", v),
302 Value::I16(v) => write!(f, "{}", v),
303 Value::I32(v) => write!(f, "{}", v),
304 Value::I64(v) => write!(f, "{}", v),
305 Value::U8(v) => write!(f, "{}", v),
306 Value::U16(v) => write!(f, "{}", v),
307 Value::U32(v) => write!(f, "{}", v),
308 Value::U64(v) => write!(f, "{}", v),
309 Value::F32(v) => write!(f, "{}", v),
310 Value::F64(v) => write!(f, "{}", v),
311 Value::String(v) => write!(f, "'{}'", v),
312 Value::Bytes(v) => write!(f, "X'{}'", hex_encode(v)),
313 Value::Uuid(v) => write!(f, "'{}'", v),
314 Value::Date(v) => write!(f, "'{}'", v),
315 Value::DateTime(v) => write!(f, "'{}'", v),
316 Value::Time(v) => write!(f, "'{}'", v),
317 Value::Json(v) => write!(f, "'{}'", v),
318 Value::Array(v) => {
319 let items: Vec<String> = v.iter().map(|i| format!("{}", i)).collect();
320 write!(f, "({})", items.join(", "))
321 }
322 Value::Object(map) => {
323 let items: Vec<String> = map.iter().map(|(k, v)| format!("{}: {}", k, v)).collect();
324 write!(f, "{{{}}}", items.join(", "))
325 }
326 }
327 }
328}
329
330impl From<()> for Value {
331 fn from(_: ()) -> Self {
332 Value::Null
333 }
334}
335
336impl From<bool> for Value {
337 fn from(v: bool) -> Self {
338 Value::Bool(v)
339 }
340}
341
342impl From<i8> for Value {
343 fn from(v: i8) -> Self {
344 Value::I8(v)
345 }
346}
347
348impl From<i16> for Value {
349 fn from(v: i16) -> Self {
350 Value::I16(v)
351 }
352}
353
354impl From<i32> for Value {
355 fn from(v: i32) -> Self {
356 Value::I32(v)
357 }
358}
359
360impl From<i64> for Value {
361 fn from(v: i64) -> Self {
362 Value::I64(v)
363 }
364}
365
366impl From<u8> for Value {
367 fn from(v: u8) -> Self {
368 Value::U8(v)
369 }
370}
371
372impl From<u16> for Value {
373 fn from(v: u16) -> Self {
374 Value::U16(v)
375 }
376}
377
378impl From<u32> for Value {
379 fn from(v: u32) -> Self {
380 Value::U32(v)
381 }
382}
383
384impl From<u64> for Value {
385 fn from(v: u64) -> Self {
386 Value::U64(v)
387 }
388}
389
390impl From<f32> for Value {
391 fn from(v: f32) -> Self {
392 Value::F32(v)
393 }
394}
395
396impl From<f64> for Value {
397 fn from(v: f64) -> Self {
398 Value::F64(v)
399 }
400}
401
402impl From<String> for Value {
403 fn from(v: String) -> Self {
404 Value::String(v)
405 }
406}
407
408impl From<&str> for Value {
409 fn from(v: &str) -> Self {
410 Value::String(v.to_string())
411 }
412}
413
414impl From<Vec<u8>> for Value {
415 fn from(v: Vec<u8>) -> Self {
416 Value::Bytes(v)
417 }
418}
419
420impl From<&[u8]> for Value {
421 fn from(v: &[u8]) -> Self {
422 Value::Bytes(v.to_vec())
423 }
424}
425
426impl From<Vec<Value>> for Value {
427 fn from(v: Vec<Value>) -> Self {
428 Value::Array(v)
429 }
430}
431
432fn escape_string(s: &str) -> String {
454 let mut escaped = String::with_capacity(s.len() + s.chars().filter(|&c| c == '\'').count());
455 for c in s.chars() {
456 if c == '\'' {
457 escaped.push_str("''");
458 } else {
459 escaped.push(c);
460 }
461 }
462 escaped
463}
464
465fn hex_encode(bytes: &[u8]) -> String {
466 bytes.iter().map(|b| format!("{:02x}", b)).collect()
467}
468
469#[cfg(test)]
470mod tests {
471 use super::*;
472
473 #[test]
474 fn test_value_is_null() {
475 assert!(Value::Null.is_null());
476 assert!(!Value::I64(0).is_null());
477 }
478
479 #[test]
480 fn test_value_as_i64() {
481 assert_eq!(Value::I64(42).as_i64(), Some(42));
482 assert_eq!(Value::I32(42).as_i64(), Some(42));
483 assert_eq!(Value::Bool(true).as_i64(), Some(1));
484 assert!(Value::String("test".to_string()).as_i64().is_none());
485 }
486
487 #[test]
488 fn test_value_as_f64() {
489 assert_eq!(Value::F64(2.5).as_f64(), Some(2.5));
490 assert_eq!(Value::I64(42).as_f64(), Some(42.0));
491 }
492
493 #[test]
494 fn test_value_as_str() {
495 assert_eq!(Value::String("hello".to_string()).as_str(), Some("hello"));
496 }
497
498 #[test]
499 fn test_value_to_param() {
500 assert_eq!(Value::Null.to_param(), "NULL");
501 assert_eq!(Value::Bool(true).to_param(), "TRUE");
502 assert_eq!(Value::I64(42).to_param(), "42");
503 assert_eq!(Value::String("test".to_string()).to_param(), "'test'");
504 assert_eq!(Value::String("it's".to_string()).to_param(), "'it''s'");
505 }
506
507 #[test]
508 fn test_value_into() {
509 let v: Value = 42i64.into();
510 assert_eq!(v, Value::I64(42));
511
512 let v: Value = "hello".into();
513 assert_eq!(v, Value::String("hello".to_string()));
514
515 let arr: Vec<Value> = vec![Value::I64(1), Value::I64(2)];
516 let v: Value = arr.into();
517 assert_eq!(v, Value::Array(vec![Value::I64(1), Value::I64(2)]));
518 }
519
520 #[test]
521 fn test_value_display() {
522 assert_eq!(format!("{}", Value::Null), "NULL");
523 assert_eq!(format!("{}", Value::Bool(true)), "true");
524 assert_eq!(format!("{}", Value::I64(42)), "42");
525 assert_eq!(format!("{}", Value::String("test".to_string())), "'test'");
526 }
527}