Skip to main content

kimberlite_query/
value.rs

1//! Typed SQL values.
2
3#![allow(clippy::match_same_arms)]
4
5use std::cmp::Ordering;
6use std::fmt::{self, Display};
7
8use bytes::Bytes;
9use kimberlite_types::Timestamp;
10use serde::{Deserialize, Serialize};
11
12use crate::error::{QueryError, Result};
13use crate::schema::DataType;
14
15/// A typed SQL value.
16///
17/// Represents values that can appear in query parameters, row data,
18/// and comparison predicates.
19///
20/// Note: Real and Decimal types use total ordering (NaN < -Inf < values < Inf)
21/// for comparisons to enable use in B+tree indexes.
22#[derive(Debug, Clone, Default, Serialize, Deserialize)]
23#[serde(untagged)]
24pub enum Value {
25    /// SQL NULL.
26    #[default]
27    Null,
28
29    // ===== Integer Types =====
30    /// 8-bit signed integer (-128 to 127).
31    TinyInt(i8),
32    /// 16-bit signed integer (-32,768 to 32,767).
33    SmallInt(i16),
34    /// 32-bit signed integer (-2^31 to 2^31-1).
35    Integer(i32),
36    /// 64-bit signed integer (-2^63 to 2^63-1).
37    BigInt(i64),
38
39    // ===== Numeric Types =====
40    /// 64-bit floating point (IEEE 754 double precision).
41    Real(f64),
42    /// Fixed-precision decimal (value in smallest units, scale).
43    ///
44    /// Stored as (i128, u8) where the second field is the scale.
45    /// Example: Decimal(12345, 2) represents 123.45
46    #[serde(skip)] // Complex serialization, handled separately
47    Decimal(i128, u8),
48
49    // ===== String Types =====
50    /// UTF-8 text string.
51    Text(String),
52
53    // ===== Binary Types =====
54    /// Raw bytes (base64 encoded in JSON).
55    #[serde(with = "bytes_base64")]
56    Bytes(Bytes),
57
58    // ===== Boolean Type =====
59    /// Boolean value.
60    Boolean(bool),
61
62    // ===== Date/Time Types =====
63    /// Date (days since Unix epoch).
64    Date(i32),
65    /// Time of day (nanoseconds within day).
66    Time(i64),
67    /// Timestamp (nanoseconds since Unix epoch).
68    Timestamp(Timestamp),
69
70    // ===== Structured Types =====
71    /// UUID (RFC 4122, 128-bit).
72    Uuid([u8; 16]),
73    /// JSON document (validated).
74    Json(serde_json::Value),
75
76    /// Parameter placeholder ($1, $2, etc.) - 1-indexed.
77    /// This is an intermediate representation used during parsing,
78    /// and should be bound to actual values before execution.
79    #[serde(skip)]
80    Placeholder(usize),
81}
82
83impl PartialEq for Value {
84    fn eq(&self, other: &Self) -> bool {
85        match (self, other) {
86            (Value::Null, Value::Null) => true,
87            (Value::TinyInt(a), Value::TinyInt(b)) => a == b,
88            (Value::SmallInt(a), Value::SmallInt(b)) => a == b,
89            (Value::Integer(a), Value::Integer(b)) => a == b,
90            (Value::BigInt(a), Value::BigInt(b)) => a == b,
91            (Value::Real(a), Value::Real(b)) => {
92                // Use total ordering for floats: NaN == NaN
93                a.to_bits() == b.to_bits()
94            }
95            (Value::Decimal(a_val, a_scale), Value::Decimal(b_val, b_scale)) => {
96                a_val == b_val && a_scale == b_scale
97            }
98            (Value::Text(a), Value::Text(b)) => a == b,
99            (Value::Bytes(a), Value::Bytes(b)) => a == b,
100            (Value::Boolean(a), Value::Boolean(b)) => a == b,
101            (Value::Date(a), Value::Date(b)) => a == b,
102            (Value::Time(a), Value::Time(b)) => a == b,
103            (Value::Timestamp(a), Value::Timestamp(b)) => a == b,
104            (Value::Uuid(a), Value::Uuid(b)) => a == b,
105            (Value::Json(a), Value::Json(b)) => a == b,
106            (Value::Placeholder(a), Value::Placeholder(b)) => a == b,
107            _ => false, // Different types are not equal
108        }
109    }
110}
111
112impl Eq for Value {}
113
114impl std::hash::Hash for Value {
115    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
116        // Hash the discriminant first
117        std::mem::discriminant(self).hash(state);
118
119        // Hash the value based on type
120        match self {
121            Value::Null => {}
122            Value::TinyInt(v) => v.hash(state),
123            Value::SmallInt(v) => v.hash(state),
124            Value::Integer(v) => v.hash(state),
125            Value::BigInt(v) => v.hash(state),
126            Value::Real(v) => v.to_bits().hash(state), // Use total ordering
127            Value::Decimal(val, scale) => {
128                val.hash(state);
129                scale.hash(state);
130            }
131            Value::Text(v) => v.hash(state),
132            Value::Bytes(v) => v.hash(state),
133            Value::Boolean(v) => v.hash(state),
134            Value::Date(v) => v.hash(state),
135            Value::Time(v) => v.hash(state),
136            Value::Timestamp(v) => v.hash(state),
137            Value::Uuid(v) => v.hash(state),
138            Value::Json(v) => v.to_string().hash(state), // Hash JSON string representation
139            Value::Placeholder(v) => v.hash(state),
140        }
141    }
142}
143
144/// Parses a decimal string like "123.45" with a given scale.
145fn parse_decimal_string(s: &str, scale: u8) -> Result<i128> {
146    let parts: Vec<&str> = s.split('.').collect();
147    match parts.as_slice() {
148        [int_part] => {
149            // No decimal point: "123" -> 12300 (with scale=2)
150            let int_val: i128 = int_part.parse().map_err(|_| QueryError::TypeMismatch {
151                expected: format!("decimal with scale {scale}"),
152                actual: s.to_string(),
153            })?;
154            Ok(int_val * 10_i128.pow(u32::from(scale)))
155        }
156        [int_part, frac_part] => {
157            // With decimal point: "123.45" -> 12345 (with scale=2)
158            let int_val: i128 = int_part.parse().map_err(|_| QueryError::TypeMismatch {
159                expected: format!("decimal with scale {scale}"),
160                actual: s.to_string(),
161            })?;
162
163            // Pad or truncate fractional part to match scale
164            let mut frac_str = (*frac_part).to_string();
165            if frac_str.len() > scale as usize {
166                frac_str.truncate(scale as usize);
167            } else {
168                frac_str.push_str(&"0".repeat(scale as usize - frac_str.len()));
169            }
170
171            let frac_val: i128 = frac_str.parse().map_err(|_| QueryError::TypeMismatch {
172                expected: format!("decimal with scale {scale}"),
173                actual: s.to_string(),
174            })?;
175
176            let multiplier = 10_i128.pow(u32::from(scale));
177            Ok(int_val * multiplier + frac_val)
178        }
179        _ => Err(QueryError::TypeMismatch {
180            expected: format!("decimal with scale {scale}"),
181            actual: s.to_string(),
182        }),
183    }
184}
185
186/// Parses a UUID string (hyphenated or raw hex).
187fn parse_uuid_string(s: &str) -> Result<[u8; 16]> {
188    // Remove hyphens if present
189    let hex_str = s.replace('-', "");
190
191    if hex_str.len() != 32 {
192        return Err(QueryError::TypeMismatch {
193            expected: "UUID (32 hex digits)".to_string(),
194            actual: s.to_string(),
195        });
196    }
197
198    let mut bytes = [0u8; 16];
199    for (i, chunk) in hex_str.as_bytes().chunks(2).enumerate() {
200        let hex_byte = std::str::from_utf8(chunk).map_err(|_| QueryError::TypeMismatch {
201            expected: "UUID (valid hex)".to_string(),
202            actual: s.to_string(),
203        })?;
204
205        bytes[i] = u8::from_str_radix(hex_byte, 16).map_err(|_| QueryError::TypeMismatch {
206            expected: "UUID (valid hex)".to_string(),
207            actual: s.to_string(),
208        })?;
209    }
210
211    Ok(bytes)
212}
213
214/// Total ordering for f64 values.
215///
216/// NaN < -Inf < negative values < -0.0 < +0.0 < positive values < +Inf
217///
218/// This enables f64 values to be used as B+tree keys.
219fn total_cmp_f64(a: f64, b: f64) -> Ordering {
220    // Use bit representation for total ordering
221    let a_bits = a.to_bits();
222    let b_bits = b.to_bits();
223
224    // Flip sign bit for negatives to get correct ordering
225    let a_key = if a.is_sign_negative() {
226        !a_bits
227    } else {
228        a_bits ^ (1u64 << 63)
229    };
230
231    let b_key = if b.is_sign_negative() {
232        !b_bits
233    } else {
234        b_bits ^ (1u64 << 63)
235    };
236
237    a_key.cmp(&b_key)
238}
239
240impl Value {
241    /// Returns the data type of this value.
242    ///
243    /// Returns `None` for `Null` and `Placeholder` since they have no concrete type.
244    pub fn data_type(&self) -> Option<DataType> {
245        match self {
246            Value::Null | Value::Placeholder(_) => None,
247            Value::TinyInt(_) => Some(DataType::TinyInt),
248            Value::SmallInt(_) => Some(DataType::SmallInt),
249            Value::Integer(_) => Some(DataType::Integer),
250            Value::BigInt(_) => Some(DataType::BigInt),
251            Value::Real(_) => Some(DataType::Real),
252            Value::Decimal(_, scale) => Some(DataType::Decimal {
253                precision: 38, // Max precision for i128
254                scale: *scale,
255            }),
256            Value::Text(_) => Some(DataType::Text),
257            Value::Bytes(_) => Some(DataType::Bytes),
258            Value::Boolean(_) => Some(DataType::Boolean),
259            Value::Date(_) => Some(DataType::Date),
260            Value::Time(_) => Some(DataType::Time),
261            Value::Timestamp(_) => Some(DataType::Timestamp),
262            Value::Uuid(_) => Some(DataType::Uuid),
263            Value::Json(_) => Some(DataType::Json),
264        }
265    }
266
267    /// Returns true if this value is NULL.
268    pub fn is_null(&self) -> bool {
269        matches!(self, Value::Null)
270    }
271
272    /// Returns the value as an i64, if it is a `BigInt`.
273    pub fn as_bigint(&self) -> Option<i64> {
274        match self {
275            Value::BigInt(v) => Some(*v),
276            _ => None,
277        }
278    }
279
280    /// Returns the value as a string slice, if it is Text.
281    pub fn as_text(&self) -> Option<&str> {
282        match self {
283            Value::Text(s) => Some(s),
284            _ => None,
285        }
286    }
287
288    /// Returns the value as a bool, if it is Boolean.
289    pub fn as_boolean(&self) -> Option<bool> {
290        match self {
291            Value::Boolean(b) => Some(*b),
292            _ => None,
293        }
294    }
295
296    /// Returns the value as a Timestamp, if it is Timestamp.
297    pub fn as_timestamp(&self) -> Option<Timestamp> {
298        match self {
299            Value::Timestamp(ts) => Some(*ts),
300            _ => None,
301        }
302    }
303
304    /// Returns the value as bytes, if it is Bytes.
305    pub fn as_bytes(&self) -> Option<&Bytes> {
306        match self {
307            Value::Bytes(b) => Some(b),
308            _ => None,
309        }
310    }
311
312    /// Returns the value as an i8, if it is a `TinyInt`.
313    pub fn as_tinyint(&self) -> Option<i8> {
314        match self {
315            Value::TinyInt(v) => Some(*v),
316            _ => None,
317        }
318    }
319
320    /// Returns the value as an i16, if it is a `SmallInt`.
321    pub fn as_smallint(&self) -> Option<i16> {
322        match self {
323            Value::SmallInt(v) => Some(*v),
324            _ => None,
325        }
326    }
327
328    /// Returns the value as an i32, if it is an `Integer`.
329    pub fn as_integer(&self) -> Option<i32> {
330        match self {
331            Value::Integer(v) => Some(*v),
332            _ => None,
333        }
334    }
335
336    /// Returns the value as an f64, if it is a `Real`.
337    pub fn as_real(&self) -> Option<f64> {
338        match self {
339            Value::Real(v) => Some(*v),
340            _ => None,
341        }
342    }
343
344    /// Returns the value as a `Decimal` (value, scale), if it is a `Decimal`.
345    pub fn as_decimal(&self) -> Option<(i128, u8)> {
346        match self {
347            Value::Decimal(v, s) => Some((*v, *s)),
348            _ => None,
349        }
350    }
351
352    /// Returns the value as a `Uuid`, if it is a `Uuid`.
353    pub fn as_uuid(&self) -> Option<&[u8; 16]> {
354        match self {
355            Value::Uuid(u) => Some(u),
356            _ => None,
357        }
358    }
359
360    /// Returns the value as a `Json`, if it is a `Json`.
361    pub fn as_json(&self) -> Option<&serde_json::Value> {
362        match self {
363            Value::Json(j) => Some(j),
364            _ => None,
365        }
366    }
367
368    /// Returns the value as a `Date`, if it is a `Date`.
369    pub fn as_date(&self) -> Option<i32> {
370        match self {
371            Value::Date(d) => Some(*d),
372            _ => None,
373        }
374    }
375
376    /// Returns the value as a `Time`, if it is a `Time`.
377    pub fn as_time(&self) -> Option<i64> {
378        match self {
379            Value::Time(t) => Some(*t),
380            _ => None,
381        }
382    }
383
384    /// Compares two values for ordering.
385    ///
386    /// NULL values are considered less than all non-NULL values.
387    /// Values of different types return None (incomparable).
388    ///
389    /// For `Real` values, uses total ordering: NaN < -Inf < values < Inf.
390    pub fn compare(&self, other: &Value) -> Option<Ordering> {
391        match (self, other) {
392            (Value::Null, Value::Null) => Some(Ordering::Equal),
393            (Value::Null, _) => Some(Ordering::Less),
394            (_, Value::Null) => Some(Ordering::Greater),
395            (Value::TinyInt(a), Value::TinyInt(b)) => Some(a.cmp(b)),
396            (Value::SmallInt(a), Value::SmallInt(b)) => Some(a.cmp(b)),
397            (Value::Integer(a), Value::Integer(b)) => Some(a.cmp(b)),
398            (Value::BigInt(a), Value::BigInt(b)) => Some(a.cmp(b)),
399            (Value::Real(a), Value::Real(b)) => Some(total_cmp_f64(*a, *b)),
400            (Value::Decimal(a_val, a_scale), Value::Decimal(b_val, b_scale)) => {
401                // Only compare if same scale
402                if a_scale == b_scale {
403                    Some(a_val.cmp(b_val))
404                } else {
405                    None
406                }
407            }
408            (Value::Text(a), Value::Text(b)) => Some(a.cmp(b)),
409            (Value::Bytes(a), Value::Bytes(b)) => Some(a.as_ref().cmp(b.as_ref())),
410            (Value::Boolean(a), Value::Boolean(b)) => Some(a.cmp(b)),
411            (Value::Date(a), Value::Date(b)) => Some(a.cmp(b)),
412            (Value::Time(a), Value::Time(b)) => Some(a.cmp(b)),
413            (Value::Timestamp(a), Value::Timestamp(b)) => Some(a.cmp(b)),
414            (Value::Uuid(a), Value::Uuid(b)) => Some(a.cmp(b)),
415            (Value::Json(a), Value::Json(b)) => {
416                // JSON comparison is complex, use string representation
417                Some(a.to_string().cmp(&b.to_string()))
418            }
419            _ => None, // Different types are incomparable
420        }
421    }
422
423    /// Checks if this value can be assigned to a column of the given type.
424    pub fn is_compatible_with(&self, data_type: DataType) -> bool {
425        match self {
426            Value::Null => true,           // NULL is compatible with any type
427            Value::Placeholder(_) => true, // Placeholder will be bound to actual value
428            Value::TinyInt(_) => data_type == DataType::TinyInt,
429            Value::SmallInt(_) => data_type == DataType::SmallInt,
430            Value::Integer(_) => data_type == DataType::Integer,
431            Value::BigInt(_) => data_type == DataType::BigInt,
432            Value::Real(_) => data_type == DataType::Real,
433            Value::Decimal(_, scale) => {
434                matches!(data_type, DataType::Decimal { scale: s, .. } if s == *scale)
435            }
436            Value::Text(_) => data_type == DataType::Text,
437            Value::Bytes(_) => data_type == DataType::Bytes,
438            Value::Boolean(_) => data_type == DataType::Boolean,
439            Value::Date(_) => data_type == DataType::Date,
440            Value::Time(_) => data_type == DataType::Time,
441            Value::Timestamp(_) => data_type == DataType::Timestamp,
442            Value::Uuid(_) => data_type == DataType::Uuid,
443            Value::Json(_) => data_type == DataType::Json,
444        }
445    }
446
447    /// Converts this value to JSON.
448    ///
449    /// # Panics
450    ///
451    /// Panics if the value is a `Placeholder` (should be bound before conversion).
452    pub fn to_json(&self) -> serde_json::Value {
453        match self {
454            Value::Null => serde_json::Value::Null,
455            Value::TinyInt(v) => serde_json::Value::Number((*v).into()),
456            Value::SmallInt(v) => serde_json::Value::Number((*v).into()),
457            Value::Integer(v) => serde_json::Value::Number((*v).into()),
458            Value::BigInt(v) => serde_json::Value::Number((*v).into()),
459            Value::Real(v) => {
460                serde_json::Number::from_f64(*v)
461                    .map_or(serde_json::Value::Null, serde_json::Value::Number) // NaN/Inf become null
462            }
463            Value::Decimal(val, scale) => {
464                // Convert to string representation
465                let divisor = 10_i128.pow(u32::from(*scale));
466                let int_part = val / divisor;
467                let frac_part = (val % divisor).abs();
468                let s = format!("{int_part}.{frac_part:0width$}", width = *scale as usize);
469                serde_json::Value::String(s)
470            }
471            Value::Text(s) => serde_json::Value::String(s.clone()),
472            Value::Bytes(b) => {
473                use base64::Engine;
474                let encoded = base64::engine::general_purpose::STANDARD.encode(b);
475                serde_json::Value::String(encoded)
476            }
477            Value::Boolean(b) => serde_json::Value::Bool(*b),
478            Value::Date(d) => serde_json::Value::Number((*d).into()),
479            Value::Time(t) => serde_json::Value::Number((*t).into()),
480            Value::Timestamp(ts) => serde_json::Value::Number(ts.as_nanos().into()),
481            Value::Uuid(u) => {
482                // Format as RFC 4122 hyphenated string
483                let s = format!(
484                    "{:02x}{:02x}{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}",
485                    u[0],
486                    u[1],
487                    u[2],
488                    u[3],
489                    u[4],
490                    u[5],
491                    u[6],
492                    u[7],
493                    u[8],
494                    u[9],
495                    u[10],
496                    u[11],
497                    u[12],
498                    u[13],
499                    u[14],
500                    u[15]
501                );
502                serde_json::Value::String(s)
503            }
504            Value::Json(j) => j.clone(),
505            Value::Placeholder(idx) => {
506                panic!("Cannot convert unbound placeholder ${idx} to JSON - bind parameters first")
507            }
508        }
509    }
510
511    /// Parses a value from JSON with an expected data type.
512    pub fn from_json(json: &serde_json::Value, data_type: DataType) -> Result<Self> {
513        match (json, data_type) {
514            (serde_json::Value::Null, _) => Ok(Value::Null),
515            (serde_json::Value::Number(n), DataType::TinyInt) => n
516                .as_i64()
517                .and_then(|v| i8::try_from(v).ok())
518                .map(Value::TinyInt)
519                .ok_or_else(|| QueryError::TypeMismatch {
520                    expected: "tinyint (-128 to 127)".to_string(),
521                    actual: format!("number {n}"),
522                }),
523            (serde_json::Value::Number(n), DataType::SmallInt) => n
524                .as_i64()
525                .and_then(|v| i16::try_from(v).ok())
526                .map(Value::SmallInt)
527                .ok_or_else(|| QueryError::TypeMismatch {
528                    expected: "smallint (-32768 to 32767)".to_string(),
529                    actual: format!("number {n}"),
530                }),
531            (serde_json::Value::Number(n), DataType::Integer) => n
532                .as_i64()
533                .and_then(|v| i32::try_from(v).ok())
534                .map(Value::Integer)
535                .ok_or_else(|| QueryError::TypeMismatch {
536                    expected: "integer (-2^31 to 2^31-1)".to_string(),
537                    actual: format!("number {n}"),
538                }),
539            (serde_json::Value::Number(n), DataType::BigInt) => n
540                .as_i64()
541                .map(Value::BigInt)
542                .ok_or_else(|| QueryError::TypeMismatch {
543                    expected: "bigint".to_string(),
544                    actual: format!("number {n}"),
545                }),
546            (serde_json::Value::Number(n), DataType::Real) => n
547                .as_f64()
548                .map(Value::Real)
549                .ok_or_else(|| QueryError::TypeMismatch {
550                    expected: "real (f64)".to_string(),
551                    actual: format!("number {n}"),
552                }),
553            (
554                serde_json::Value::String(s),
555                DataType::Decimal {
556                    precision: _,
557                    scale,
558                },
559            ) => {
560                // Parse decimal string like "123.45"
561                parse_decimal_string(s, scale).map(|val| Value::Decimal(val, scale))
562            }
563            (serde_json::Value::String(s), DataType::Text) => Ok(Value::Text(s.clone())),
564            (serde_json::Value::String(s), DataType::Bytes) => {
565                use base64::Engine;
566                let decoded = base64::engine::general_purpose::STANDARD
567                    .decode(s)
568                    .map_err(|e| QueryError::TypeMismatch {
569                        expected: "base64 bytes".to_string(),
570                        actual: e.to_string(),
571                    })?;
572                Ok(Value::Bytes(Bytes::from(decoded)))
573            }
574            (serde_json::Value::Bool(b), DataType::Boolean) => Ok(Value::Boolean(*b)),
575            (serde_json::Value::Number(n), DataType::Date) => n
576                .as_i64()
577                .and_then(|v| i32::try_from(v).ok())
578                .map(Value::Date)
579                .ok_or_else(|| QueryError::TypeMismatch {
580                    expected: "date (i32 days)".to_string(),
581                    actual: format!("number {n}"),
582                }),
583            (serde_json::Value::Number(n), DataType::Time) => n
584                .as_i64()
585                .map(Value::Time)
586                .ok_or_else(|| QueryError::TypeMismatch {
587                    expected: "time (i64 nanos)".to_string(),
588                    actual: format!("number {n}"),
589                }),
590            (serde_json::Value::Number(n), DataType::Timestamp) => n
591                .as_u64()
592                .map(|nanos| Value::Timestamp(Timestamp::from_nanos(nanos)))
593                .ok_or_else(|| QueryError::TypeMismatch {
594                    expected: "timestamp".to_string(),
595                    actual: format!("number {n}"),
596                }),
597            (serde_json::Value::String(s), DataType::Uuid) => parse_uuid_string(s).map(Value::Uuid),
598            (
599                json @ (serde_json::Value::Object(_)
600                | serde_json::Value::Array(_)
601                | serde_json::Value::String(_)
602                | serde_json::Value::Number(_)
603                | serde_json::Value::Bool(_)),
604                DataType::Json,
605            ) => Ok(Value::Json(json.clone())),
606            (json, dt) => Err(QueryError::TypeMismatch {
607                expected: format!("{dt:?}"),
608                actual: format!("{json:?}"),
609            }),
610        }
611    }
612}
613
614impl Display for Value {
615    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
616        match self {
617            Value::Null => write!(f, "NULL"),
618            Value::TinyInt(v) => write!(f, "{v}"),
619            Value::SmallInt(v) => write!(f, "{v}"),
620            Value::Integer(v) => write!(f, "{v}"),
621            Value::BigInt(v) => write!(f, "{v}"),
622            Value::Real(v) => write!(f, "{v}"),
623            Value::Decimal(val, scale) => {
624                let divisor = 10_i128.pow(u32::from(*scale));
625                let int_part = val / divisor;
626                let frac_part = (val % divisor).abs();
627                write!(f, "{int_part}.{frac_part:0width$}", width = *scale as usize)
628            }
629            Value::Text(s) => write!(f, "'{s}'"),
630            Value::Bytes(b) => write!(f, "<{} bytes>", b.len()),
631            Value::Boolean(b) => write!(f, "{b}"),
632            Value::Date(d) => write!(f, "DATE({d})"),
633            Value::Time(t) => write!(f, "TIME({t})"),
634            Value::Timestamp(ts) => write!(f, "{ts}"),
635            Value::Uuid(u) => {
636                write!(
637                    f,
638                    "{:02x}{:02x}{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}",
639                    u[0],
640                    u[1],
641                    u[2],
642                    u[3],
643                    u[4],
644                    u[5],
645                    u[6],
646                    u[7],
647                    u[8],
648                    u[9],
649                    u[10],
650                    u[11],
651                    u[12],
652                    u[13],
653                    u[14],
654                    u[15]
655                )
656            }
657            Value::Json(j) => write!(f, "{j}"),
658            Value::Placeholder(idx) => write!(f, "${idx}"),
659        }
660    }
661}
662
663impl From<i8> for Value {
664    fn from(v: i8) -> Self {
665        Value::TinyInt(v)
666    }
667}
668
669impl From<i16> for Value {
670    fn from(v: i16) -> Self {
671        Value::SmallInt(v)
672    }
673}
674
675impl From<i32> for Value {
676    fn from(v: i32) -> Self {
677        Value::Integer(v)
678    }
679}
680
681impl From<i64> for Value {
682    fn from(v: i64) -> Self {
683        Value::BigInt(v)
684    }
685}
686
687impl From<f64> for Value {
688    fn from(v: f64) -> Self {
689        Value::Real(v)
690    }
691}
692
693impl From<String> for Value {
694    fn from(s: String) -> Self {
695        Value::Text(s)
696    }
697}
698
699impl From<&str> for Value {
700    fn from(s: &str) -> Self {
701        Value::Text(s.to_string())
702    }
703}
704
705impl From<bool> for Value {
706    fn from(b: bool) -> Self {
707        Value::Boolean(b)
708    }
709}
710
711impl From<Timestamp> for Value {
712    fn from(ts: Timestamp) -> Self {
713        Value::Timestamp(ts)
714    }
715}
716
717impl From<Bytes> for Value {
718    fn from(b: Bytes) -> Self {
719        Value::Bytes(b)
720    }
721}
722
723impl From<[u8; 16]> for Value {
724    fn from(u: [u8; 16]) -> Self {
725        Value::Uuid(u)
726    }
727}
728
729impl From<serde_json::Value> for Value {
730    fn from(j: serde_json::Value) -> Self {
731        Value::Json(j)
732    }
733}
734
735/// Serde module for base64 encoding of bytes.
736mod bytes_base64 {
737    use base64::Engine;
738    use bytes::Bytes;
739    use serde::{Deserialize, Deserializer, Serializer};
740
741    pub fn serialize<S>(bytes: &Bytes, serializer: S) -> Result<S::Ok, S::Error>
742    where
743        S: Serializer,
744    {
745        let encoded = base64::engine::general_purpose::STANDARD.encode(bytes);
746        serializer.serialize_str(&encoded)
747    }
748
749    pub fn deserialize<'de, D>(deserializer: D) -> Result<Bytes, D::Error>
750    where
751        D: Deserializer<'de>,
752    {
753        let s = String::deserialize(deserializer)?;
754        let decoded = base64::engine::general_purpose::STANDARD
755            .decode(&s)
756            .map_err(serde::de::Error::custom)?;
757        Ok(Bytes::from(decoded))
758    }
759}