Skip to main content

google_cloud_spanner/
to_value.rs

1// Copyright 2026 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15pub use crate::value::Value;
16use base64::Engine;
17use base64::prelude::BASE64_STANDARD;
18use prost_types::Value as ProtoValue;
19use rust_decimal::Decimal;
20
21use std::time::SystemTime;
22use time::{Date, OffsetDateTime};
23
24/// Converts Rust types to Spanner [Value].
25///
26/// This trait is used to encode native Rust types into the generic `Value`
27/// representation suitable for transmission to Cloud Spanner (such as in query parameters
28/// or mutation values).
29///
30/// Implementations are provided for standard Rust types, mapping them to their appropriate
31/// Spanner values. For example, optional types naturally map to `Value::Null` when they are `None`.
32pub trait ToValue {
33    /// Encodes this Rust type as a Spanner `Value`.
34    ///
35    /// Implementations are responsible for using the correct value kind for the
36    /// corresponding data type in Spanner.
37    fn to_value(&self) -> Value;
38}
39
40impl<T> ToValue for Option<T>
41where
42    T: ToValue,
43{
44    fn to_value(&self) -> Value {
45        match self {
46            Some(v) => v.to_value(),
47            None => Value(ProtoValue {
48                kind: Some(prost_types::value::Kind::NullValue(0)),
49            }),
50        }
51    }
52}
53
54impl ToValue for Value {
55    fn to_value(&self) -> Value {
56        self.clone()
57    }
58}
59
60impl ToValue for ProtoValue {
61    fn to_value(&self) -> Value {
62        Value(self.clone())
63    }
64}
65
66impl ToValue for String {
67    fn to_value(&self) -> Value {
68        Value(ProtoValue {
69            kind: Some(prost_types::value::Kind::StringValue(self.clone())),
70        })
71    }
72}
73
74impl ToValue for &str {
75    fn to_value(&self) -> Value {
76        Value(ProtoValue {
77            kind: Some(prost_types::value::Kind::StringValue(self.to_string())),
78        })
79    }
80}
81
82impl ToValue for i64 {
83    fn to_value(&self) -> Value {
84        Value(ProtoValue {
85            kind: Some(prost_types::value::Kind::StringValue(self.to_string())),
86        })
87    }
88}
89
90impl ToValue for i32 {
91    fn to_value(&self) -> Value {
92        Value(ProtoValue {
93            kind: Some(prost_types::value::Kind::StringValue(self.to_string())),
94        })
95    }
96}
97
98impl ToValue for Decimal {
99    fn to_value(&self) -> Value {
100        Value(ProtoValue {
101            kind: Some(prost_types::value::Kind::StringValue(self.to_string())),
102        })
103    }
104}
105
106impl ToValue for SystemTime {
107    fn to_value(&self) -> Value {
108        let dt = OffsetDateTime::from(*self);
109        Value(ProtoValue {
110            kind: Some(prost_types::value::Kind::StringValue(
111                dt.format(crate::value::SPANNER_TIMESTAMP_FORMAT)
112                    .expect("failed to format time"),
113            )),
114        })
115    }
116}
117
118impl ToValue for OffsetDateTime {
119    fn to_value(&self) -> Value {
120        Value(ProtoValue {
121            kind: Some(prost_types::value::Kind::StringValue(
122                self.format(crate::value::SPANNER_TIMESTAMP_FORMAT)
123                    .expect("failed to format time"),
124            )),
125        })
126    }
127}
128
129impl ToValue for wkt::Timestamp {
130    fn to_value(&self) -> Value {
131        let dt = OffsetDateTime::try_from(*self)
132            .expect("valid wkt timestamp conversion to OffsetDateTime");
133        dt.to_value()
134    }
135}
136
137impl ToValue for Date {
138    fn to_value(&self) -> Value {
139        Value(ProtoValue {
140            kind: Some(prost_types::value::Kind::StringValue(
141                self.format(crate::value::SPANNER_DATE_FORMAT)
142                    .expect("failed to format date"),
143            )),
144        })
145    }
146}
147
148impl ToValue for bool {
149    fn to_value(&self) -> Value {
150        Value(ProtoValue {
151            kind: Some(prost_types::value::Kind::BoolValue(*self)),
152        })
153    }
154}
155
156impl ToValue for f64 {
157    fn to_value(&self) -> Value {
158        Value(ProtoValue {
159            kind: Some(prost_types::value::Kind::NumberValue(*self)),
160        })
161    }
162}
163
164impl ToValue for f32 {
165    fn to_value(&self) -> Value {
166        Value(ProtoValue {
167            kind: Some(prost_types::value::Kind::NumberValue(*self as f64)),
168        })
169    }
170}
171
172impl ToValue for Vec<u8> {
173    fn to_value(&self) -> Value {
174        Value(ProtoValue {
175            kind: Some(prost_types::value::Kind::StringValue(
176                BASE64_STANDARD.encode(self),
177            )),
178        })
179    }
180}
181
182impl<T> ToValue for Vec<T>
183where
184    T: ToValue,
185{
186    fn to_value(&self) -> Value {
187        Value(ProtoValue {
188            kind: Some(prost_types::value::Kind::ListValue(
189                prost_types::ListValue {
190                    values: self.iter().map(|v| v.to_value().0).collect(),
191                },
192            )),
193        })
194    }
195}
196
197#[cfg(test)]
198mod tests {
199    use super::*;
200    use crate::value::Kind;
201    use std::str::FromStr;
202
203    #[test]
204    fn test_to_value_string() {
205        let v = "hello".to_string().to_value();
206        assert_eq!(v.kind(), Kind::String);
207        assert_eq!(v.as_string(), "hello");
208
209        let v = "world".to_value();
210        assert_eq!(v.kind(), Kind::String);
211        assert_eq!(v.as_string(), "world");
212    }
213
214    #[test]
215    fn test_to_value_int() {
216        let v = 42i64.to_value();
217        assert_eq!(v.kind(), Kind::String);
218        assert_eq!(v.as_string(), "42");
219
220        let v = 42i32.to_value();
221        assert_eq!(v.kind(), Kind::String);
222        assert_eq!(v.as_string(), "42");
223    }
224
225    #[test]
226    fn test_to_value_float() {
227        let v = 42.5f64.to_value();
228        assert_eq!(v.kind(), Kind::Number);
229        assert_eq!(v.as_f64(), 42.5);
230
231        let v = 42.5f32.to_value();
232        assert_eq!(v.kind(), Kind::Number);
233        assert_eq!(v.as_f64(), 42.5);
234    }
235
236    #[test]
237    fn test_to_value_bool() {
238        let v = true.to_value();
239        assert_eq!(v.kind(), Kind::Bool);
240        assert!(v.as_bool());
241
242        let v = false.to_value();
243        assert_eq!(v.kind(), Kind::Bool);
244        assert!(!v.as_bool());
245    }
246
247    #[test]
248    fn test_to_value_bytes() {
249        let bytes: Vec<u8> = vec![1, 2, 3];
250        let v = bytes.to_value();
251        assert_eq!(v.kind(), Kind::String);
252        assert_eq!(v.as_string(), "AQID"); // Base64 encoded
253    }
254
255    #[test]
256    fn test_to_value_decimal() {
257        let d = Decimal::from_str("123.456").unwrap();
258        let v = d.to_value();
259        assert_eq!(v.kind(), Kind::String);
260        assert_eq!(v.as_string(), "123.456");
261    }
262
263    #[test]
264    fn test_to_value_date() {
265        let d = Date::from_calendar_date(2023, time::Month::October, 27).unwrap();
266        let v = d.to_value();
267        assert_eq!(v.kind(), Kind::String);
268        assert_eq!(v.as_string(), "2023-10-27");
269    }
270
271    #[test]
272    fn test_to_value_timestamp() {
273        let dt = OffsetDateTime::parse(
274            "2023-10-27T10:00:00Z",
275            &time::format_description::well_known::Rfc3339,
276        )
277        .unwrap();
278        let v = dt.to_value();
279        assert_eq!(v.kind(), Kind::String);
280        assert_eq!(v.as_string(), "2023-10-27T10:00:00.000000000Z");
281
282        let system_time: SystemTime = dt.into();
283        let v = system_time.to_value();
284        assert_eq!(v.kind(), Kind::String);
285        assert_eq!(v.as_string(), "2023-10-27T10:00:00.000000000Z");
286    }
287
288    #[test]
289    fn test_to_value_wkt_timestamp() {
290        let dt = OffsetDateTime::parse(
291            "2023-10-27T10:00:00Z",
292            &time::format_description::well_known::Rfc3339,
293        )
294        .expect("valid date time parsing");
295        let wkt_ts = wkt::Timestamp::try_from(dt).expect("valid wkt timestamp conversion");
296        let v = wkt_ts.to_value();
297        assert_eq!(v.kind(), Kind::String);
298        assert_eq!(v.as_string(), "2023-10-27T10:00:00.000000000Z");
299    }
300
301    #[test]
302    fn test_to_value_option() {
303        let some_val: Option<i32> = Some(42);
304        let v = some_val.to_value();
305        assert_eq!(v.kind(), Kind::String);
306        assert_eq!(v.as_string(), "42");
307
308        let none_val: Option<i32> = None;
309        let v = none_val.to_value();
310        assert_eq!(v.kind(), Kind::Null);
311    }
312
313    #[test]
314    fn test_to_value_value() {
315        let v_original = 42i32.to_value();
316        let v = v_original.to_value();
317        assert_eq!(v, v_original);
318
319        let v_proto = ProtoValue {
320            kind: Some(prost_types::value::Kind::BoolValue(true)),
321        };
322        let v = v_proto.to_value();
323        assert_eq!(v.kind(), Kind::Bool);
324        assert!(v.as_bool());
325    }
326
327    #[test]
328    fn test_to_value_array() {
329        let str_array = vec!["one".to_string(), "two".to_string()];
330        let v = str_array.to_value();
331        assert_eq!(v.kind(), Kind::List);
332        let list = v.as_list();
333        assert_eq!(list.len(), 2);
334        assert_eq!(
335            list.get(0).expect("element 0 should exist").as_string(),
336            "one"
337        );
338        assert_eq!(
339            list.get(1).expect("element 1 should exist").as_string(),
340            "two"
341        );
342
343        let int_array = vec![42i64, 100i64];
344        let v = int_array.to_value();
345        assert_eq!(v.kind(), Kind::List);
346        let list = v.as_list();
347        assert_eq!(list.len(), 2);
348        assert_eq!(
349            list.get(0).expect("element 0 should exist").as_string(),
350            "42"
351        );
352        assert_eq!(
353            list.get(1).expect("element 1 should exist").as_string(),
354            "100"
355        );
356
357        let bool_array = vec![true, false];
358        let v = bool_array.to_value();
359        assert_eq!(v.kind(), Kind::List);
360        let list = v.as_list();
361        assert_eq!(list.len(), 2);
362        assert!(list.get(0).expect("element 0 should exist").as_bool());
363        assert!(!list.get(1).expect("element 1 should exist").as_bool());
364
365        let float_array = vec![9.9f64, -2.5f64];
366        let v = float_array.to_value();
367        assert_eq!(v.kind(), Kind::List);
368        let list = v.as_list();
369        assert_eq!(list.len(), 2);
370        assert_eq!(list.get(0).expect("element 0 should exist").as_f64(), 9.9);
371        assert_eq!(list.get(1).expect("element 1 should exist").as_f64(), -2.5);
372
373        let empty_array: Vec<f64> = vec![];
374        let v = empty_array.to_value();
375        assert_eq!(v.kind(), Kind::List);
376        assert_eq!(v.as_list().len(), 0);
377
378        let null_array: Option<Vec<i64>> = None;
379        let v = null_array.to_value();
380        assert_eq!(v.kind(), Kind::Null);
381
382        let opt_array: Vec<Option<i64>> = vec![Some(42), None, Some(100)];
383        let v = opt_array.to_value();
384        assert_eq!(v.kind(), Kind::List);
385        let list = v.as_list();
386        assert_eq!(list.len(), 3);
387        assert_eq!(
388            list.get(0).expect("element 0 should exist").as_string(),
389            "42"
390        );
391        assert_eq!(
392            list.get(1).expect("element 1 should exist").kind(),
393            Kind::Null
394        );
395        assert_eq!(
396            list.get(2).expect("element 2 should exist").as_string(),
397            "100"
398        );
399    }
400}