Skip to main content

uqa_sql/expr/
json_carrier.rs

1//
2// Unified Query Algebra
3//
4// Copyright (c) 2023-2026 Cognica, Inc.
5//
6
7//! Convert SQL values into the JSON carrier used by table and aggregate execution.
8
9use uqa_core::Value;
10
11pub fn core_value_to_json(value: &Value) -> serde_json::Value {
12    match value {
13        Value::Null => serde_json::Value::Null,
14        Value::Void => serde_json::Value::String(String::new()),
15        Value::Bool(b) => serde_json::Value::Bool(*b),
16        Value::Int(i) => serde_json::Value::Number((*i).into()),
17        Value::Float(f) => serde_json::Number::from_f64(*f).map_or_else(
18            || {
19                let label = if f.is_nan() {
20                    "NaN"
21                } else if f.is_sign_positive() {
22                    "Infinity"
23                } else {
24                    "-Infinity"
25                };
26                serde_json::Value::String(label.to_string())
27            },
28            serde_json::Value::Number,
29        ),
30        Value::Decimal(d) => d
31            .to_f64()
32            .and_then(serde_json::Number::from_f64)
33            .map_or_else(
34                || serde_json::Value::String(d.to_sql_string()),
35                serde_json::Value::Number,
36            ),
37        Value::Str(s) => serde_json::from_str::<serde_json::Value>(s)
38            .unwrap_or_else(|_| serde_json::Value::String(s.clone())),
39        Value::FixedChar(s) => serde_json::Value::String(s.trim_end_matches(' ').to_string()),
40        Value::Bytes(bytes) => serde_json::Value::String(String::from_utf8_lossy(bytes).into()),
41        Value::Temporal(t) => serde_json::Value::String(t.to_sql_string()),
42        Value::Json(text) | Value::JsonB(text) => {
43            serde_json::from_str(text).unwrap_or_else(|_| serde_json::Value::String(text.clone()))
44        }
45        Value::Array(array) => {
46            serde_json::Value::Array(array.elements().iter().map(core_value_to_json).collect())
47        }
48        Value::List(items) => {
49            serde_json::Value::Array(items.iter().map(core_value_to_json).collect())
50        }
51        Value::Row(values) => serde_json::Value::Object(
52            values
53                .iter()
54                .enumerate()
55                .map(|(index, value)| (format!("f{}", index + 1), core_value_to_json(value)))
56                .collect(),
57        ),
58        Value::Record(fields) => serde_json::Value::Object(
59            fields
60                .iter()
61                .map(|(name, value)| (name.clone(), core_value_to_json(value)))
62                .collect(),
63        ),
64        Value::Map(map) => serde_json::Value::Object(
65            map.iter()
66                .map(|(k, v)| (k.clone(), core_value_to_json(v)))
67                .collect(),
68        ),
69    }
70}
71
72pub fn value_to_text(value: &Value) -> String {
73    match value {
74        Value::Null => String::new(),
75        Value::Void => String::new(),
76        Value::Bool(b) => b.to_string(),
77        Value::Int(i) => i.to_string(),
78        Value::Float(f) => f.to_string(),
79        Value::Decimal(d) => d.to_sql_string(),
80        Value::Str(s) => s.clone(),
81        Value::FixedChar(s) => s.trim_end_matches(' ').to_string(),
82        Value::Bytes(bytes) => String::from_utf8_lossy(bytes).into_owned(),
83        Value::Temporal(t) => t.to_sql_string(),
84        Value::Json(text) | Value::JsonB(text) => text.clone(),
85        Value::Array(array) => crate::expr::array_value_to_string(array),
86        Value::List(_) | Value::Map(_) => serde_json::to_string(&core_value_to_json(value))
87            .unwrap_or_else(|_| format!("{value:?}")),
88        Value::Row(_) | Value::Record(_) => crate::expr::value_to_string(value),
89    }
90}