1#[cfg(feature = "numeric")]
2use bigdecimal::BigDecimal;
3use prost::bytes::Bytes;
4
5use crate::{Error, Type, Value};
6
7pub trait ToSpanner {
41 fn to_spanner(&self) -> Result<Value, Error>;
43
44 fn spanner_type() -> Type
46 where
47 Self: Sized;
48}
49
50impl<T> ToSpanner for Option<T>
51where
52 T: ToSpanner,
53{
54 fn to_spanner(&self) -> Result<Value, Error> {
55 match self.as_ref() {
56 Some(v) => v.to_spanner(),
57 None => Ok(Value::Null(<T as ToSpanner>::spanner_type())),
58 }
59 }
60 fn spanner_type() -> Type {
61 <T as ToSpanner>::spanner_type()
62 }
63}
64
65impl<T> ToSpanner for Vec<T>
66where
67 T: ToSpanner,
68{
69 fn to_spanner(&self) -> Result<Value, Error> {
70 let values = self
71 .iter()
72 .map(|v| v.to_spanner())
73 .collect::<Result<Vec<Value>, Error>>()?;
74 Ok(Value::Array(<T as ToSpanner>::spanner_type(), values))
75 }
76 fn spanner_type() -> Type {
77 Type::Array(Box::new(<T as ToSpanner>::spanner_type()))
78 }
79}
80
81impl<T> ToSpanner for &[T]
82where
83 T: ToSpanner,
84{
85 fn to_spanner(&self) -> Result<Value, Error> {
86 let values = self
87 .iter()
88 .map(|v| v.to_spanner())
89 .collect::<Result<Vec<Value>, Error>>()?;
90 Ok(Value::Array(<T as ToSpanner>::spanner_type(), values))
91 }
92 fn spanner_type() -> Type {
93 Type::Array(Box::new(<T as ToSpanner>::spanner_type()))
94 }
95}
96
97macro_rules! simple {
98 ($t:ty, $v:ident, $into:path $(, $deref:tt)?) => {
99 impl ToSpanner for $t {
100 fn to_spanner(&self) -> Result<Value, Error> {
101 Ok(Value::$v($into($($deref)? self)))
102 }
103
104 fn spanner_type() -> Type {
105 Type::$v
106 }
107 }
108 };
109}
110
111simple!(i8, Int64, i64::from, *);
112simple!(u8, Int64, i64::from, *);
113simple!(i16, Int64, i64::from, *);
114simple!(u16, Int64, i64::from, *);
115simple!(i32, Int64, i64::from, *);
116simple!(u32, Int64, i64::from, *);
117simple!(i64, Int64, i64::from, *);
118simple!(String, String, Clone::clone);
119simple!(&str, String, ToString::to_string);
120#[cfg(feature = "numeric")]
121simple!(BigDecimal, Numeric, Clone::clone);
122simple!(Bytes, Bytes, Clone::clone);
123#[cfg(feature = "json")]
124simple!(serde_json::Value, Json, Clone::clone);
125#[cfg(feature = "temporal")]
126simple!(chrono::DateTime<chrono::Utc>, Timestamp, Clone::clone);
127#[cfg(feature = "temporal")]
128simple!(chrono::NaiveDate, Date, Clone::clone);
129
130#[cfg(test)]
131mod test {
132 use super::*;
133
134 macro_rules! simple_test_int64 {
135 ($t:ty) => {
136 assert_eq!((0 as $t).to_spanner().ok(), Some(Value::Int64(0)));
137 };
138 ($($t:ty),+) => {
139 $(
140 simple_test_int64!($t);
141 )+
142 };
143 }
144
145 #[test]
146 fn test_to_spanner_simple_int64() {
147 simple_test_int64!(i8, u8, i16, u16, i32, u32, i64);
148 }
149
150 #[test]
151 fn test_to_spanner_opt() {
152 let some = Some(0 as u32);
153 assert_eq!(some.to_spanner().ok(), Some(Value::Int64(0)));
154 let none: Option<u32> = None;
155 assert_eq!(none.to_spanner().ok(), Some(Value::Null(Type::Int64)));
156 }
157
158 #[test]
159 fn test_to_spanner_array() {
160 let array = vec![0, 1, 2, 3, 4];
161 assert_eq!(
162 array.to_spanner().ok(),
163 Some(Value::Array(
164 Type::Int64,
165 vec![
166 Value::Int64(0),
167 Value::Int64(1),
168 Value::Int64(2),
169 Value::Int64(3),
170 Value::Int64(4)
171 ]
172 ))
173 );
174 let empty: Vec<u32> = vec![];
175 assert_eq!(
176 empty.to_spanner().ok(),
177 Some(Value::Array(Type::Int64, vec![]))
178 );
179 }
180}