vibesql/types/
value.rs

1//! SQL value types.
2
3/// A SQL value.
4#[derive(Debug, Clone, PartialEq, Default)]
5pub enum Value {
6    #[default]
7    Null,
8    Boolean(bool),
9    Int64(i64),
10    Float64(f64),
11    String(String),
12    Bytes(Vec<u8>),
13    Date(i32),      // Days since Unix epoch
14    Time(i64),      // Microseconds since midnight
15    Datetime(i64),  // Microseconds since Unix epoch
16    Timestamp(i64), // Microseconds since Unix epoch (with timezone)
17    Interval(Interval),
18    Array(Vec<Value>),
19    Struct(Vec<(String, Value)>),
20    Json(String),
21}
22
23/// Interval value.
24#[derive(Debug, Clone, PartialEq)]
25pub struct Interval {
26    pub months: i32,
27    pub days: i32,
28    pub micros: i64,
29}
30
31impl Value {
32    /// Check if this value is NULL.
33    pub fn is_null(&self) -> bool {
34        matches!(self, Value::Null)
35    }
36
37    /// Get the type of this value.
38    pub fn type_name(&self) -> &'static str {
39        match self {
40            Value::Null => "NULL",
41            Value::Boolean(_) => "BOOLEAN",
42            Value::Int64(_) => "BIGINT",
43            Value::Float64(_) => "DOUBLE PRECISION",
44            Value::String(_) => "VARCHAR",
45            Value::Bytes(_) => "VARBINARY",
46            Value::Date(_) => "DATE",
47            Value::Time(_) => "TIME",
48            Value::Datetime(_) => "DATETIME",
49            Value::Timestamp(_) => "TIMESTAMP",
50            Value::Interval(_) => "INTERVAL",
51            Value::Array(_) => "ARRAY",
52            Value::Struct(_) => "STRUCT",
53            Value::Json(_) => "JSON",
54        }
55    }
56}
57
58impl From<bool> for Value {
59    fn from(v: bool) -> Self {
60        Value::Boolean(v)
61    }
62}
63
64impl From<i64> for Value {
65    fn from(v: i64) -> Self {
66        Value::Int64(v)
67    }
68}
69
70impl From<f64> for Value {
71    fn from(v: f64) -> Self {
72        Value::Float64(v)
73    }
74}
75
76impl From<String> for Value {
77    fn from(v: String) -> Self {
78        Value::String(v)
79    }
80}
81
82impl From<&str> for Value {
83    fn from(v: &str) -> Self {
84        Value::String(v.to_string())
85    }
86}
87
88impl From<Vec<u8>> for Value {
89    fn from(v: Vec<u8>) -> Self {
90        Value::Bytes(v)
91    }
92}
93
94#[cfg(test)]
95mod tests {
96    use super::*;
97
98    #[test]
99    fn test_value_from_bool() {
100        assert_eq!(Value::from(true), Value::Boolean(true));
101        assert_eq!(Value::from(false), Value::Boolean(false));
102    }
103
104    #[test]
105    fn test_value_from_i64() {
106        assert_eq!(Value::from(42i64), Value::Int64(42));
107        assert_eq!(Value::from(-1i64), Value::Int64(-1));
108        assert_eq!(Value::from(0i64), Value::Int64(0));
109    }
110
111    #[test]
112    fn test_value_from_f64() {
113        assert_eq!(Value::from(3.14f64), Value::Float64(3.14));
114        assert_eq!(Value::from(-0.5f64), Value::Float64(-0.5));
115    }
116
117    #[test]
118    fn test_value_from_string() {
119        assert_eq!(
120            Value::from("hello".to_string()),
121            Value::String("hello".to_string())
122        );
123        assert_eq!(Value::from(String::new()), Value::String(String::new()));
124    }
125
126    #[test]
127    fn test_value_from_str() {
128        assert_eq!(Value::from("hello"), Value::String("hello".to_string()));
129        assert_eq!(Value::from(""), Value::String(String::new()));
130    }
131
132    #[test]
133    fn test_value_from_bytes() {
134        assert_eq!(Value::from(vec![1u8, 2, 3]), Value::Bytes(vec![1, 2, 3]));
135        assert_eq!(Value::from(Vec::<u8>::new()), Value::Bytes(vec![]));
136    }
137
138    #[test]
139    fn test_value_is_null() {
140        assert!(Value::Null.is_null());
141        assert!(!Value::Boolean(true).is_null());
142        assert!(!Value::Int64(0).is_null());
143        assert!(!Value::String("".to_string()).is_null());
144    }
145
146    #[test]
147    fn test_value_type_name() {
148        assert_eq!(Value::Null.type_name(), "NULL");
149        assert_eq!(Value::Boolean(true).type_name(), "BOOLEAN");
150        assert_eq!(Value::Int64(42).type_name(), "BIGINT");
151        assert_eq!(Value::Float64(3.14).type_name(), "DOUBLE PRECISION");
152        assert_eq!(Value::String("test".to_string()).type_name(), "VARCHAR");
153        assert_eq!(Value::Bytes(vec![]).type_name(), "VARBINARY");
154        assert_eq!(Value::Date(0).type_name(), "DATE");
155        assert_eq!(Value::Time(0).type_name(), "TIME");
156        assert_eq!(Value::Datetime(0).type_name(), "DATETIME");
157        assert_eq!(Value::Timestamp(0).type_name(), "TIMESTAMP");
158        assert_eq!(
159            Value::Interval(Interval {
160                months: 0,
161                days: 0,
162                micros: 0
163            })
164            .type_name(),
165            "INTERVAL"
166        );
167        assert_eq!(Value::Array(vec![]).type_name(), "ARRAY");
168        assert_eq!(Value::Struct(vec![]).type_name(), "STRUCT");
169        assert_eq!(Value::Json("{}".to_string()).type_name(), "JSON");
170    }
171
172    #[test]
173    fn test_value_default() {
174        assert_eq!(Value::default(), Value::Null);
175    }
176}