Skip to main content

geode_client/
types.rs

1//! Type system for Geode values.
2
3use chrono::{DateTime, NaiveDate, NaiveTime, Utc};
4use rust_decimal::Decimal;
5use std::collections::HashMap;
6
7use crate::error::{Error, Result};
8
9/// Kind of value
10#[derive(Debug, Clone, Copy, PartialEq, Eq)]
11pub enum ValueKind {
12    Null,
13    Int,
14    Bool,
15    String,
16    Decimal,
17    Array,
18    Object,
19    Bytea,
20    Date,
21    Time,
22    TimeTz,
23    Timestamp,
24    TimestampTz,
25    Interval,
26    Json,
27    Jsonb,
28    Xml,
29    Url,
30    Domain,
31    Uuid,
32    Enum,
33    BitString,
34    Range,
35}
36
37/// Range type value
38#[derive(Debug, Clone)]
39pub struct Range {
40    pub lower: Option<Box<Value>>,
41    pub upper: Option<Box<Value>>,
42    pub bounds: String,
43}
44
45/// Native representation of Geode values
46#[derive(Debug, Clone)]
47pub struct Value {
48    pub kind: ValueKind,
49    int_value: i64,
50    bool_value: bool,
51    string_value: String,
52    decimal_value: Option<Decimal>,
53    #[allow(dead_code)] // Reserved for future decimal scale support
54    decimal_scale: String,
55    array_value: Vec<Value>,
56    object_value: HashMap<String, Value>,
57    bytes_value: Vec<u8>,
58    date_value: Option<NaiveDate>,
59    #[allow(dead_code)] // Reserved for future time type support
60    time_value: Option<NaiveTime>,
61    timestamp_value: Option<DateTime<Utc>>,
62    range_value: Option<Range>,
63}
64
65impl Value {
66    /// Create a NULL value
67    pub fn null() -> Self {
68        Self {
69            kind: ValueKind::Null,
70            int_value: 0,
71            bool_value: false,
72            string_value: String::new(),
73            decimal_value: None,
74            decimal_scale: String::new(),
75            array_value: Vec::new(),
76            object_value: HashMap::new(),
77            bytes_value: Vec::new(),
78            date_value: None,
79            time_value: None,
80            timestamp_value: None,
81            range_value: None,
82        }
83    }
84
85    /// Create an INT value
86    pub fn int(value: i64) -> Self {
87        Self {
88            kind: ValueKind::Int,
89            int_value: value,
90            ..Self::null()
91        }
92    }
93
94    /// Create a BOOL value
95    pub fn bool(value: bool) -> Self {
96        Self {
97            kind: ValueKind::Bool,
98            bool_value: value,
99            ..Self::null()
100        }
101    }
102
103    /// Create a STRING value
104    pub fn string<S: Into<String>>(value: S) -> Self {
105        Self {
106            kind: ValueKind::String,
107            string_value: value.into(),
108            ..Self::null()
109        }
110    }
111
112    /// Create a DECIMAL value
113    pub fn decimal(value: Decimal) -> Self {
114        Self {
115            kind: ValueKind::Decimal,
116            decimal_value: Some(value),
117            ..Self::null()
118        }
119    }
120
121    /// Create an ARRAY value
122    pub fn array(values: Vec<Value>) -> Self {
123        Self {
124            kind: ValueKind::Array,
125            array_value: values,
126            ..Self::null()
127        }
128    }
129
130    /// Create an OBJECT value
131    pub fn object(values: HashMap<String, Value>) -> Self {
132        Self {
133            kind: ValueKind::Object,
134            object_value: values,
135            ..Self::null()
136        }
137    }
138
139    /// Check if value is NULL
140    pub fn is_null(&self) -> bool {
141        self.kind == ValueKind::Null
142    }
143
144    /// Get as integer
145    pub fn as_int(&self) -> Result<i64> {
146        if self.kind == ValueKind::Int {
147            Ok(self.int_value)
148        } else {
149            Err(Error::type_error(format!(
150                "Cannot convert {:?} to int",
151                self.kind
152            )))
153        }
154    }
155
156    /// Get as boolean
157    pub fn as_bool(&self) -> Result<bool> {
158        if self.kind == ValueKind::Bool {
159            Ok(self.bool_value)
160        } else {
161            Err(Error::type_error(format!(
162                "Cannot convert {:?} to bool",
163                self.kind
164            )))
165        }
166    }
167
168    /// Get as string
169    pub fn as_string(&self) -> Result<&str> {
170        match self.kind {
171            ValueKind::String
172            | ValueKind::Xml
173            | ValueKind::Json
174            | ValueKind::Jsonb
175            | ValueKind::Url
176            | ValueKind::Domain
177            | ValueKind::Uuid
178            | ValueKind::Enum
179            | ValueKind::BitString => Ok(&self.string_value),
180            _ => Err(Error::type_error(format!(
181                "Cannot convert {:?} to string",
182                self.kind
183            ))),
184        }
185    }
186
187    /// Get as decimal
188    pub fn as_decimal(&self) -> Result<Decimal> {
189        if self.kind == ValueKind::Decimal {
190            self.decimal_value
191                .ok_or_else(|| Error::type_error("Decimal value is None"))
192        } else {
193            Err(Error::type_error(format!(
194                "Cannot convert {:?} to decimal",
195                self.kind
196            )))
197        }
198    }
199
200    /// Get as array
201    pub fn as_array(&self) -> Result<&[Value]> {
202        if self.kind == ValueKind::Array {
203            Ok(&self.array_value)
204        } else {
205            Err(Error::type_error(format!(
206                "Cannot convert {:?} to array",
207                self.kind
208            )))
209        }
210    }
211
212    /// Get as object
213    pub fn as_object(&self) -> Result<&HashMap<String, Value>> {
214        if self.kind == ValueKind::Object {
215            Ok(&self.object_value)
216        } else {
217            Err(Error::type_error(format!(
218                "Cannot convert {:?} to object",
219                self.kind
220            )))
221        }
222    }
223
224    /// Get as bytes
225    pub fn as_bytes(&self) -> Result<&[u8]> {
226        if self.kind == ValueKind::Bytea {
227            Ok(&self.bytes_value)
228        } else {
229            Err(Error::type_error(format!(
230                "Cannot convert {:?} to bytes",
231                self.kind
232            )))
233        }
234    }
235
236    /// Get as date
237    pub fn as_date(&self) -> Result<NaiveDate> {
238        if self.kind == ValueKind::Date {
239            self.date_value
240                .ok_or_else(|| Error::type_error("Date value is None"))
241        } else {
242            Err(Error::type_error(format!(
243                "Cannot convert {:?} to date",
244                self.kind
245            )))
246        }
247    }
248
249    /// Get as timestamp
250    pub fn as_timestamp(&self) -> Result<DateTime<Utc>> {
251        if self.kind == ValueKind::Timestamp || self.kind == ValueKind::TimestampTz {
252            self.timestamp_value
253                .ok_or_else(|| Error::type_error("Timestamp value is None"))
254        } else {
255            Err(Error::type_error(format!(
256                "Cannot convert {:?} to timestamp",
257                self.kind
258            )))
259        }
260    }
261
262    /// Get as range
263    pub fn as_range(&self) -> Result<&Range> {
264        if self.kind == ValueKind::Range {
265            self.range_value
266                .as_ref()
267                .ok_or_else(|| Error::type_error("Range value is None"))
268        } else {
269            Err(Error::type_error(format!(
270                "Cannot convert {:?} to range",
271                self.kind
272            )))
273        }
274    }
275
276    /// Convert to serde_json::Value for serialization
277    pub fn to_json(&self) -> serde_json::Value {
278        match self.kind {
279            ValueKind::Null => serde_json::Value::Null,
280            ValueKind::Int => serde_json::Value::Number(self.int_value.into()),
281            ValueKind::Bool => serde_json::Value::Bool(self.bool_value),
282            ValueKind::String
283            | ValueKind::Xml
284            | ValueKind::Json
285            | ValueKind::Jsonb
286            | ValueKind::Url
287            | ValueKind::Domain
288            | ValueKind::Uuid
289            | ValueKind::Enum
290            | ValueKind::BitString => serde_json::Value::String(self.string_value.clone()),
291            ValueKind::Decimal => serde_json::Value::String(
292                self.decimal_value
293                    .map(|d| d.to_string())
294                    .unwrap_or_default(),
295            ),
296            ValueKind::Array => {
297                serde_json::Value::Array(self.array_value.iter().map(|v| v.to_json()).collect())
298            }
299            ValueKind::Object => {
300                let mut map = serde_json::Map::new();
301                for (k, v) in &self.object_value {
302                    map.insert(k.clone(), v.to_json());
303                }
304                serde_json::Value::Object(map)
305            }
306            ValueKind::Bytea => {
307                if self.bytes_value.is_empty() {
308                    serde_json::Value::String(self.string_value.clone())
309                } else {
310                    serde_json::Value::String(format!("\\x{}", hex::encode(&self.bytes_value)))
311                }
312            }
313            ValueKind::Date
314            | ValueKind::Time
315            | ValueKind::TimeTz
316            | ValueKind::Timestamp
317            | ValueKind::TimestampTz
318            | ValueKind::Interval => serde_json::Value::String(self.string_value.clone()),
319            ValueKind::Range => {
320                if let Some(range) = &self.range_value {
321                    let mut map = serde_json::Map::new();
322                    if let Some(lower) = &range.lower {
323                        map.insert("lower".to_string(), lower.to_json());
324                    }
325                    if let Some(upper) = &range.upper {
326                        map.insert("upper".to_string(), upper.to_json());
327                    }
328                    map.insert(
329                        "bounds".to_string(),
330                        serde_json::Value::String(range.bounds.clone()),
331                    );
332                    serde_json::Value::Object(map)
333                } else {
334                    serde_json::Value::Null
335                }
336            }
337        }
338    }
339
340    /// Convert to a string representation for protobuf parameters
341    pub fn to_proto_string(&self) -> String {
342        match self.kind {
343            ValueKind::Null => String::new(),
344            ValueKind::Int => self.int_value.to_string(),
345            ValueKind::Bool => self.bool_value.to_string(),
346            ValueKind::String
347            | ValueKind::Xml
348            | ValueKind::Json
349            | ValueKind::Jsonb
350            | ValueKind::Url
351            | ValueKind::Domain
352            | ValueKind::Uuid
353            | ValueKind::Enum
354            | ValueKind::BitString => self.string_value.clone(),
355            ValueKind::Decimal => self
356                .decimal_value
357                .map(|d| d.to_string())
358                .unwrap_or_default(),
359            ValueKind::Array => serde_json::to_string(&self.to_json()).unwrap_or_default(),
360            ValueKind::Object => serde_json::to_string(&self.to_json()).unwrap_or_default(),
361            ValueKind::Bytea => {
362                if self.bytes_value.is_empty() {
363                    self.string_value.clone()
364                } else {
365                    format!("\\x{}", hex::encode(&self.bytes_value))
366                }
367            }
368            ValueKind::Date
369            | ValueKind::Time
370            | ValueKind::TimeTz
371            | ValueKind::Timestamp
372            | ValueKind::TimestampTz
373            | ValueKind::Interval => self.string_value.clone(),
374            ValueKind::Range => serde_json::to_string(&self.to_json()).unwrap_or_default(),
375        }
376    }
377
378    /// Create a Value from a serde_json::Value
379    pub fn from_json(json: serde_json::Value) -> Self {
380        match json {
381            serde_json::Value::Null => Self::null(),
382            serde_json::Value::Bool(b) => Self::bool(b),
383            serde_json::Value::Number(n) => {
384                if let Some(i) = n.as_i64() {
385                    Self::int(i)
386                } else if let Some(f) = n.as_f64() {
387                    // Try to convert to decimal
388                    Self::string(f.to_string())
389                } else {
390                    Self::null()
391                }
392            }
393            serde_json::Value::String(s) => Self::string(s),
394            serde_json::Value::Array(arr) => {
395                let values: Vec<Value> = arr.into_iter().map(Self::from_json).collect();
396                Self::array(values)
397            }
398            serde_json::Value::Object(obj) => {
399                let mut map = HashMap::new();
400                for (k, v) in obj {
401                    map.insert(k, Self::from_json(v));
402                }
403                Self::object(map)
404            }
405        }
406    }
407}
408
409/// Decode a JSON value into a typed Value object
410pub fn decode_value(raw: &serde_json::Value, type_name: &str) -> Result<Value> {
411    if raw.is_null() {
412        return Ok(Value::null());
413    }
414
415    let type_upper = type_name.to_uppercase();
416
417    match type_upper.as_str() {
418        "INT" => {
419            if let Some(n) = raw.as_i64() {
420                Ok(Value::int(n))
421            } else if let Some(s) = raw.as_str() {
422                if let Ok(n) = s.parse::<i64>() {
423                    Ok(Value::int(n))
424                } else {
425                    Ok(Value::string(s))
426                }
427            } else {
428                Ok(Value::string(raw.to_string()))
429            }
430        }
431        "DECIMAL" => {
432            let s = raw
433                .as_str()
434                .map(|v| v.to_string())
435                .unwrap_or_else(|| raw.to_string());
436            if let Ok(dec) = s.parse::<Decimal>() {
437                Ok(Value::decimal(dec))
438            } else {
439                Ok(Value::string(s))
440            }
441        }
442        "BOOL" => {
443            if let Some(b) = raw.as_bool() {
444                Ok(Value::bool(b))
445            } else if let Some(s) = raw.as_str() {
446                let lower = s.to_ascii_lowercase();
447                if lower == "true" {
448                    Ok(Value::bool(true))
449                } else if lower == "false" {
450                    Ok(Value::bool(false))
451                } else {
452                    Ok(Value::string(s))
453                }
454            } else {
455                Ok(Value::string(raw.to_string()))
456            }
457        }
458        "STRING" => Ok(Value::string(raw.as_str().unwrap_or(""))),
459        "BYTEA" => {
460            let s = raw.as_str().unwrap_or("");
461            let bytes = if let Some(hex_str) = s.strip_prefix("\\x") {
462                hex::decode(hex_str).unwrap_or_default()
463            } else {
464                Vec::new()
465            };
466            Ok(Value {
467                kind: ValueKind::Bytea,
468                bytes_value: bytes,
469                string_value: s.to_string(),
470                ..Value::null()
471            })
472        }
473        "JSON" => Ok(Value {
474            kind: ValueKind::Json,
475            string_value: raw.to_string(),
476            ..Value::null()
477        }),
478        "JSONB" => Ok(Value {
479            kind: ValueKind::Jsonb,
480            string_value: raw.to_string(),
481            ..Value::null()
482        }),
483        "DATE" => {
484            let s = raw.as_str().unwrap_or("");
485            let date = NaiveDate::parse_from_str(s, "%Y-%m-%d").ok();
486            Ok(Value {
487                kind: ValueKind::Date,
488                string_value: s.to_string(),
489                date_value: date,
490                ..Value::null()
491            })
492        }
493        "TIMESTAMP" | "TIMESTAMPTZ" => {
494            let s = raw.as_str().unwrap_or("");
495            let timestamp = DateTime::parse_from_rfc3339(s)
496                .ok()
497                .map(|dt| dt.with_timezone(&Utc));
498            let kind = if type_upper == "TIMESTAMPTZ" {
499                ValueKind::TimestampTz
500            } else {
501                ValueKind::Timestamp
502            };
503            Ok(Value {
504                kind,
505                string_value: s.to_string(),
506                timestamp_value: timestamp,
507                ..Value::null()
508            })
509        }
510        _ if type_upper.contains("RANGE") => {
511            if let Some(obj) = raw.as_object() {
512                let range = Range {
513                    lower: obj
514                        .get("lower")
515                        .and_then(|v| decode_value(v, "").ok().map(Box::new)),
516                    upper: obj
517                        .get("upper")
518                        .and_then(|v| decode_value(v, "").ok().map(Box::new)),
519                    bounds: obj
520                        .get("bounds")
521                        .and_then(|v| v.as_str())
522                        .unwrap_or("")
523                        .to_string(),
524                };
525                Ok(Value {
526                    kind: ValueKind::Range,
527                    range_value: Some(range),
528                    ..Value::null()
529                })
530            } else {
531                Ok(Value::string(raw.to_string()))
532            }
533        }
534        _ => {
535            // Handle arrays and objects generically
536            if let Some(arr) = raw.as_array() {
537                let values: Result<Vec<_>> = arr.iter().map(|v| decode_value(v, "")).collect();
538                Ok(Value::array(values?))
539            } else if let Some(obj) = raw.as_object() {
540                let mut map = HashMap::new();
541                for (k, v) in obj {
542                    map.insert(k.clone(), decode_value(v, "")?);
543                }
544                Ok(Value::object(map))
545            } else if let Some(b) = raw.as_bool() {
546                Ok(Value::bool(b))
547            } else if let Some(n) = raw.as_i64() {
548                Ok(Value::int(n))
549            } else if let Some(f) = raw.as_f64() {
550                let s = f.to_string();
551                if let Ok(dec) = s.parse::<Decimal>() {
552                    Ok(Value::decimal(dec))
553                } else {
554                    Ok(Value::string(s))
555                }
556            } else if let Some(s) = raw.as_str() {
557                Ok(Value::string(s))
558            } else {
559                Ok(Value::string(raw.to_string()))
560            }
561        }
562    }
563}
564
565#[cfg(test)]
566mod tests {
567    use super::*;
568    use chrono::{Datelike, Timelike};
569    use rust_decimal_macros::dec;
570    use serde_json::json;
571
572    // ==================== ValueKind Tests ====================
573
574    #[test]
575    fn test_value_kind_equality() {
576        assert_eq!(ValueKind::Null, ValueKind::Null);
577        assert_eq!(ValueKind::Int, ValueKind::Int);
578        assert_ne!(ValueKind::Int, ValueKind::String);
579    }
580
581    #[test]
582    fn test_value_kind_copy() {
583        let kind = ValueKind::Int;
584        let kind_copy = kind;
585        assert_eq!(kind, kind_copy);
586    }
587
588    #[test]
589    fn test_value_kind_debug() {
590        let debug_str = format!("{:?}", ValueKind::Timestamp);
591        assert_eq!(debug_str, "Timestamp");
592    }
593
594    #[test]
595    fn test_value_kind_all_variants() {
596        // Ensure all variants exist and are distinct
597        let variants = [
598            ValueKind::Null,
599            ValueKind::Int,
600            ValueKind::Bool,
601            ValueKind::String,
602            ValueKind::Decimal,
603            ValueKind::Array,
604            ValueKind::Object,
605            ValueKind::Bytea,
606            ValueKind::Date,
607            ValueKind::Time,
608            ValueKind::TimeTz,
609            ValueKind::Timestamp,
610            ValueKind::TimestampTz,
611            ValueKind::Interval,
612            ValueKind::Json,
613            ValueKind::Jsonb,
614            ValueKind::Xml,
615            ValueKind::Url,
616            ValueKind::Domain,
617            ValueKind::Uuid,
618            ValueKind::Enum,
619            ValueKind::BitString,
620            ValueKind::Range,
621        ];
622        assert_eq!(variants.len(), 23);
623        // Check uniqueness
624        for i in 0..variants.len() {
625            for j in (i + 1)..variants.len() {
626                assert_ne!(variants[i], variants[j]);
627            }
628        }
629    }
630
631    // ==================== Value Construction Tests ====================
632
633    #[test]
634    fn test_value_null() {
635        let v = Value::null();
636        assert_eq!(v.kind, ValueKind::Null);
637        assert!(v.is_null());
638    }
639
640    #[test]
641    fn test_value_int() {
642        let v = Value::int(42);
643        assert_eq!(v.kind, ValueKind::Int);
644        assert!(!v.is_null());
645        assert_eq!(v.as_int().unwrap(), 42);
646    }
647
648    #[test]
649    fn test_value_int_negative() {
650        let v = Value::int(-100);
651        assert_eq!(v.as_int().unwrap(), -100);
652    }
653
654    #[test]
655    fn test_value_int_zero() {
656        let v = Value::int(0);
657        assert_eq!(v.as_int().unwrap(), 0);
658    }
659
660    #[test]
661    fn test_value_int_max() {
662        let v = Value::int(i64::MAX);
663        assert_eq!(v.as_int().unwrap(), i64::MAX);
664    }
665
666    #[test]
667    fn test_value_int_min() {
668        let v = Value::int(i64::MIN);
669        assert_eq!(v.as_int().unwrap(), i64::MIN);
670    }
671
672    #[test]
673    fn test_value_bool_true() {
674        let v = Value::bool(true);
675        assert_eq!(v.kind, ValueKind::Bool);
676        assert!(v.as_bool().unwrap());
677    }
678
679    #[test]
680    fn test_value_bool_false() {
681        let v = Value::bool(false);
682        assert!(!v.as_bool().unwrap());
683    }
684
685    #[test]
686    fn test_value_string() {
687        let v = Value::string("hello");
688        assert_eq!(v.kind, ValueKind::String);
689        assert_eq!(v.as_string().unwrap(), "hello");
690    }
691
692    #[test]
693    fn test_value_string_empty() {
694        let v = Value::string("");
695        assert_eq!(v.as_string().unwrap(), "");
696    }
697
698    #[test]
699    fn test_value_string_unicode() {
700        let v = Value::string("こんにちは世界🌍");
701        assert_eq!(v.as_string().unwrap(), "こんにちは世界🌍");
702    }
703
704    #[test]
705    fn test_value_string_owned() {
706        let owned = String::from("owned string");
707        let v = Value::string(owned);
708        assert_eq!(v.as_string().unwrap(), "owned string");
709    }
710
711    #[test]
712    fn test_value_decimal() {
713        let v = Value::decimal(dec!(123.456));
714        assert_eq!(v.kind, ValueKind::Decimal);
715        assert_eq!(v.as_decimal().unwrap(), dec!(123.456));
716    }
717
718    #[test]
719    fn test_value_decimal_precision() {
720        let v = Value::decimal(dec!(0.000000001));
721        assert_eq!(v.as_decimal().unwrap(), dec!(0.000000001));
722    }
723
724    #[test]
725    fn test_value_decimal_large() {
726        let v = Value::decimal(dec!(99999999999999.99));
727        assert_eq!(v.as_decimal().unwrap(), dec!(99999999999999.99));
728    }
729
730    #[test]
731    fn test_value_array_empty() {
732        let v = Value::array(vec![]);
733        assert_eq!(v.kind, ValueKind::Array);
734        assert!(v.as_array().unwrap().is_empty());
735    }
736
737    #[test]
738    fn test_value_array() {
739        let v = Value::array(vec![Value::int(1), Value::int(2), Value::int(3)]);
740        let arr = v.as_array().unwrap();
741        assert_eq!(arr.len(), 3);
742        assert_eq!(arr[0].as_int().unwrap(), 1);
743        assert_eq!(arr[1].as_int().unwrap(), 2);
744        assert_eq!(arr[2].as_int().unwrap(), 3);
745    }
746
747    #[test]
748    fn test_value_array_mixed() {
749        let v = Value::array(vec![
750            Value::int(42),
751            Value::string("hello"),
752            Value::bool(true),
753            Value::null(),
754        ]);
755        let arr = v.as_array().unwrap();
756        assert_eq!(arr[0].as_int().unwrap(), 42);
757        assert_eq!(arr[1].as_string().unwrap(), "hello");
758        assert!(arr[2].as_bool().unwrap());
759        assert!(arr[3].is_null());
760    }
761
762    #[test]
763    fn test_value_array_nested() {
764        let inner = Value::array(vec![Value::int(1), Value::int(2)]);
765        let outer = Value::array(vec![inner]);
766        let arr = outer.as_array().unwrap();
767        let inner_arr = arr[0].as_array().unwrap();
768        assert_eq!(inner_arr.len(), 2);
769    }
770
771    #[test]
772    fn test_value_object_empty() {
773        let v = Value::object(HashMap::new());
774        assert_eq!(v.kind, ValueKind::Object);
775        assert!(v.as_object().unwrap().is_empty());
776    }
777
778    #[test]
779    fn test_value_object() {
780        let mut map = HashMap::new();
781        map.insert("name".to_string(), Value::string("Alice"));
782        map.insert("age".to_string(), Value::int(30));
783        let v = Value::object(map);
784
785        let obj = v.as_object().unwrap();
786        assert_eq!(obj.get("name").unwrap().as_string().unwrap(), "Alice");
787        assert_eq!(obj.get("age").unwrap().as_int().unwrap(), 30);
788    }
789
790    #[test]
791    fn test_value_object_nested() {
792        let mut inner = HashMap::new();
793        inner.insert("city".to_string(), Value::string("NYC"));
794
795        let mut outer = HashMap::new();
796        outer.insert("address".to_string(), Value::object(inner));
797
798        let v = Value::object(outer);
799        let obj = v.as_object().unwrap();
800        let addr = obj.get("address").unwrap().as_object().unwrap();
801        assert_eq!(addr.get("city").unwrap().as_string().unwrap(), "NYC");
802    }
803
804    // ==================== Type Accessor Error Tests ====================
805
806    #[test]
807    fn test_as_int_wrong_type() {
808        let v = Value::string("not an int");
809        let result = v.as_int();
810        assert!(result.is_err());
811        assert!(result.unwrap_err().to_string().contains("String"));
812    }
813
814    #[test]
815    fn test_as_bool_wrong_type() {
816        let v = Value::int(42);
817        let result = v.as_bool();
818        assert!(result.is_err());
819    }
820
821    #[test]
822    fn test_as_string_wrong_type() {
823        let v = Value::int(42);
824        let result = v.as_string();
825        assert!(result.is_err());
826    }
827
828    #[test]
829    fn test_as_decimal_wrong_type() {
830        let v = Value::int(42);
831        let result = v.as_decimal();
832        assert!(result.is_err());
833    }
834
835    #[test]
836    fn test_as_array_wrong_type() {
837        let v = Value::int(42);
838        let result = v.as_array();
839        assert!(result.is_err());
840    }
841
842    #[test]
843    fn test_as_object_wrong_type() {
844        let v = Value::int(42);
845        let result = v.as_object();
846        assert!(result.is_err());
847    }
848
849    #[test]
850    fn test_as_bytes_wrong_type() {
851        let v = Value::int(42);
852        let result = v.as_bytes();
853        assert!(result.is_err());
854    }
855
856    #[test]
857    fn test_as_date_wrong_type() {
858        let v = Value::int(42);
859        let result = v.as_date();
860        assert!(result.is_err());
861    }
862
863    #[test]
864    fn test_as_timestamp_wrong_type() {
865        let v = Value::int(42);
866        let result = v.as_timestamp();
867        assert!(result.is_err());
868    }
869
870    #[test]
871    fn test_as_range_wrong_type() {
872        let v = Value::int(42);
873        let result = v.as_range();
874        assert!(result.is_err());
875    }
876
877    // ==================== String-like Type Accessors ====================
878
879    #[test]
880    fn test_as_string_from_xml() {
881        let v = Value {
882            kind: ValueKind::Xml,
883            string_value: "<root/>".to_string(),
884            ..Value::null()
885        };
886        assert_eq!(v.as_string().unwrap(), "<root/>");
887    }
888
889    #[test]
890    fn test_as_string_from_json() {
891        let v = Value {
892            kind: ValueKind::Json,
893            string_value: r#"{"key":"value"}"#.to_string(),
894            ..Value::null()
895        };
896        assert_eq!(v.as_string().unwrap(), r#"{"key":"value"}"#);
897    }
898
899    #[test]
900    fn test_as_string_from_url() {
901        let v = Value {
902            kind: ValueKind::Url,
903            string_value: "https://example.com".to_string(),
904            ..Value::null()
905        };
906        assert_eq!(v.as_string().unwrap(), "https://example.com");
907    }
908
909    #[test]
910    fn test_as_string_from_uuid() {
911        let v = Value {
912            kind: ValueKind::Uuid,
913            string_value: "550e8400-e29b-41d4-a716-446655440000".to_string(),
914            ..Value::null()
915        };
916        assert_eq!(
917            v.as_string().unwrap(),
918            "550e8400-e29b-41d4-a716-446655440000"
919        );
920    }
921
922    // ==================== to_json Tests ====================
923
924    #[test]
925    fn test_to_json_null() {
926        let v = Value::null();
927        assert_eq!(v.to_json(), json!(null));
928    }
929
930    #[test]
931    fn test_to_json_int() {
932        let v = Value::int(42);
933        assert_eq!(v.to_json(), json!(42));
934    }
935
936    #[test]
937    fn test_to_json_bool() {
938        let v = Value::bool(true);
939        assert_eq!(v.to_json(), json!(true));
940    }
941
942    #[test]
943    fn test_to_json_string() {
944        let v = Value::string("hello");
945        assert_eq!(v.to_json(), json!("hello"));
946    }
947
948    #[test]
949    fn test_to_json_decimal() {
950        let v = Value::decimal(dec!(123.45));
951        assert_eq!(v.to_json(), json!("123.45"));
952    }
953
954    #[test]
955    fn test_to_json_array() {
956        let v = Value::array(vec![Value::int(1), Value::int(2)]);
957        assert_eq!(v.to_json(), json!([1, 2]));
958    }
959
960    #[test]
961    fn test_to_json_object() {
962        let mut map = HashMap::new();
963        map.insert("key".to_string(), Value::string("value"));
964        let v = Value::object(map);
965        assert_eq!(v.to_json(), json!({"key": "value"}));
966    }
967
968    #[test]
969    fn test_to_json_bytea_empty() {
970        let v = Value {
971            kind: ValueKind::Bytea,
972            bytes_value: vec![],
973            string_value: "".to_string(),
974            ..Value::null()
975        };
976        assert_eq!(v.to_json(), json!(""));
977    }
978
979    #[test]
980    fn test_to_json_bytea_with_data() {
981        let v = Value {
982            kind: ValueKind::Bytea,
983            bytes_value: vec![0xDE, 0xAD, 0xBE, 0xEF],
984            ..Value::null()
985        };
986        assert_eq!(v.to_json(), json!("\\xdeadbeef"));
987    }
988
989    #[test]
990    fn test_to_json_range() {
991        let range = Range {
992            lower: Some(Box::new(Value::int(1))),
993            upper: Some(Box::new(Value::int(10))),
994            bounds: "[)".to_string(),
995        };
996        let v = Value {
997            kind: ValueKind::Range,
998            range_value: Some(range),
999            ..Value::null()
1000        };
1001        let j = v.to_json();
1002        assert_eq!(j["lower"], json!(1));
1003        assert_eq!(j["upper"], json!(10));
1004        assert_eq!(j["bounds"], json!("[)"));
1005    }
1006
1007    #[test]
1008    fn test_to_json_range_none() {
1009        let v = Value {
1010            kind: ValueKind::Range,
1011            range_value: None,
1012            ..Value::null()
1013        };
1014        assert_eq!(v.to_json(), json!(null));
1015    }
1016
1017    // ==================== from_json Tests ====================
1018
1019    #[test]
1020    fn test_from_json_null() {
1021        let v = Value::from_json(json!(null));
1022        assert!(v.is_null());
1023    }
1024
1025    #[test]
1026    fn test_from_json_bool() {
1027        let v = Value::from_json(json!(true));
1028        assert!(v.as_bool().unwrap());
1029    }
1030
1031    #[test]
1032    fn test_from_json_int() {
1033        let v = Value::from_json(json!(42));
1034        assert_eq!(v.as_int().unwrap(), 42);
1035    }
1036
1037    #[test]
1038    fn test_from_json_float() {
1039        let v = Value::from_json(json!(1.5));
1040        // Floats are converted to strings
1041        assert_eq!(v.kind, ValueKind::String);
1042    }
1043
1044    #[test]
1045    fn test_from_json_string() {
1046        let v = Value::from_json(json!("hello"));
1047        assert_eq!(v.as_string().unwrap(), "hello");
1048    }
1049
1050    #[test]
1051    fn test_from_json_array() {
1052        let v = Value::from_json(json!([1, 2, 3]));
1053        let arr = v.as_array().unwrap();
1054        assert_eq!(arr.len(), 3);
1055    }
1056
1057    #[test]
1058    fn test_from_json_object() {
1059        let v = Value::from_json(json!({"name": "Alice"}));
1060        let obj = v.as_object().unwrap();
1061        assert_eq!(obj.get("name").unwrap().as_string().unwrap(), "Alice");
1062    }
1063
1064    #[test]
1065    fn test_from_json_nested() {
1066        let v = Value::from_json(json!({
1067            "users": [
1068                {"name": "Alice", "age": 30},
1069                {"name": "Bob", "age": 25}
1070            ]
1071        }));
1072        let obj = v.as_object().unwrap();
1073        let users = obj.get("users").unwrap().as_array().unwrap();
1074        assert_eq!(users.len(), 2);
1075    }
1076
1077    // ==================== decode_value Tests ====================
1078
1079    #[test]
1080    fn test_decode_value_null() {
1081        let v = decode_value(&json!(null), "INT").unwrap();
1082        assert!(v.is_null());
1083    }
1084
1085    #[test]
1086    fn test_decode_value_int_from_number() {
1087        let v = decode_value(&json!(42), "INT").unwrap();
1088        assert_eq!(v.as_int().unwrap(), 42);
1089    }
1090
1091    #[test]
1092    fn test_decode_value_int_from_string() {
1093        let v = decode_value(&json!("123"), "INT").unwrap();
1094        assert_eq!(v.as_int().unwrap(), 123);
1095    }
1096
1097    #[test]
1098    fn test_decode_value_int_invalid_string() {
1099        let v = decode_value(&json!("not_a_number"), "INT").unwrap();
1100        // Falls back to string
1101        assert_eq!(v.kind, ValueKind::String);
1102    }
1103
1104    #[test]
1105    fn test_decode_value_decimal() {
1106        let v = decode_value(&json!("123.456"), "DECIMAL").unwrap();
1107        assert_eq!(v.as_decimal().unwrap(), dec!(123.456));
1108    }
1109
1110    #[test]
1111    fn test_decode_value_decimal_from_number() {
1112        let v = decode_value(&json!(123), "DECIMAL").unwrap();
1113        assert_eq!(v.as_decimal().unwrap(), dec!(123));
1114    }
1115
1116    #[test]
1117    fn test_decode_value_bool_true() {
1118        let v = decode_value(&json!(true), "BOOL").unwrap();
1119        assert!(v.as_bool().unwrap());
1120    }
1121
1122    #[test]
1123    fn test_decode_value_bool_false() {
1124        let v = decode_value(&json!(false), "BOOL").unwrap();
1125        assert!(!v.as_bool().unwrap());
1126    }
1127
1128    #[test]
1129    fn test_decode_value_bool_from_string_true() {
1130        let v = decode_value(&json!("true"), "BOOL").unwrap();
1131        assert!(v.as_bool().unwrap());
1132    }
1133
1134    #[test]
1135    fn test_decode_value_bool_from_string_false() {
1136        let v = decode_value(&json!("false"), "BOOL").unwrap();
1137        assert!(!v.as_bool().unwrap());
1138    }
1139
1140    #[test]
1141    fn test_decode_value_bool_from_string_case_insensitive() {
1142        let v = decode_value(&json!("TRUE"), "BOOL").unwrap();
1143        assert!(v.as_bool().unwrap());
1144    }
1145
1146    #[test]
1147    fn test_decode_value_string() {
1148        let v = decode_value(&json!("hello"), "STRING").unwrap();
1149        assert_eq!(v.as_string().unwrap(), "hello");
1150    }
1151
1152    #[test]
1153    fn test_decode_value_bytea() {
1154        let v = decode_value(&json!("\\xDEADBEEF"), "BYTEA").unwrap();
1155        assert_eq!(v.kind, ValueKind::Bytea);
1156        assert_eq!(v.as_bytes().unwrap(), &[0xDE, 0xAD, 0xBE, 0xEF]);
1157    }
1158
1159    #[test]
1160    fn test_decode_value_bytea_no_prefix() {
1161        let v = decode_value(&json!("plain"), "BYTEA").unwrap();
1162        assert_eq!(v.kind, ValueKind::Bytea);
1163        assert!(v.as_bytes().unwrap().is_empty());
1164    }
1165
1166    #[test]
1167    fn test_decode_value_json() {
1168        let v = decode_value(&json!({"key": "value"}), "JSON").unwrap();
1169        assert_eq!(v.kind, ValueKind::Json);
1170    }
1171
1172    #[test]
1173    fn test_decode_value_jsonb() {
1174        let v = decode_value(&json!({"key": "value"}), "JSONB").unwrap();
1175        assert_eq!(v.kind, ValueKind::Jsonb);
1176    }
1177
1178    #[test]
1179    fn test_decode_value_date() {
1180        let v = decode_value(&json!("2024-01-15"), "DATE").unwrap();
1181        assert_eq!(v.kind, ValueKind::Date);
1182        let date = v.as_date().unwrap();
1183        assert_eq!(date.to_string(), "2024-01-15");
1184    }
1185
1186    #[test]
1187    fn test_decode_value_date_invalid() {
1188        let v = decode_value(&json!("not-a-date"), "DATE").unwrap();
1189        assert_eq!(v.kind, ValueKind::Date);
1190        // Date parsing fails, but value is stored as string
1191        assert!(v.date_value.is_none());
1192    }
1193
1194    #[test]
1195    fn test_decode_value_timestamp() {
1196        let v = decode_value(&json!("2024-01-15T10:30:00Z"), "TIMESTAMP").unwrap();
1197        assert_eq!(v.kind, ValueKind::Timestamp);
1198        let ts = v.as_timestamp().unwrap();
1199        assert_eq!(ts.to_rfc3339(), "2024-01-15T10:30:00+00:00");
1200    }
1201
1202    #[test]
1203    fn test_decode_value_timestamptz() {
1204        let v = decode_value(&json!("2024-01-15T10:30:00+05:00"), "TIMESTAMPTZ").unwrap();
1205        assert_eq!(v.kind, ValueKind::TimestampTz);
1206    }
1207
1208    #[test]
1209    fn test_decode_value_range() {
1210        let v = decode_value(
1211            &json!({"lower": 1, "upper": 10, "bounds": "[)"}),
1212            "INT4RANGE",
1213        )
1214        .unwrap();
1215        assert_eq!(v.kind, ValueKind::Range);
1216        let range = v.as_range().unwrap();
1217        assert_eq!(range.bounds, "[)");
1218    }
1219
1220    #[test]
1221    fn test_decode_value_array_generic() {
1222        let v = decode_value(&json!([1, 2, 3]), "").unwrap();
1223        assert_eq!(v.kind, ValueKind::Array);
1224        assert_eq!(v.as_array().unwrap().len(), 3);
1225    }
1226
1227    #[test]
1228    fn test_decode_value_object_generic() {
1229        let v = decode_value(&json!({"key": "value"}), "").unwrap();
1230        assert_eq!(v.kind, ValueKind::Object);
1231    }
1232
1233    #[test]
1234    fn test_decode_value_generic_bool() {
1235        let v = decode_value(&json!(true), "UNKNOWN").unwrap();
1236        assert!(v.as_bool().unwrap());
1237    }
1238
1239    #[test]
1240    fn test_decode_value_generic_int() {
1241        let v = decode_value(&json!(42), "UNKNOWN").unwrap();
1242        assert_eq!(v.as_int().unwrap(), 42);
1243    }
1244
1245    #[test]
1246    fn test_decode_value_generic_float() {
1247        let v = decode_value(&json!(1.23), "UNKNOWN").unwrap();
1248        // Floats become decimals if parseable
1249        assert_eq!(v.kind, ValueKind::Decimal);
1250    }
1251
1252    #[test]
1253    fn test_decode_value_generic_string() {
1254        let v = decode_value(&json!("hello"), "UNKNOWN").unwrap();
1255        assert_eq!(v.as_string().unwrap(), "hello");
1256    }
1257
1258    #[test]
1259    fn test_decode_value_case_insensitive() {
1260        let v1 = decode_value(&json!(42), "int").unwrap();
1261        let v2 = decode_value(&json!(42), "INT").unwrap();
1262        let v3 = decode_value(&json!(42), "Int").unwrap();
1263        assert_eq!(v1.as_int().unwrap(), 42);
1264        assert_eq!(v2.as_int().unwrap(), 42);
1265        assert_eq!(v3.as_int().unwrap(), 42);
1266    }
1267
1268    // ==================== Range Tests ====================
1269
1270    #[test]
1271    fn test_range_construction() {
1272        let range = Range {
1273            lower: Some(Box::new(Value::int(0))),
1274            upper: Some(Box::new(Value::int(100))),
1275            bounds: "[)".to_string(),
1276        };
1277        assert_eq!(range.lower.as_ref().unwrap().as_int().unwrap(), 0);
1278        assert_eq!(range.upper.as_ref().unwrap().as_int().unwrap(), 100);
1279        assert_eq!(range.bounds, "[)");
1280    }
1281
1282    #[test]
1283    fn test_range_unbounded_lower() {
1284        let range = Range {
1285            lower: None,
1286            upper: Some(Box::new(Value::int(100))),
1287            bounds: "(]".to_string(),
1288        };
1289        assert!(range.lower.is_none());
1290        assert!(range.upper.is_some());
1291    }
1292
1293    #[test]
1294    fn test_range_unbounded_upper() {
1295        let range = Range {
1296            lower: Some(Box::new(Value::int(0))),
1297            upper: None,
1298            bounds: "[)".to_string(),
1299        };
1300        assert!(range.lower.is_some());
1301        assert!(range.upper.is_none());
1302    }
1303
1304    #[test]
1305    fn test_range_clone() {
1306        let range = Range {
1307            lower: Some(Box::new(Value::int(1))),
1308            upper: Some(Box::new(Value::int(10))),
1309            bounds: "[]".to_string(),
1310        };
1311        let cloned = range.clone();
1312        assert_eq!(cloned.bounds, "[]");
1313    }
1314
1315    // ==================== Value Clone Tests ====================
1316
1317    #[test]
1318    fn test_value_clone() {
1319        let v = Value::string("test");
1320        let cloned = v.clone();
1321        assert_eq!(cloned.as_string().unwrap(), "test");
1322    }
1323
1324    #[test]
1325    fn test_value_clone_array() {
1326        let v = Value::array(vec![Value::int(1), Value::int(2)]);
1327        let cloned = v.clone();
1328        assert_eq!(cloned.as_array().unwrap().len(), 2);
1329    }
1330
1331    #[test]
1332    fn test_value_clone_object() {
1333        let mut map = HashMap::new();
1334        map.insert("key".to_string(), Value::string("value"));
1335        let v = Value::object(map);
1336        let cloned = v.clone();
1337        assert_eq!(
1338            cloned
1339                .as_object()
1340                .unwrap()
1341                .get("key")
1342                .unwrap()
1343                .as_string()
1344                .unwrap(),
1345            "value"
1346        );
1347    }
1348
1349    // ==================== JSON Round-Trip Tests ====================
1350
1351    #[test]
1352    fn test_json_roundtrip_int() {
1353        let original = Value::int(42);
1354        let json = original.to_json();
1355        let restored = Value::from_json(json);
1356        assert_eq!(restored.as_int().unwrap(), 42);
1357    }
1358
1359    #[test]
1360    fn test_json_roundtrip_string() {
1361        let original = Value::string("hello world");
1362        let json = original.to_json();
1363        let restored = Value::from_json(json);
1364        assert_eq!(restored.as_string().unwrap(), "hello world");
1365    }
1366
1367    #[test]
1368    fn test_json_roundtrip_bool() {
1369        let original = Value::bool(true);
1370        let json = original.to_json();
1371        let restored = Value::from_json(json);
1372        assert!(restored.as_bool().unwrap());
1373    }
1374
1375    #[test]
1376    fn test_json_roundtrip_array() {
1377        let original = Value::array(vec![Value::int(1), Value::string("two")]);
1378        let json = original.to_json();
1379        let restored = Value::from_json(json);
1380        let arr = restored.as_array().unwrap();
1381        assert_eq!(arr[0].as_int().unwrap(), 1);
1382        assert_eq!(arr[1].as_string().unwrap(), "two");
1383    }
1384
1385    #[test]
1386    fn test_json_roundtrip_object() {
1387        let mut map = HashMap::new();
1388        map.insert("name".to_string(), Value::string("Alice"));
1389        map.insert("age".to_string(), Value::int(30));
1390        let original = Value::object(map);
1391        let json = original.to_json();
1392        let restored = Value::from_json(json);
1393        let obj = restored.as_object().unwrap();
1394        assert_eq!(obj.get("name").unwrap().as_string().unwrap(), "Alice");
1395        assert_eq!(obj.get("age").unwrap().as_int().unwrap(), 30);
1396    }
1397
1398    #[test]
1399    fn test_json_roundtrip_null() {
1400        let original = Value::null();
1401        let json = original.to_json();
1402        let restored = Value::from_json(json);
1403        assert!(restored.is_null());
1404    }
1405
1406    // ==================== Timestamp Accessor Tests ====================
1407
1408    #[test]
1409    fn test_as_timestamp_from_timestamp() {
1410        let v = decode_value(&json!("2024-01-15T10:30:00Z"), "TIMESTAMP").unwrap();
1411        let ts = v.as_timestamp().unwrap();
1412        assert_eq!(ts.year(), 2024);
1413        assert_eq!(ts.month(), 1);
1414        assert_eq!(ts.day(), 15);
1415    }
1416
1417    #[test]
1418    fn test_as_timestamp_from_timestamptz() {
1419        let v = decode_value(&json!("2024-01-15T10:30:00Z"), "TIMESTAMPTZ").unwrap();
1420        let ts = v.as_timestamp().unwrap();
1421        assert!(ts.hour() == 10);
1422    }
1423}