1use {
2 super::{Value, ValueError},
3 crate::result::{Error, Result},
4 chrono::{TimeZone, offset::Utc},
5 core::str::FromStr,
6 serde_json::{Map as JsonMap, Number as JsonNumber, Value as JsonValue},
7 std::collections::BTreeMap,
8 uuid::Uuid,
9};
10
11pub trait BTreeMapJsonExt {
12 fn parse_json_object(value: &str) -> Result<BTreeMap<String, Value>>;
13
14 fn try_from_json_map(json_map: JsonMap<String, JsonValue>) -> Result<BTreeMap<String, Value>>;
15}
16
17impl BTreeMapJsonExt for BTreeMap<String, Value> {
18 fn parse_json_object(value: &str) -> Result<BTreeMap<String, Value>> {
19 let value = serde_json::from_str(value)
20 .map_err(|_| ValueError::InvalidJsonString(value.to_owned()))?;
21
22 match value {
23 JsonValue::Object(json_map) => BTreeMap::try_from_json_map(json_map),
24 _ => Err(ValueError::JsonObjectTypeRequired.into()),
25 }
26 }
27
28 fn try_from_json_map(json_map: JsonMap<String, JsonValue>) -> Result<BTreeMap<String, Value>> {
29 json_map
30 .into_iter()
31 .map(|(key, value)| value.try_into().map(|value| (key, value)))
32 .collect::<Result<BTreeMap<String, Value>>>()
33 }
34}
35
36impl Value {
37 pub fn parse_json_map(value: &str) -> Result<Value> {
38 BTreeMap::parse_json_object(value).map(Value::Map)
39 }
40
41 pub fn parse_json_list(value: &str) -> Result<Value> {
42 let value = serde_json::from_str(value)
43 .map_err(|_| ValueError::InvalidJsonString(value.to_owned()))?;
44
45 if !matches!(value, JsonValue::Array(_)) {
46 return Err(ValueError::JsonArrayTypeRequired.into());
47 }
48
49 value.try_into()
50 }
51}
52
53impl TryFrom<Value> for JsonValue {
54 type Error = Error;
55
56 fn try_from(value: Value) -> Result<Self> {
57 match value {
58 Value::Bool(v) => Ok(JsonValue::Bool(v)),
59 Value::I8(v) => Ok(v.into()),
60 Value::I16(v) => Ok(v.into()),
61 Value::I32(v) => Ok(v.into()),
62 Value::I64(v) => Ok(v.into()),
63 Value::I128(v) => JsonNumber::from_str(&v.to_string())
64 .map(JsonValue::Number)
65 .map_err(|_| ValueError::UnreachableJsonNumberParseFailure(v.to_string()).into()),
66 Value::U8(v) => Ok(v.into()),
67 Value::U16(v) => Ok(v.into()),
68 Value::U32(v) => Ok(v.into()),
69 Value::U64(v) => Ok(v.into()),
70 Value::U128(v) => JsonNumber::from_str(&v.to_string())
71 .map(JsonValue::Number)
72 .map_err(|_| ValueError::UnreachableJsonNumberParseFailure(v.to_string()).into()),
73 Value::F32(v) => Ok(v.into()),
74 Value::F64(v) => Ok(v.into()),
75 Value::Decimal(v) => JsonNumber::from_str(&v.to_string())
76 .map(JsonValue::Number)
77 .map_err(|_| ValueError::UnreachableJsonNumberParseFailure(v.to_string()).into()),
78 Value::Str(v) => Ok(v.into()),
79 Value::Bytea(v) => Ok(hex::encode(v).into()),
80 Value::Inet(v) => Ok(v.to_string().into()),
81 Value::Date(v) => Ok(v.to_string().into()),
82 Value::Timestamp(v) => Ok(Utc.from_utc_datetime(&v).to_string().into()),
83 Value::Time(v) => Ok(v.to_string().into()),
84 Value::Interval(v) => Ok(v.to_sql_str().into()),
85 Value::Uuid(v) => Ok(Uuid::from_u128(v).hyphenated().to_string().into()),
86 Value::Map(v) => v
87 .into_iter()
88 .map(|(key, value)| value.try_into().map(|value| (key, value)))
89 .collect::<Result<Vec<(String, JsonValue)>>>()
90 .map(|v| JsonMap::from_iter(v).into()),
91 Value::List(v) => v
92 .into_iter()
93 .map(TryInto::try_into)
94 .collect::<Result<Vec<JsonValue>>>()
95 .map(Into::into),
96 Value::Point(v) => Ok(v.to_string().into()),
97 Value::Null => Ok(JsonValue::Null),
98 }
99 }
100}
101
102impl TryFrom<JsonValue> for Value {
103 type Error = Error;
104
105 fn try_from(json_value: JsonValue) -> Result<Self> {
106 match json_value {
107 JsonValue::Null => Ok(Value::Null),
108 JsonValue::Bool(v) => Ok(Value::Bool(v)),
109 JsonValue::Number(v) => {
110 if let Some(value) = v.as_i64().map(Value::I64) {
111 return Ok(value);
112 }
113
114 v.as_f64().map(Value::F64).ok_or_else(|| {
115 ValueError::UnreachableJsonNumberParseFailure(v.to_string()).into()
116 })
117 }
118 JsonValue::String(v) => Ok(Value::Str(v)),
119 JsonValue::Array(json_array) => json_array
120 .into_iter()
121 .map(Value::try_from)
122 .collect::<Result<Vec<Value>>>()
123 .map(Value::List),
124 JsonValue::Object(json_map) => json_map
125 .into_iter()
126 .map(|(key, value)| value.try_into().map(|value| (key, value)))
127 .collect::<Result<BTreeMap<String, Value>>>()
128 .map(Value::Map),
129 }
130 }
131}
132
133#[cfg(test)]
134mod tests {
135 use {
136 crate::data::{Interval, Point, Value, ValueError, value::uuid::parse_uuid},
137 chrono::{NaiveDate, NaiveTime},
138 rust_decimal::Decimal,
139 serde_json::{Number as JsonNumber, Value as JsonValue, json},
140 std::{net::IpAddr, str::FromStr},
141 };
142
143 #[test]
144 fn parse_json() {
145 assert_eq!(
146 Value::parse_json_map("[1, 2, 3]"),
147 Err(ValueError::JsonObjectTypeRequired.into())
148 );
149 assert_eq!(
150 Value::parse_json_list(r#"{ "a": 30 }"#),
151 Err(ValueError::JsonArrayTypeRequired.into())
152 );
153 }
154
155 #[test]
156 fn value_to_json() {
157 assert_eq!(Value::Bool(true).try_into(), Ok(JsonValue::Bool(true)));
158 assert_eq!(Value::I8(16).try_into(), Ok(JsonValue::Number(16.into())));
159 assert_eq!(
160 Value::I16(100).try_into(),
161 Ok(JsonValue::Number(100.into()))
162 );
163 assert_eq!(
164 Value::I32(100).try_into(),
165 Ok(JsonValue::Number(100.into()))
166 );
167 assert_eq!(
168 Value::I64(100).try_into(),
169 Ok(JsonValue::Number(100.into()))
170 );
171 assert_eq!(
172 Value::I128(100).try_into(),
173 Ok(JsonValue::Number(100.into()))
174 );
175 assert_eq!(Value::U8(100).try_into(), Ok(JsonValue::Number(100.into())));
176 assert_eq!(
177 Value::U16(100).try_into(),
178 Ok(JsonValue::Number(100.into()))
179 );
180 assert_eq!(
181 Value::U32(100).try_into(),
182 Ok(JsonValue::Number(100.into()))
183 );
184 assert_eq!(
185 Value::U64(100).try_into(),
186 Ok(JsonValue::Number(100.into()))
187 );
188 assert_eq!(
189 Value::U128(100).try_into(),
190 Ok(JsonValue::Number(100.into()))
191 );
192 assert!(JsonValue::try_from(Value::I128(i128::MAX)).is_ok());
193
194 assert_eq!(
195 Value::F32(1.23_f32).try_into(),
196 Ok(JsonValue::Number(
197 JsonNumber::from_f64(f64::from(1.23_f32)).unwrap()
198 ))
199 );
200 assert_eq!(
201 Value::F64(1.23).try_into(),
202 Ok(JsonValue::Number(JsonNumber::from_f64(1.23).unwrap()))
203 );
204 assert_eq!(
205 Value::Decimal(Decimal::ONE).try_into(),
206 Ok(JsonValue::Number(1.into()))
207 );
208 assert_eq!(
209 Value::Str("abc".to_owned()).try_into(),
210 Ok(JsonValue::String("abc".to_owned()))
211 );
212 assert_eq!(
213 Value::Bytea(hex::decode("a1b2").unwrap()).try_into(),
214 Ok(JsonValue::String("a1b2".to_owned()))
215 );
216 assert_eq!(
217 Value::Inet(IpAddr::from_str("::1").unwrap()).try_into(),
218 Ok(JsonValue::String("::1".to_owned()))
219 );
220 assert_eq!(
221 Value::Date(NaiveDate::from_ymd_opt(2020, 1, 3).unwrap()).try_into(),
222 Ok(JsonValue::String("2020-01-03".to_owned()))
223 );
224 assert_eq!(
225 Value::Timestamp(
226 NaiveDate::from_ymd_opt(2022, 6, 11)
227 .unwrap()
228 .and_hms_opt(13, 30, 1)
229 .unwrap()
230 )
231 .try_into(),
232 Ok(JsonValue::String("2022-06-11 13:30:01 UTC".to_owned()))
233 );
234 assert_eq!(
235 Value::Time(NaiveTime::from_hms_opt(20, 11, 59).unwrap()).try_into(),
236 Ok(JsonValue::String("20:11:59".to_owned()))
237 );
238 assert_eq!(
239 Value::Interval(Interval::Month(17)).try_into(),
240 Ok(JsonValue::String("'1-5' YEAR TO MONTH".to_owned()))
241 );
242
243 let uuid = "43185717-59af-4e2b-9cd3-3264bf3691a4";
244 assert_eq!(
245 Value::Uuid(parse_uuid(uuid).unwrap()).try_into(),
246 Ok(JsonValue::String(uuid.to_owned()))
247 );
248
249 assert_eq!(
250 Value::parse_json_map(r#"{ "a": 10, "b": { "c": true, "d": "hello" }}"#)
251 .unwrap()
252 .try_into(),
253 Ok(json!({
254 "a": 10,
255 "b": {
256 "c": true,
257 "d": "hello",
258 }
259 }))
260 );
261 assert_eq!(
262 Value::parse_json_list(r#"[1, 2, { "a": 3 }]"#)
263 .unwrap()
264 .try_into(),
265 Ok(json!([1, 2, { "a": 3 }]))
266 );
267 assert_eq!(
268 Value::Point(Point::new(0.34, 0.56)).try_into(),
269 Ok(JsonValue::String("POINT(0.34 0.56)".to_owned()))
270 );
271 assert_eq!(Value::Null.try_into(), Ok(JsonValue::Null));
272 }
273
274 #[test]
275 fn json_to_value() {
276 use utils::Tribool::True;
277
278 assert!(Value::try_from(JsonValue::Null).unwrap().is_null());
279 assert_eq!(
280 True,
281 Value::try_from(JsonValue::Bool(false))
282 .unwrap()
283 .evaluate_eq(&Value::Bool(false))
284 );
285 assert_eq!(
286 True,
287 Value::try_from(JsonValue::Number(54321.into()))
288 .unwrap()
289 .evaluate_eq(&Value::I32(54321))
290 );
291 assert_eq!(
292 True,
293 Value::try_from(JsonValue::Number(54321.into()))
294 .unwrap()
295 .evaluate_eq(&Value::I64(54321))
296 );
297 assert_eq!(
298 True,
299 Value::try_from(JsonValue::Number(54321.into()))
300 .unwrap()
301 .evaluate_eq(&Value::I128(54321))
302 );
303 assert_eq!(
304 True,
305 Value::try_from(JsonValue::Number(JsonNumber::from_f64(3.21).unwrap()))
306 .unwrap()
307 .evaluate_eq(&Value::F64(3.21))
308 );
309 assert_eq!(
310 True,
311 Value::try_from(JsonValue::String("world".to_owned()))
312 .unwrap()
313 .evaluate_eq(&Value::Str("world".to_owned()))
314 );
315 assert_eq!(
316 True,
317 Value::try_from(JsonValue::Array(vec![JsonValue::Bool(true)]))
318 .unwrap()
319 .evaluate_eq(&Value::List(vec![Value::Bool(true)]))
320 );
321 assert_eq!(
322 True,
323 Value::try_from(json!({ "a": true }))
324 .unwrap()
325 .evaluate_eq(&Value::Map(
326 [("a".to_owned(), Value::Bool(true))].into_iter().collect()
327 ))
328 );
329 }
330}