1use std::collections::BTreeMap;
4
5use crate::error::Result;
6use crate::value::{Geography, Geometry, Value};
7
8pub trait FromValue: Sized {
13 fn from_value(value: &Value) -> Result<Self>;
18
19 fn from_value_owned(value: Value) -> Result<Self> {
25 Self::from_value(&value)
26 }
27}
28
29impl FromValue for i64 {
30 fn from_value(value: &Value) -> Result<Self> {
31 match value {
32 Value::I64(v) => Ok(*v),
33 Value::Null => Err(crate::Error::TypeError("NULL value for i64".to_string())),
34 _ => Err(crate::Error::TypeError(format!(
35 "expected i64, got {:?}",
36 value
37 ))),
38 }
39 }
40}
41
42impl FromValue for i32 {
43 fn from_value(value: &Value) -> Result<Self> {
44 match value {
45 Value::I32(v) => Ok(*v),
46 Value::I64(v) => (*v).try_into().map_err(|_| {
47 crate::Error::TypeError(format!("i64 value {} doesn't fit in i32", v))
48 }),
49 Value::Null => Err(crate::Error::TypeError("NULL value for i32".to_string())),
50 _ => Err(crate::Error::TypeError(format!(
51 "expected i32, got {:?}",
52 value
53 ))),
54 }
55 }
56}
57
58impl FromValue for String {
59 fn from_value(value: &Value) -> Result<Self> {
60 match value {
61 Value::String(v) => Ok(v.clone()),
62 Value::Null => Err(crate::Error::TypeError("NULL value for String".to_string())),
63 _ => Err(crate::Error::TypeError(format!(
64 "expected String, got {:?}",
65 value
66 ))),
67 }
68 }
69
70 fn from_value_owned(value: Value) -> Result<Self> {
71 match value {
72 Value::String(v) => Ok(v),
73 Value::Null => Err(crate::Error::TypeError("NULL value for String".to_string())),
74 other => Err(crate::Error::TypeError(format!(
75 "expected String, got {:?}",
76 other
77 ))),
78 }
79 }
80}
81
82impl FromValue for bool {
83 fn from_value(value: &Value) -> Result<Self> {
84 match value {
85 Value::Bool(v) => Ok(*v),
86 Value::I32(v) => match *v {
87 0 => Ok(false),
88 1 => Ok(true),
89 other => Err(crate::Error::TypeError(format!(
90 "expected bool-compatible i32 (0 or 1), got {}",
91 other
92 ))),
93 },
94 Value::I64(v) => match *v {
95 0 => Ok(false),
96 1 => Ok(true),
97 other => Err(crate::Error::TypeError(format!(
98 "expected bool-compatible i64 (0 or 1), got {}",
99 other
100 ))),
101 },
102 Value::Null => Err(crate::Error::TypeError("NULL value for bool".to_string())),
103 _ => Err(crate::Error::TypeError(format!(
104 "expected bool, got {:?}",
105 value
106 ))),
107 }
108 }
109}
110
111impl FromValue for f64 {
112 fn from_value(value: &Value) -> Result<Self> {
113 match value {
114 Value::F64(v) => Ok(*v),
115 Value::Null => Err(crate::Error::TypeError("NULL value for f64".to_string())),
116 _ => Err(crate::Error::TypeError(format!(
117 "expected f64, got {:?}",
118 value
119 ))),
120 }
121 }
122}
123
124impl FromValue for f32 {
125 fn from_value(value: &Value) -> Result<Self> {
126 let value = match value {
127 Value::F64(v) if v.is_finite() => *v,
128 Value::I32(v) => *v as f64,
129 Value::I64(v) => *v as f64,
130 Value::Null => return Err(crate::Error::TypeError("NULL value for f32".to_string())),
131 _ => {
132 return Err(crate::Error::TypeError(format!(
133 "expected f32-compatible number, got {:?}",
134 value
135 )));
136 }
137 };
138
139 if value < f32::MIN as f64 || value > f32::MAX as f64 {
140 return Err(crate::Error::TypeError(format!(
141 "number {} does not fit in f32",
142 value
143 )));
144 }
145
146 Ok(value as f32)
147 }
148}
149
150impl FromValue for rust_decimal::Decimal {
151 fn from_value(value: &Value) -> Result<Self> {
152 match value {
153 Value::Decimal(v) => Ok(*v),
154 Value::String(v) => v.parse::<rust_decimal::Decimal>().map_err(|e| {
155 crate::Error::TypeError(format!(
156 "failed to parse Decimal from string {:?}: {}",
157 v, e
158 ))
159 }),
160 Value::Null => Err(crate::Error::TypeError(
161 "NULL value for Decimal".to_string(),
162 )),
163 _ => Err(crate::Error::TypeError(format!(
164 "expected Decimal, got {:?}",
165 value
166 ))),
167 }
168 }
169}
170
171impl FromValue for chrono::NaiveDateTime {
172 fn from_value(value: &Value) -> Result<Self> {
173 match value {
174 Value::DateTime(v) => Ok(*v),
175 Value::String(v) => chrono::DateTime::parse_from_rfc3339(v)
176 .map(|dt| dt.naive_utc())
177 .or_else(|_| chrono::NaiveDateTime::parse_from_str(v, "%Y-%m-%dT%H:%M:%S%.f"))
178 .or_else(|_| chrono::NaiveDateTime::parse_from_str(v, "%Y-%m-%d %H:%M:%S%.f"))
179 .map_err(|_| {
180 crate::Error::TypeError(format!("failed to parse DateTime from string {:?}", v))
181 }),
182 Value::Null => Err(crate::Error::TypeError(
183 "NULL value for DateTime".to_string(),
184 )),
185 _ => Err(crate::Error::TypeError(format!(
186 "expected DateTime, got {:?}",
187 value
188 ))),
189 }
190 }
191}
192
193impl FromValue for uuid::Uuid {
194 fn from_value(value: &Value) -> Result<Self> {
195 match value {
196 Value::Uuid(v) => Ok(*v),
197 Value::String(v) => uuid::Uuid::parse_str(v).map_err(|e| {
198 crate::Error::TypeError(format!("failed to parse Uuid from string {:?}: {}", v, e))
199 }),
200 Value::Null => Err(crate::Error::TypeError("NULL value for Uuid".to_string())),
201 _ => Err(crate::Error::TypeError(format!(
202 "expected Uuid, got {:?}",
203 value
204 ))),
205 }
206 }
207}
208
209impl FromValue for serde_json::Value {
210 fn from_value(value: &Value) -> Result<Self> {
211 match value {
212 Value::Null => Err(crate::Error::TypeError("NULL value for Json".to_string())),
213 other => Ok(other.to_json_plain()),
214 }
215 }
216
217 fn from_value_owned(value: Value) -> Result<Self> {
218 match value {
219 Value::Null => Err(crate::Error::TypeError("NULL value for Json".to_string())),
220 other => Ok(other.to_json_plain()),
221 }
222 }
223}
224
225impl FromValue for BTreeMap<String, Option<String>> {
226 fn from_value(value: &Value) -> Result<Self> {
227 match value {
228 Value::Hstore(map) => Ok(map.clone()),
229 Value::Json(serde_json::Value::Object(map)) => decode_hstore_json_object(map),
230 Value::Null => Err(crate::Error::TypeError("NULL value for Hstore".to_string())),
231 other => Err(crate::Error::TypeError(format!(
232 "expected Hstore or Json object, got {:?}",
233 other
234 ))),
235 }
236 }
237
238 fn from_value_owned(value: Value) -> Result<Self> {
239 match value {
240 Value::Hstore(map) => Ok(map),
241 Value::Json(serde_json::Value::Object(map)) => decode_hstore_json_object(&map),
242 Value::Null => Err(crate::Error::TypeError("NULL value for Hstore".to_string())),
243 other => Err(crate::Error::TypeError(format!(
244 "expected Hstore or Json object, got {:?}",
245 other
246 ))),
247 }
248 }
249}
250
251impl FromValue for Geometry {
252 fn from_value(value: &Value) -> Result<Self> {
253 match value {
254 Value::Geometry(v) | Value::String(v) => Ok(Geometry::new(v.clone())),
255 Value::Null => Err(crate::Error::TypeError(
256 "NULL value for Geometry".to_string(),
257 )),
258 other => Err(crate::Error::TypeError(format!(
259 "expected Geometry or String, got {:?}",
260 other
261 ))),
262 }
263 }
264
265 fn from_value_owned(value: Value) -> Result<Self> {
266 match value {
267 Value::Geometry(v) | Value::String(v) => Ok(Geometry::new(v)),
268 Value::Null => Err(crate::Error::TypeError(
269 "NULL value for Geometry".to_string(),
270 )),
271 other => Err(crate::Error::TypeError(format!(
272 "expected Geometry or String, got {:?}",
273 other
274 ))),
275 }
276 }
277}
278
279impl FromValue for Geography {
280 fn from_value(value: &Value) -> Result<Self> {
281 match value {
282 Value::Geography(v) | Value::String(v) => Ok(Geography::new(v.clone())),
283 Value::Null => Err(crate::Error::TypeError(
284 "NULL value for Geography".to_string(),
285 )),
286 other => Err(crate::Error::TypeError(format!(
287 "expected Geography or String, got {:?}",
288 other
289 ))),
290 }
291 }
292
293 fn from_value_owned(value: Value) -> Result<Self> {
294 match value {
295 Value::Geography(v) | Value::String(v) => Ok(Geography::new(v)),
296 Value::Null => Err(crate::Error::TypeError(
297 "NULL value for Geography".to_string(),
298 )),
299 other => Err(crate::Error::TypeError(format!(
300 "expected Geography or String, got {:?}",
301 other
302 ))),
303 }
304 }
305}
306
307impl FromValue for Vec<u8> {
308 fn from_value(value: &Value) -> Result<Self> {
309 match value {
310 Value::Bytes(v) => Ok(v.clone()),
311 Value::Null => Err(crate::Error::TypeError("NULL value for Bytes".to_string())),
312 _ => Err(crate::Error::TypeError(format!(
313 "expected Bytes, got {:?}",
314 value
315 ))),
316 }
317 }
318
319 fn from_value_owned(value: Value) -> Result<Self> {
320 match value {
321 Value::Bytes(v) => Ok(v),
322 Value::Null => Err(crate::Error::TypeError("NULL value for Bytes".to_string())),
323 other => Err(crate::Error::TypeError(format!(
324 "expected Bytes, got {:?}",
325 other
326 ))),
327 }
328 }
329}
330
331impl FromValue for Vec<f32> {
332 fn from_value(value: &Value) -> Result<Self> {
333 match value {
334 Value::Vector(values) => Ok(values.clone()),
335 Value::Array(items) => items.iter().map(f32::from_value).collect(),
336 Value::Json(json_value) => decode_json_array(json_value, f32::from_value),
337 Value::Null => Err(crate::Error::TypeError(
338 "NULL value for Vec<f32>".to_string(),
339 )),
340 _ => Err(crate::Error::TypeError(format!(
341 "expected Vector, Array, or Json for Vec<f32>, got {:?}",
342 value
343 ))),
344 }
345 }
346
347 fn from_value_owned(value: Value) -> Result<Self> {
348 match value {
349 Value::Vector(values) => Ok(values),
350 other => Self::from_value(&other),
351 }
352 }
353}
354
355impl<T: FromValue> FromValue for Option<T> {
356 fn from_value(value: &Value) -> Result<Self> {
357 match value {
358 Value::Null => Ok(None),
359 _ => T::from_value(value).map(Some),
360 }
361 }
362
363 fn from_value_owned(value: Value) -> Result<Self> {
364 match value {
365 Value::Null => Ok(None),
366 _ => T::from_value_owned(value).map(Some),
367 }
368 }
369}
370
371macro_rules! impl_vec_from_value {
378 ($T:ty) => {
379 impl FromValue for Vec<$T> {
380 fn from_value(value: &Value) -> Result<Self> {
381 match value {
382 Value::Array(items) => items.iter().map(<$T>::from_value).collect(),
383 Value::Json(json_value) => decode_json_array(json_value, <$T>::from_value),
384 Value::Null => Err(crate::Error::TypeError(
385 concat!("NULL value for Vec<", stringify!($T), ">").to_string(),
386 )),
387 _ => Err(crate::Error::TypeError(format!(
388 concat!(
389 "expected Array or Json for Vec<",
390 stringify!($T),
391 ">, got {:?}"
392 ),
393 value
394 ))),
395 }
396 }
397 }
398
399 impl FromValue for Vec<Vec<$T>> {
400 fn from_value(value: &Value) -> Result<Self> {
401 match value {
402 Value::Array2D(rows) => rows
403 .iter()
404 .map(|row| row.iter().map(<$T>::from_value).collect())
405 .collect(),
406 Value::Json(json_value) => decode_json_2d_array(json_value, <$T>::from_value),
407 Value::Null => Err(crate::Error::TypeError(
408 concat!("NULL value for Vec<Vec<", stringify!($T), ">>").to_string(),
409 )),
410 _ => Err(crate::Error::TypeError(format!(
411 concat!(
412 "expected Array2D or Json for Vec<Vec<",
413 stringify!($T),
414 ">>, got {:?}"
415 ),
416 value
417 ))),
418 }
419 }
420 }
421 };
422}
423
424impl_vec_from_value!(String);
425impl_vec_from_value!(i32);
426impl_vec_from_value!(i64);
427impl_vec_from_value!(f64);
428impl_vec_from_value!(bool);
429impl_vec_from_value!(rust_decimal::Decimal);
430impl_vec_from_value!(chrono::NaiveDateTime);
431impl_vec_from_value!(uuid::Uuid);
432impl_vec_from_value!(serde_json::Value);
433impl_vec_from_value!(BTreeMap<String, Option<String>>);
434
435fn decode_json_array<T, F>(json_value: &serde_json::Value, decoder: F) -> Result<Vec<T>>
436where
437 F: Fn(&Value) -> Result<T>,
438{
439 if let serde_json::Value::Array(arr) = json_value {
440 let mut result = Vec::with_capacity(arr.len());
441 for json_item in arr {
442 let value = crate::value::json_to_value_ref(json_item);
443 result.push(decoder(&value)?);
444 }
445 Ok(result)
446 } else {
447 Err(crate::Error::TypeError(format!(
448 "expected JSON array, got {:?}",
449 json_value
450 )))
451 }
452}
453
454fn decode_json_2d_array<T, F>(json_value: &serde_json::Value, decoder: F) -> Result<Vec<Vec<T>>>
455where
456 F: Fn(&Value) -> Result<T>,
457{
458 if let serde_json::Value::Array(outer_arr) = json_value {
459 let mut result = Vec::with_capacity(outer_arr.len());
460 for json_row in outer_arr {
461 if let serde_json::Value::Array(inner_arr) = json_row {
462 let mut row = Vec::with_capacity(inner_arr.len());
463 for json_item in inner_arr {
464 let value = crate::value::json_to_value_ref(json_item);
465 row.push(decoder(&value)?);
466 }
467 result.push(row);
468 } else {
469 return Err(crate::Error::TypeError(format!(
470 "expected inner JSON array, got {:?}",
471 json_row
472 )));
473 }
474 }
475 Ok(result)
476 } else {
477 Err(crate::Error::TypeError(format!(
478 "expected JSON 2D array, got {:?}",
479 json_value
480 )))
481 }
482}
483
484fn decode_hstore_json_object(
485 object: &serde_json::Map<String, serde_json::Value>,
486) -> Result<BTreeMap<String, Option<String>>> {
487 let mut decoded = BTreeMap::new();
488 for (key, value) in object {
489 let mapped = match value {
490 serde_json::Value::String(item) => Some(item.clone()),
491 serde_json::Value::Null => None,
492 other => {
493 return Err(crate::Error::TypeError(format!(
494 "expected Hstore JSON value to be string or null for key {:?}, got {:?}",
495 key, other
496 )));
497 }
498 };
499 decoded.insert(key.clone(), mapped);
500 }
501 Ok(decoded)
502}
503
504#[cfg(test)]
505mod tests {
506 use std::collections::BTreeMap;
507
508 use super::FromValue;
509 use crate::Value;
510
511 #[test]
512 fn decimal_uuid_datetime_and_json_arrays_decode_from_json_storage() {
513 let decimals = Value::Json(serde_json::json!(["12.34", "56.78"]));
514 let uuids = Value::Json(serde_json::json!([
515 "550e8400-e29b-41d4-a716-446655440000",
516 "123e4567-e89b-12d3-a456-426614174000"
517 ]));
518 let datetimes = Value::Json(serde_json::json!([
519 "2026-02-18T10:30:45Z",
520 "2026-02-19T11:31:46Z"
521 ]));
522 let jsons = Value::Json(serde_json::json!([
523 {"name": "Alice"},
524 42,
525 true
526 ]));
527
528 let decimals: Vec<rust_decimal::Decimal> = Vec::from_value(&decimals).unwrap();
529 let uuids: Vec<uuid::Uuid> = Vec::from_value(&uuids).unwrap();
530 let datetimes: Vec<chrono::NaiveDateTime> = Vec::from_value(&datetimes).unwrap();
531 let jsons: Vec<serde_json::Value> = Vec::from_value(&jsons).unwrap();
532
533 assert_eq!(decimals.len(), 2);
534 assert_eq!(uuids.len(), 2);
535 assert_eq!(datetimes.len(), 2);
536 assert_eq!(
537 jsons,
538 vec![
539 serde_json::json!({"name": "Alice"}),
540 serde_json::json!(42),
541 serde_json::json!(true),
542 ]
543 );
544 }
545
546 #[test]
547 fn uuid_and_decimal_scalars_accept_string_values() {
548 let uuid = uuid::Uuid::from_value(&Value::String(
549 "550e8400-e29b-41d4-a716-446655440000".to_string(),
550 ))
551 .unwrap();
552 let decimal =
553 rust_decimal::Decimal::from_value(&Value::String("12.34".to_string())).unwrap();
554
555 assert_eq!(uuid.to_string(), "550e8400-e29b-41d4-a716-446655440000");
556 assert_eq!(decimal.to_string(), "12.34");
557 }
558
559 #[test]
560 fn hstore_scalar_accepts_native_and_json_object_values() {
561 let native = Value::Hstore(BTreeMap::from([
562 ("display_name".to_string(), Some("Bob".to_string())),
563 ("nickname".to_string(), None),
564 ]));
565 let json = Value::Json(serde_json::json!({
566 "display_name": "Bob",
567 "nickname": null
568 }));
569
570 let native_map = BTreeMap::<String, Option<String>>::from_value(&native).unwrap();
571 let json_map = BTreeMap::<String, Option<String>>::from_value(&json).unwrap();
572
573 assert_eq!(native_map, json_map);
574 assert_eq!(native_map["display_name"], Some("Bob".to_string()));
575 assert_eq!(native_map["nickname"], None);
576 }
577
578 #[test]
579 fn hstore_arrays_decode_from_json_storage() {
580 let json = Value::Json(serde_json::json!([
581 {"display_name": "Bob", "nickname": null},
582 {"display_name": "OpenAI", "nickname": "oai"}
583 ]));
584
585 let decoded: Vec<BTreeMap<String, Option<String>>> = Vec::from_value(&json).unwrap();
586
587 assert_eq!(decoded.len(), 2);
588 assert_eq!(decoded[0]["display_name"], Some("Bob".to_string()));
589 assert_eq!(decoded[0]["nickname"], None);
590 assert_eq!(decoded[1]["nickname"], Some("oai".to_string()));
591 }
592
593 #[test]
594 fn vector_decodes_from_native_and_json_values() {
595 let native = Value::Vector(vec![0.1, 0.2, 0.3]);
596 let json = Value::Json(serde_json::json!([0.1, 0.2, 0.3]));
597
598 assert_eq!(
599 Vec::<f32>::from_value(&native).unwrap(),
600 vec![0.1, 0.2, 0.3]
601 );
602 assert_eq!(Vec::<f32>::from_value(&json).unwrap(), vec![0.1, 0.2, 0.3]);
603 }
604}