1use radixdb_core::{DataType, Error, Result, Value};
18
19use crate::params::DecimalValue;
20
21pub trait FromValue: Sized {
23 fn from_value(value: &Value) -> Result<Self>;
25}
26
27impl FromValue for i64 {
28 fn from_value(value: &Value) -> Result<Self> {
29 match value {
30 Value::Integer(i) => Ok(*i),
31 Value::Float(f)
32 if f.is_finite() && *f >= i64::MIN as f64 && *f < -(i64::MIN as f64) =>
33 {
34 let integer = *f as i64;
35 (Value::Integer(integer) == Value::Float(*f))
36 .then_some(integer)
37 .ok_or_else(|| Error::type_conversion(format!("{value:?}"), "Integer"))
38 }
39 _ => Err(Error::TypeConversion {
40 from: format!("{:?}", value),
41 to: "Integer".to_string(),
42 }),
43 }
44 }
45}
46
47impl FromValue for i32 {
48 fn from_value(value: &Value) -> Result<Self> {
49 let integer = i64::from_value(value)?;
50 i32::try_from(integer).map_err(|_| Error::type_conversion(format!("{value:?}"), "Integer"))
51 }
52}
53
54impl FromValue for f64 {
55 fn from_value(value: &Value) -> Result<Self> {
56 let candidate = match value {
57 Value::Float(f) => return Ok(*f),
58 Value::Integer(i) => *i as f64,
59 Value::Extension(data) if data.first() == Some(&(DataType::Decimal as u8)) => value
64 .as_decimal_parts()
65 .and_then(|(unscaled, _, scale)| {
66 radixdb_core::value::format_decimal_parts(unscaled, scale)
67 .parse::<f64>()
68 .ok()
69 })
70 .ok_or_else(|| Error::TypeConversion {
71 from: format!("{:?}", value),
72 to: "Float".to_string(),
73 })?,
74 _ => return Err(Error::type_conversion(format!("{value:?}"), "Float")),
75 };
76 if Value::Float(candidate) == *value {
77 Ok(candidate)
78 } else {
79 Err(Error::type_conversion(format!("{value:?}"), "Float"))
80 }
81 }
82}
83
84impl FromValue for String {
85 fn from_value(value: &Value) -> Result<Self> {
86 match value {
87 Value::Text(s) => Ok(s.to_string()),
88 Value::Extension(data) if data.first() == Some(&(DataType::Json as u8)) => {
89 std::str::from_utf8(&data[1..])
90 .map(str::to_owned)
91 .map_err(|_| Error::type_conversion(format!("{value:?}"), "String"))
92 }
93 Value::Integer(i) => Ok(i.to_string()),
94 Value::Float(f) => Ok(f.to_string()),
95 Value::Boolean(b) => Ok(if *b {
96 "true".to_string()
97 } else {
98 "false".to_string()
99 }),
100 Value::Timestamp(ts) => Ok(ts.to_rfc3339_opts(chrono::SecondsFormat::AutoSi, true)),
101 Value::Extension(_) => value
102 .as_string()
103 .ok_or_else(|| Error::invalid_argument("Cannot convert extension to String")),
104 Value::Null(_) => Err(Error::type_conversion("NULL", "String")),
105 }
106 }
107}
108
109impl FromValue for bool {
110 fn from_value(value: &Value) -> Result<Self> {
111 match value {
112 Value::Boolean(b) => Ok(*b),
113 Value::Integer(i) => Ok(*i != 0),
114 _ => Err(Error::TypeConversion {
115 from: format!("{:?}", value),
116 to: "Boolean".to_string(),
117 }),
118 }
119 }
120}
121
122impl FromValue for Value {
123 fn from_value(value: &Value) -> Result<Self> {
124 Ok(value.clone())
125 }
126}
127
128impl FromValue for chrono::DateTime<chrono::Utc> {
129 fn from_value(value: &Value) -> Result<Self> {
130 match value {
131 Value::Timestamp(timestamp) => Ok(*timestamp),
132 _ => Err(Error::type_conversion(format!("{value:?}"), "Timestamp")),
133 }
134 }
135}
136
137impl FromValue for chrono::NaiveDate {
138 fn from_value(value: &Value) -> Result<Self> {
139 let days = value
140 .as_date_days()
141 .ok_or_else(|| Error::type_conversion(format!("{value:?}"), "Date"))?;
142 chrono::NaiveDate::from_ymd_opt(1970, 1, 1)
143 .expect("valid Unix epoch date")
144 .checked_add_signed(chrono::Duration::days(i64::from(days)))
145 .ok_or_else(|| Error::type_conversion(format!("{value:?}"), "Date"))
146 }
147}
148
149impl FromValue for Vec<u8> {
150 fn from_value(value: &Value) -> Result<Self> {
151 value
152 .as_bytes_value()
153 .map(ToOwned::to_owned)
154 .ok_or_else(|| Error::type_conversion(format!("{value:?}"), "Bytes"))
155 }
156}
157
158impl FromValue for Vec<f32> {
159 fn from_value(value: &Value) -> Result<Self> {
160 value
161 .as_vector_f32()
162 .ok_or_else(|| Error::type_conversion(format!("{value:?}"), "Vector"))
163 }
164}
165
166impl FromValue for uuid::Uuid {
167 fn from_value(value: &Value) -> Result<Self> {
168 value
169 .as_uuid_bytes()
170 .map(uuid::Uuid::from_bytes)
171 .ok_or_else(|| Error::type_conversion(format!("{value:?}"), "UUID"))
172 }
173}
174
175impl FromValue for serde_json::Value {
176 fn from_value(value: &Value) -> Result<Self> {
177 let json = value
178 .as_json()
179 .ok_or_else(|| Error::type_conversion(format!("{value:?}"), "JSON"))?;
180 serde_json::from_str(json).map_err(|_| Error::type_conversion(format!("{value:?}"), "JSON"))
181 }
182}
183
184impl FromValue for DecimalValue {
185 fn from_value(value: &Value) -> Result<Self> {
186 let (unscaled, precision, scale) = value
187 .as_decimal_parts()
188 .ok_or_else(|| Error::type_conversion(format!("{value:?}"), "Decimal"))?;
189 DecimalValue::try_new(unscaled, precision, scale)
190 }
191}
192
193impl<T: FromValue> FromValue for Option<T> {
194 fn from_value(value: &Value) -> Result<Self> {
195 if value.is_null() {
196 Ok(None)
197 } else {
198 Ok(Some(T::from_value(value)?))
199 }
200 }
201}