1#[cfg(feature = "numeric")]
2use bigdecimal::BigDecimal;
3use prost::bytes::Bytes;
4
5use crate::{Error, Type, Value};
6
7pub trait FromSpanner<'a>: Sized {
41 fn from_spanner(value: &'a Value) -> Result<Self, Error>;
44
45 #[allow(unused_variables)]
47 fn from_spanner_null(tpe: &Type) -> Result<Self, Error> {
48 Err(crate::Error::Codec("value was null".to_string()))
49 }
50
51 fn from_spanner_nullable(value: &'a Value) -> Result<Self, Error> {
55 match value {
56 Value::Null(tpe) => Self::from_spanner_null(tpe),
57 not_null => Self::from_spanner(not_null),
58 }
59 }
60}
61
62impl<'a, T> FromSpanner<'a> for Option<T>
63where
64 T: FromSpanner<'a>,
65{
66 fn from_spanner(value: &'a Value) -> Result<Self, Error> {
67 <T as FromSpanner>::from_spanner(value).map(Some)
68 }
69
70 fn from_spanner_null(_tpe: &Type) -> Result<Self, Error> {
71 Ok(None)
72 }
73}
74
75macro_rules! wrong_type {
76 ($expect:ident, $tpe:expr) => {
77 Err(Error::Codec(format!(
78 "type {:?} is unsupported by FromSpanner impl, expected {:?}",
79 $tpe,
80 Type::$expect,
81 )))
82 };
83}
84
85impl<'a, T> FromSpanner<'a> for Vec<T>
86where
87 T: FromSpanner<'a>,
88{
89 fn from_spanner(value: &'a Value) -> Result<Self, Error> {
90 match value {
91 Value::Array(_, values) => values
92 .iter()
93 .map(|value| <T as FromSpanner>::from_spanner_nullable(value))
94 .collect(),
95 _ => wrong_type!(String, value.spanner_type()),
96 }
97 }
98}
99
100impl<'a> FromSpanner<'a> for String {
101 fn from_spanner(value: &'a Value) -> Result<Self, Error> {
102 match value {
103 Value::String(v) => Ok(v.clone()),
104 _ => wrong_type!(String, value.spanner_type()),
105 }
106 }
107}
108
109impl<'a> FromSpanner<'a> for &'a str {
110 fn from_spanner(value: &'a Value) -> Result<Self, Error> {
111 match value {
112 Value::String(v) => Ok(v),
113 _ => wrong_type!(String, value.spanner_type()),
114 }
115 }
116}
117
118macro_rules! simple {
119 ($t:ty, $f:ident, TryFrom::try_from) => {
120 impl<'a> FromSpanner<'a> for $t {
121 fn from_spanner(value: &'a Value) -> Result<$t, Error> {
122 match value {
123 Value::$f(v) => Ok(TryFrom::try_from(*v)?),
124 _ => wrong_type!($f, value.spanner_type()),
125 }
126 }
127 }
128 };
129 ($t:ty, $f:ident, $from:path) => {
130 impl<'a> FromSpanner<'a> for $t {
131 fn from_spanner(value: &'a Value) -> Result<$t, Error> {
132 match value {
133 Value::$f(v) => Ok($from(v)),
134 _ => wrong_type!($f, value.spanner_type()),
135 }
136 }
137 }
138 };
139}
140
141#[inline]
142fn copy<T>(value: &T) -> T
143where
144 T: Copy,
145{
146 *value
147}
148
149simple!(i8, Int64, TryFrom::try_from);
150simple!(u8, Int64, TryFrom::try_from);
151simple!(i16, Int64, TryFrom::try_from);
152simple!(u16, Int64, TryFrom::try_from);
153simple!(i32, Int64, TryFrom::try_from);
154simple!(u32, Int64, TryFrom::try_from);
155simple!(i64, Int64, copy);
156simple!(f64, Float64, copy);
157simple!(bool, Bool, copy);
158#[cfg(feature = "numeric")]
159simple!(BigDecimal, Numeric, Clone::clone);
160#[cfg(feature = "numeric")]
161simple!(&'a BigDecimal, Numeric, std::convert::identity);
162simple!(Bytes, Bytes, Clone::clone);
163simple!(&'a Bytes, Bytes, std::convert::identity);
164simple!(&'a [u8], Bytes, std::convert::identity);
165#[cfg(feature = "json")]
166simple!(serde_json::Value, Json, Clone::clone);
167#[cfg(feature = "json")]
168simple!(&'a serde_json::Value, Json, std::convert::identity);
169#[cfg(feature = "temporal")]
170simple!(chrono::DateTime<chrono::Utc>, Timestamp, Clone::clone);
171#[cfg(feature = "temporal")]
172simple!(
173 &'a chrono::DateTime<chrono::Utc>,
174 Timestamp,
175 std::convert::identity
176);
177#[cfg(feature = "temporal")]
178simple!(chrono::NaiveDate, Date, Clone::clone);
179#[cfg(feature = "temporal")]
180simple!(&'a chrono::NaiveDate, Date, std::convert::identity);
181
182#[cfg(test)]
183mod test {
184 use super::*;
185 use crate::{Type, Value};
186 #[cfg(feature = "numeric")]
187 use bigdecimal::{BigDecimal, FromPrimitive};
188
189 macro_rules! from_spanner_ok {
190 ($t:ty, $ok_tpe:ident, $($ok_val:expr),+) => {
191 $(
192 let result = <$t as FromSpanner>::from_spanner_nullable(
193 &Value::$ok_tpe($ok_val.into()),
194 );
195 assert_eq!(result.ok(), Some($ok_val));
196 )+
197 };
198 }
199 macro_rules! from_spanner_err {
200 ($t:ty, $err_tpe:ident, $($err_val:expr), +) => {
201 $(
202 let result = <$t as FromSpanner>::from_spanner_nullable(
203 &Value::$err_tpe($err_val),
204 );
205 assert!(
206 result.is_err(),
207 "value {:?} expected to fail",
208 &Value::$err_tpe($err_val)
209 );
210 )+
211 };
212 }
213 macro_rules! from_spanner_non_nullable {
214 ($t:ty, $tpe:ident) => {
215 let result = <$t as FromSpanner>::from_spanner_nullable(&Value::Null(Type::$tpe));
216 assert!(
217 result.is_err(),
218 "expected Err from null value, got {:?}",
219 result
220 );
221 };
222 }
223 macro_rules! from_spanner_nullable {
224 ($t:ty, $tpe:ident) => {
225 let result =
226 <Option<$t> as FromSpanner>::from_spanner_nullable(&Value::Null(Type::$tpe));
227 assert_eq!(result.ok(), Some(None));
228 };
229 }
230
231 macro_rules! from_spanner_int64 {
232 ($t:ty) => {
233 from_spanner_ok!($t, Int64, <$t>::MIN, <$t>::MAX, 0);
234 from_spanner_err!($t, Float64, 0.0, 42.5);
235 from_spanner_err!($t, Bool, true, false);
236 from_spanner_err!($t, String, "this is not an int64".to_string());
237 from_spanner_non_nullable!($t, Int64);
238 from_spanner_nullable!($t, Int64);
239 };
240 ($($t:ty),+) => {
241 $(
242 from_spanner_int64!($t);
243 )+
244 };
245 }
246
247 #[test]
248 fn test_from_spanner_int64() {
249 from_spanner_int64!(i8, u8, i16, u16, i32, u32, i64);
250 }
251
252 #[test]
253 fn test_from_spanner_bool() {
254 from_spanner_ok!(bool, Bool, true, false);
255 from_spanner_err!(bool, Float64, 0.0);
256 from_spanner_err!(bool, Int64, 0);
257 from_spanner_err!(bool, String, "this is not a bool".to_string());
258 from_spanner_non_nullable!(bool, Bool);
259 from_spanner_nullable!(bool, Bool);
260 }
261
262 #[test]
263 fn test_from_spanner_bytes() {
264 from_spanner_ok!(
265 Bytes,
266 Bytes,
267 Bytes::from_static(&[1, 2, 3, 4]),
268 Bytes::from_static(&[])
269 );
270 from_spanner_err!(Bytes, Float64, 0.0);
271 from_spanner_err!(Bytes, Int64, 0);
272 from_spanner_non_nullable!(Bytes, Bytes);
273 from_spanner_nullable!(Bytes, Bytes);
274
275 let data: &'static [u8] = &[1, 2, 3, 4];
277 let bytes = Value::Bytes(Bytes::from_static(data));
278 let slice = <&[u8] as FromSpanner>::from_spanner_nullable(&bytes);
279 assert_eq!(slice.ok(), Some(data));
280 }
281
282 #[test]
283 fn test_from_spanner_float64() {
284 from_spanner_ok!(
285 f64,
286 Float64,
287 f64::MIN,
288 f64::MAX,
289 f64::NEG_INFINITY,
291 0.0
292 );
293 from_spanner_err!(f64, Bool, true);
294 from_spanner_err!(f64, Int64, 0);
295 from_spanner_err!(f64, String, "this is not a bool".to_string());
296 from_spanner_non_nullable!(f64, Float64);
297 from_spanner_nullable!(f64, Float64);
298 }
299
300 #[cfg(feature = "numeric")]
301 #[test]
302 fn test_from_spanner_numeric() {
303 from_spanner_ok!(
304 BigDecimal,
305 Numeric,
306 BigDecimal::from_i128(0).unwrap(),
307 BigDecimal::from_i128(42).unwrap()
308 );
309 from_spanner_err!(BigDecimal, Float64, 0.0);
310 from_spanner_err!(BigDecimal, Int64, 0);
311 from_spanner_err!(BigDecimal, String, "this is not a bool".to_string());
312 from_spanner_non_nullable!(BigDecimal, Numeric);
313 from_spanner_nullable!(BigDecimal, Numeric);
314 }
315
316 #[test]
317 fn test_from_spanner_array() {
318 let bool_array = Type::Array(Box::new(Type::Bool));
319 let value = Value::Array(Type::Bool, vec![Value::Bool(true), Value::Bool(false)]);
320
321 let result = <Vec<bool> as FromSpanner>::from_spanner_nullable(&value);
322 assert_eq!(result.ok(), Some(vec![true, false]));
323 let result =
324 <Vec<bool> as FromSpanner>::from_spanner_nullable(&Value::Array(Type::Bool, vec![]));
325 assert_eq!(result.ok(), Some(vec![]));
326
327 let result =
328 <Vec<bool> as FromSpanner>::from_spanner_nullable(&Value::Null(bool_array.clone()));
329 assert!(result.is_err());
330 let result = <Option<Vec<bool>> as FromSpanner>::from_spanner_nullable(&Value::Null(
331 bool_array.clone(),
332 ));
333 assert_eq!(result.ok(), Some(None));
334
335 let result = <Vec<Option<bool>> as FromSpanner>::from_spanner_nullable(&Value::Array(
336 Type::Bool,
337 vec![
338 Value::Bool(true),
339 Value::Null(bool_array),
340 Value::Bool(false),
341 ],
342 ))
343 .unwrap();
344 assert_eq!(result, vec![Some(true), None, Some(false)]);
345 }
346
347 #[test]
348 fn test_from_spanner_string() {
349 from_spanner_ok!(
350 String,
351 String,
352 "this is a string".to_string(),
353 "".to_string()
354 );
355 from_spanner_err!(String, Float64, 0.0);
356 from_spanner_err!(String, Int64, 0);
357 from_spanner_non_nullable!(String, String);
358 from_spanner_nullable!(String, String);
359 }
360}