Google Cloud Spanner C++ Client 2.13.0
A C++ Client Library for Google Cloud Spanner
Loading...
Searching...
No Matches
value.h
1// Copyright 2019 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
15#ifndef GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_SPANNER_VALUE_H
16#define GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_SPANNER_VALUE_H
17
18#include "google/cloud/spanner/bytes.h"
19#include "google/cloud/spanner/date.h"
20#include "google/cloud/spanner/internal/tuple_utils.h"
21#include "google/cloud/spanner/json.h"
22#include "google/cloud/spanner/numeric.h"
23#include "google/cloud/spanner/timestamp.h"
24#include "google/cloud/spanner/version.h"
25#include "google/cloud/internal/throw_delegate.h"
26#include "google/cloud/optional.h"
27#include "google/cloud/status_or.h"
28#include "absl/time/civil_time.h"
29#include "absl/types/optional.h"
30#include <google/protobuf/struct.pb.h>
31#include <google/protobuf/util/message_differencer.h>
32#include <google/spanner/v1/type.pb.h>
33#include <ostream>
34#include <string>
35#include <tuple>
36#include <type_traits>
37#include <utility>
38#include <vector>
39
40namespace google {
41namespace cloud {
42namespace spanner_internal {
43GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN
44struct ValueInternals;
45GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END
46} // namespace spanner_internal
47
48namespace spanner {
49GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN
50
51/**
52 * The Value class represents a type-safe, nullable Spanner value.
53 *
54 * It is conceptually similar to a `std::any` except the only allowed types are
55 * those supported by Spanner, and a "null" value (similar to a `std::any`
56 * without a value) still has an associated type. The supported types are shown
57 * in the following table along with how they map to the Spanner types
58 * (https://cloud.google.com/spanner/docs/data-types):
59 *
60 * Spanner Type | C++ Type `T`
61 * ------------ | ------------
62 * BOOL | `bool`
63 * INT64 | `std::int64_t`
64 * FLOAT64 | `double`
65 * STRING | `std::string`
66 * BYTES | `google::cloud::spanner::Bytes`
67 * JSON | `google::cloud::spanner::Json`
68 * JSONB | `google::cloud::spanner::JsonB`
69 * NUMERIC | `google::cloud::spanner::Numeric`
70 * NUMERIC(PG) | `google::cloud::spanner::PgNumeric`
71 * TIMESTAMP | `google::cloud::spanner::Timestamp`
72 * DATE | `absl::CivilDay`
73 * ARRAY | `std::vector<T>` // [1]
74 * STRUCT | `std::tuple<Ts...>`
75 *
76 * [1] The type `T` may be any of the other supported types, except for
77 * ARRAY/`std::vector`.
78 *
79 * Value is a regular C++ value type with support for copy, move, equality,
80 * etc. A default-constructed Value represents an empty value with no type.
81 *
82 * @note There is also a C++ type of `CommitTimestamp` that corresponds to a
83 * Cloud Spanner TIMESTAMP object for setting the commit timestamp on a
84 * column with the `allow_commit_timestamp` set to `true` in the schema.
85 *
86 * @see https://cloud.google.com/spanner/docs/commit-timestamp
87 *
88 * Callers may create instances by passing any of the supported values
89 * (shown in the table above) to the constructor. "Null" values are created
90 * using the `MakeNullValue<T>()` factory function or by passing an empty
91 * `absl::optional<T>` to the Value constructor..
92 *
93 * @par Example
94 * Using a non-null value.
95 * @code
96 * std::string msg = "hello";
97 * spanner::Value v(msg);
98 * StatusOr<std::string> copy = v.get<std::string>();
99 * if (copy) {
100 * std::cout << *copy; // prints "hello"
101 * }
102 * @endcode
103 *
104 * @par Example
105 * Using a null value.
106 * @code
107 * spanner::Value v = spanner::MakeNullValue<std::int64_t>();
108 * StatusOr<std::int64_t> i = v.get<std::int64_t>();
109 * assert(!i.ok()); // Can't get the value because v is null
110 * StatusOr < absl::optional<std::int64_t> j =
111 * v.get<absl::optional<std::int64_t>>();
112 * assert(j.ok()); // OK because an empty option can represent the null
113 * assert(!j->has_value()); // v held no value.
114 * @endcode
115 *
116 * @par Nullness
117 *
118 * All of the supported types (above) are "nullable". A null is created in one
119 * of two ways:
120 *
121 * 1. Passing an `absl::optional<T>()` with no value to `Value`'s constructor.
122 * 2. Using the `MakeNullValue<T>()` helper function (defined below).
123 *
124 * Nulls can be retrieved from a `Value::get<T>` by specifying the type `T`
125 * as an `absl::optional<U>`. The returned optional will either be empty
126 * (indicating null) or it will contain the actual value. See the documentation
127 * for `Value::get<T>` below for more details.
128 *
129 * @par Spanner Arrays
130 *
131 * Spanner arrays are represented in C++ as a `std::vector<T>`, where the type
132 * `T` may be any of the other allowed Spanner types, such as `bool`,
133 * `std::int64_t`, etc. The only exception is that arrays may not directly
134 * contain another array; to achieve a similar result you could create an array
135 * of a 1-element struct holding an array. The following examples show usage of
136 * arrays.
137 *
138 * @code
139 * std::vector<std::int64_t> vec = {1, 2, 3, 4, 5};
140 * spanner::Value v(vec);
141 * auto copy = *v.get<std::vector<std::int64_t>>();
142 * assert(vec == copy);
143 * @endcode
144 *
145 * @par Spanner Structs
146 *
147 * Spanner structs are represented in C++ as instances of `std::tuple` holding
148 * zero or more of the allowed Spanner types, such as `bool`, `std::int64_t`,
149 * `std::vector`, and even other `std::tuple` objects. Each tuple element
150 * corresponds to a single field in a Spanner STRUCT.
151 *
152 * Spanner STRUCT fields may optionally contain a string indicating the field's
153 * name. Fields names may be empty, unique, or repeated. A named field may be
154 * specified as a tuple element of type `std::pair<std::string, T>`, where the
155 * pair's `.first` member indicates the field's name, and the `.second` member
156 * is any valid Spanner type `T`.
157 *
158 * @code
159 * using Struct = std::tuple<bool, std::pair<std::string, std::int64_t>>;
160 * Struct s = {true, {"Foo", 42}};
161 * spanner::Value v(s);
162 * assert(s == *v.get<Struct>());
163 * @endcode
164 *
165 * @note While a STRUCT's (optional) field names are not part of its C++ type,
166 * they are part of its Spanner STRUCT type. Array's (i.e., `std::vector`)
167 * must contain a single element type, therefore it is an error to construct
168 * a `std::vector` of `std::tuple` objects with differently named fields.
169 */
170class Value {
171 public:
172 /**
173 * Constructs a `Value` that holds nothing.
174 *
175 * All calls to `get<T>()` will return an error.
176 */
177 Value() = default;
178
179 // Copy and move.
180 Value(Value const&) = default;
181 Value(Value&&) = default;
182 Value& operator=(Value const&) = default;
183 Value& operator=(Value&&) = default;
184
185 /// Constructs an instance with the specified type and value.
186 explicit Value(bool v) : Value(PrivateConstructor{}, v) {}
187 /// @copydoc Value(bool)
188 explicit Value(std::int64_t v) : Value(PrivateConstructor{}, v) {}
189 /// @copydoc Value(bool)
190 explicit Value(double v) : Value(PrivateConstructor{}, v) {}
191 /// @copydoc Value(bool)
192 explicit Value(std::string v) : Value(PrivateConstructor{}, std::move(v)) {}
193 /// @copydoc Value(bool)
194 explicit Value(Bytes v) : Value(PrivateConstructor{}, std::move(v)) {}
195 /// @copydoc Value(bool)
196 explicit Value(Json v) : Value(PrivateConstructor{}, std::move(v)) {}
197 /// @copydoc Value(bool)
198 explicit Value(JsonB v) : Value(PrivateConstructor{}, std::move(v)) {}
199 /// @copydoc Value(bool)
200 explicit Value(Numeric v) : Value(PrivateConstructor{}, std::move(v)) {}
201 /// @copydoc Value(bool)
202 explicit Value(PgNumeric v) : Value(PrivateConstructor{}, std::move(v)) {}
203 /// @copydoc Value(bool)
204 explicit Value(Timestamp v) : Value(PrivateConstructor{}, std::move(v)) {}
205 /// @copydoc Value(bool)
206 explicit Value(CommitTimestamp v)
207 : Value(PrivateConstructor{}, std::move(v)) {}
208 /// @copydoc Value(bool)
209 explicit Value(absl::CivilDay v)
210 : Value(PrivateConstructor{}, std::move(v)) {}
211
212 /**
213 * Constructs an instance from common C++ literal types that closely, though
214 * not exactly, match supported Spanner types.
215 *
216 * An integer literal in C++ is of type `int`, which is not exactly an
217 * allowed Spanner type. This will be allowed but it will be implicitly up
218 * converted to a `std::int64_t`. Similarly, a C++ string literal will be
219 * implicitly converted to a `std::string`. For example:
220 *
221 * @code
222 * spanner::Value v1(42);
223 * assert(42 == *v1.get<std::int64_t>());
224 *
225 * spanner::Value v2("hello");
226 * assert("hello" == *v2.get<std::string>());
227 * @endcode
228 */
229 explicit Value(int v) : Value(PrivateConstructor{}, v) {}
230 /// @copydoc Value(int)
231 explicit Value(char const* v) : Value(PrivateConstructor{}, v) {}
232
233 /**
234 * Constructs a non-null instance if `opt` has a value, otherwise constructs
235 * a null instance with the specified type `T`.
236 */
237 template <typename T>
238 explicit Value(absl::optional<T> opt)
239 : Value(PrivateConstructor{}, std::move(opt)) {}
240
241 /**
242 * Constructs an instance from a Spanner ARRAY of the specified type and
243 * values.
244 *
245 * The type `T` may be any valid type shown above, except vectors of vectors
246 * are not allowed.
247 *
248 * @warning If `T` is a `std::tuple` with field names (i.e., at least one of
249 * its element types is a `std::pair<std::string, T>`) then, all of the
250 * vector's elements must have exactly the same field names. Any mismatch
251 * in in field names results in undefined behavior.
252 */
253 template <typename T>
254 explicit Value(std::vector<T> v) : Value(PrivateConstructor{}, std::move(v)) {
255 static_assert(!IsVector<typename std::decay<T>::type>::value,
256 "vector of vector not allowed. See value.h documentation.");
257 }
258
259 /**
260 * Constructs an instance from a Spanner STRUCT with a type and values
261 * matching the given `std::tuple`.
262 *
263 * Any STRUCT field may optionally have a name, which is specified as
264 * `std::pair<std::string, T>`.
265 */
266 template <typename... Ts>
267 explicit Value(std::tuple<Ts...> tup)
268 : Value(PrivateConstructor{}, std::move(tup)) {}
269
270 friend bool operator==(Value const& a, Value const& b);
271 friend bool operator!=(Value const& a, Value const& b) { return !(a == b); }
272
273 /**
274 * Returns the contained value wrapped in a `google::cloud::StatusOr<T>`.
275 *
276 * Returns a non-OK status IFF:
277 *
278 * * The contained value is "null", and `T` is not an `absl::optional`.
279 * * There is an error converting the contained value to `T`.
280 *
281 * @par Example
282 *
283 * @code
284 * spanner::Value v{3.14};
285 * StatusOr<double> d = v.get<double>();
286 * if (d) {
287 * std::cout << "d=" << *d;
288 * }
289 *
290 * // Now using a "null" std::int64_t
291 * v = spanner::MakeNullValue<std::int64_t>();
292 * StatusOr<std::int64_t> i = v.get<std::int64_t>();
293 * if (!i) {
294 * std::cerr << "Could not get integer: " << i.status();
295 * }
296 * StatusOr<absl::optional<std::int64_t>> j =
297 * v.get<absl::optional<std::int64_t>>();
298 * assert(j.ok()); // Since we know the types match in this example
299 * assert(!v->has_value()); // Since we know v was null in this example
300 * @endcode
301 */
302 template <typename T>
303 StatusOr<T> get() const& {
304 if (!TypeProtoIs(T{}, type_))
305 return Status(StatusCode::kUnknown, "wrong type");
306 if (value_.kind_case() == google::protobuf::Value::kNullValue) {
307 if (IsOptional<T>::value) return T{};
308 return Status(StatusCode::kUnknown, "null value");
309 }
310 return GetValue(T{}, value_, type_);
311 }
312
313 /// @copydoc get()
314 template <typename T>
315 StatusOr<T> get() && {
316 if (!TypeProtoIs(T{}, type_))
317 return Status(StatusCode::kUnknown, "wrong type");
318 if (value_.kind_case() == google::protobuf::Value::kNullValue) {
319 if (IsOptional<T>::value) return T{};
320 return Status(StatusCode::kUnknown, "null value");
321 }
322 auto tag = T{}; // Works around an odd msvc issue
323 return GetValue(std::move(tag), std::move(value_), type_);
324 }
325
326 /**
327 * Outputs string representation of a given Value to the provided stream.
328 *
329 * @warning This is intended for debugging and human consumption only, not
330 * machine consumption, as the output format may change without notice.
331 *
332 * @par Example:
333 * @code
334 * spanner::Value v{42};
335 * std::cout << v << "\n";
336 * @endcode
337 */
338 friend std::ostream& operator<<(std::ostream& os, Value const& v);
339
340 /**
341 * Prints the same output as `operator<<`.
342 *
343 * @warning DO NOT CALL. This function will be removed in a future release.
344 * Use `operator<<` instead.
345 */
346 friend void PrintTo(Value const& v, std::ostream* os) { *os << v; }
347
348 private:
349 // Metafunction that returns true if `T` is an `absl::optional<U>`
350 template <typename T>
351 struct IsOptional : std::false_type {};
352 template <typename T>
353 struct IsOptional<absl::optional<T>> : std::true_type {};
354
355 // Metafunction that returns true if `T` is a std::vector<U>
356 template <typename T>
357 struct IsVector : std::false_type {};
358 template <typename... Ts>
359 struct IsVector<std::vector<Ts...>> : std::true_type {};
360
361 // Tag-dispatch overloads to check if a C++ type matches the type specified
362 // by the given `Type` proto.
363 static bool TypeProtoIs(bool, google::spanner::v1::Type const&);
364 static bool TypeProtoIs(std::int64_t, google::spanner::v1::Type const&);
365 static bool TypeProtoIs(double, google::spanner::v1::Type const&);
366 static bool TypeProtoIs(Timestamp, google::spanner::v1::Type const&);
367 static bool TypeProtoIs(CommitTimestamp, google::spanner::v1::Type const&);
368 static bool TypeProtoIs(absl::CivilDay, google::spanner::v1::Type const&);
369 static bool TypeProtoIs(std::string const&, google::spanner::v1::Type const&);
370 static bool TypeProtoIs(Bytes const&, google::spanner::v1::Type const&);
371 static bool TypeProtoIs(Json const&, google::spanner::v1::Type const&);
372 static bool TypeProtoIs(JsonB const&, google::spanner::v1::Type const&);
373 static bool TypeProtoIs(Numeric const&, google::spanner::v1::Type const&);
374 static bool TypeProtoIs(PgNumeric const&, google::spanner::v1::Type const&);
375 template <typename T>
376 static bool TypeProtoIs(absl::optional<T>,
377 google::spanner::v1::Type const& type) {
378 return TypeProtoIs(T{}, type);
379 }
380 template <typename T>
381 static bool TypeProtoIs(std::vector<T> const&,
382 google::spanner::v1::Type const& type) {
383 return type.code() == google::spanner::v1::TypeCode::ARRAY &&
384 TypeProtoIs(T{}, type.array_element_type());
385 }
386 template <typename... Ts>
387 static bool TypeProtoIs(std::tuple<Ts...> const& tup,
388 google::spanner::v1::Type const& type) {
389 bool ok = type.code() == google::spanner::v1::TypeCode::STRUCT;
390 ok = ok && type.struct_type().fields().size() == sizeof...(Ts);
391 spanner_internal::ForEach(tup, IsStructTypeProto{ok, 0},
392 type.struct_type());
393 return ok;
394 }
395
396 // A functor to be used with internal::ForEach to check if a StructType proto
397 // matches the types in a std::tuple.
398 struct IsStructTypeProto {
399 bool& ok;
400 int field;
401 template <typename T>
402 void operator()(T const&, google::spanner::v1::StructType const& type) {
403 ok = ok && TypeProtoIs(T{}, type.fields(field).type());
404 ++field;
405 }
406 template <typename T>
407 void operator()(std::pair<std::string, T> const&,
408 google::spanner::v1::StructType const& type) {
409 operator()(T{}, type);
410 }
411 };
412
413 // Tag-dispatch overloads to convert a C++ type to a `Type` protobuf. The
414 // argument type is the tag, the argument value is ignored.
415 static google::spanner::v1::Type MakeTypeProto(bool);
416 static google::spanner::v1::Type MakeTypeProto(std::int64_t);
417 static google::spanner::v1::Type MakeTypeProto(double);
418 static google::spanner::v1::Type MakeTypeProto(std::string const&);
419 static google::spanner::v1::Type MakeTypeProto(Bytes const&);
420 static google::spanner::v1::Type MakeTypeProto(Json const&);
421 static google::spanner::v1::Type MakeTypeProto(JsonB const&);
422 static google::spanner::v1::Type MakeTypeProto(Numeric const&);
423 static google::spanner::v1::Type MakeTypeProto(PgNumeric const&);
424 static google::spanner::v1::Type MakeTypeProto(Timestamp);
425 static google::spanner::v1::Type MakeTypeProto(CommitTimestamp);
426 static google::spanner::v1::Type MakeTypeProto(absl::CivilDay);
427 static google::spanner::v1::Type MakeTypeProto(int);
428 static google::spanner::v1::Type MakeTypeProto(char const*);
429 template <typename T>
430 static google::spanner::v1::Type MakeTypeProto(absl::optional<T> const&) {
431 return MakeTypeProto(T{});
432 }
433 template <typename T>
434 static google::spanner::v1::Type MakeTypeProto(std::vector<T> const& v) {
435 google::spanner::v1::Type t;
436 t.set_code(google::spanner::v1::TypeCode::ARRAY);
437 *t.mutable_array_element_type() = MakeTypeProto(v.empty() ? T{} : v[0]);
438 // Checks that vector elements have exactly the same proto Type, which
439 // includes field names. This is documented UB.
440 for (auto&& e : v) {
441 if (!google::protobuf::util::MessageDifferencer::Equals(
442 MakeTypeProto(e), t.array_element_type())) {
443 google::cloud::internal::ThrowInvalidArgument("Mismatched types");
444 }
445 }
446 return t;
447 }
448 template <typename... Ts>
449 static google::spanner::v1::Type MakeTypeProto(std::tuple<Ts...> const& tup) {
450 google::spanner::v1::Type t;
451 t.set_code(google::spanner::v1::TypeCode::STRUCT);
452 spanner_internal::ForEach(tup, AddStructTypes{}, *t.mutable_struct_type());
453 return t;
454 }
455
456 // A functor to be used with internal::ForEach to add type protos for all the
457 // elements of a tuple.
458 struct AddStructTypes {
459 template <typename T>
460 void operator()(T const& t,
461 google::spanner::v1::StructType& struct_type) const {
462 auto* field = struct_type.add_fields();
463 *field->mutable_type() = MakeTypeProto(t);
464 }
465 template <typename S, typename T,
466 typename std::enable_if<
467 std::is_convertible<S, std::string>::value, int>::type = 0>
468 void operator()(std::pair<S, T> const& p,
469 google::spanner::v1::StructType& struct_type) const {
470 auto* field = struct_type.add_fields();
471 field->set_name(p.first);
472 *field->mutable_type() = MakeTypeProto(p.second);
473 }
474 };
475
476 // Encodes the argument as a protobuf according to the rules described in
477 // https://github.com/googleapis/googleapis/blob/master/google/spanner/v1/type.proto
478 static google::protobuf::Value MakeValueProto(bool b);
479 static google::protobuf::Value MakeValueProto(std::int64_t i);
480 static google::protobuf::Value MakeValueProto(double d);
481 static google::protobuf::Value MakeValueProto(std::string s);
482 static google::protobuf::Value MakeValueProto(Bytes b);
483 static google::protobuf::Value MakeValueProto(Json j);
484 static google::protobuf::Value MakeValueProto(JsonB j);
485 static google::protobuf::Value MakeValueProto(Numeric n);
486 static google::protobuf::Value MakeValueProto(PgNumeric n);
487 static google::protobuf::Value MakeValueProto(Timestamp ts);
488 static google::protobuf::Value MakeValueProto(CommitTimestamp ts);
489 static google::protobuf::Value MakeValueProto(absl::CivilDay d);
490 static google::protobuf::Value MakeValueProto(int i);
491 static google::protobuf::Value MakeValueProto(char const* s);
492 template <typename T>
493 static google::protobuf::Value MakeValueProto(absl::optional<T> opt) {
494 if (opt.has_value()) return MakeValueProto(*std::move(opt));
495 google::protobuf::Value v;
496 v.set_null_value(google::protobuf::NullValue::NULL_VALUE);
497 return v;
498 }
499 template <typename T>
500 static google::protobuf::Value MakeValueProto(std::vector<T> vec) {
501 google::protobuf::Value v;
502 auto& list = *v.mutable_list_value();
503 for (auto&& e : vec) {
504 *list.add_values() = MakeValueProto(std::move(e));
505 }
506 return v;
507 }
508 template <typename... Ts>
509 static google::protobuf::Value MakeValueProto(std::tuple<Ts...> tup) {
510 google::protobuf::Value v;
511 spanner_internal::ForEach(tup, AddStructValues{}, *v.mutable_list_value());
512 return v;
513 }
514
515 // A functor to be used with internal::ForEach to add Value protos for all
516 // the elements of a tuple.
517 struct AddStructValues {
518 template <typename T>
519 void operator()(T& t, google::protobuf::ListValue& list_value) const {
520 *list_value.add_values() = MakeValueProto(std::move(t));
521 }
522 template <typename S, typename T,
523 typename std::enable_if<
524 std::is_convertible<S, std::string>::value, int>::type = 0>
525 void operator()(std::pair<S, T> p,
526 google::protobuf::ListValue& list_value) const {
527 *list_value.add_values() = MakeValueProto(std::move(p.second));
528 }
529 };
530
531 // Tag-dispatch overloads to extract a C++ value from a `Value` protobuf. The
532 // first argument type is the tag, its value is ignored.
533 static StatusOr<bool> GetValue(bool, google::protobuf::Value const&,
534 google::spanner::v1::Type const&);
535 static StatusOr<std::int64_t> GetValue(std::int64_t,
536 google::protobuf::Value const&,
537 google::spanner::v1::Type const&);
538 static StatusOr<double> GetValue(double, google::protobuf::Value const&,
539 google::spanner::v1::Type const&);
540 static StatusOr<std::string> GetValue(std::string const&,
541 google::protobuf::Value const&,
542 google::spanner::v1::Type const&);
543 static StatusOr<std::string> GetValue(std::string const&,
544 google::protobuf::Value&&,
545 google::spanner::v1::Type const&);
546 static StatusOr<Bytes> GetValue(Bytes const&, google::protobuf::Value const&,
547 google::spanner::v1::Type const&);
548 static StatusOr<Json> GetValue(Json const&, google::protobuf::Value const&,
549 google::spanner::v1::Type const&);
550 static StatusOr<JsonB> GetValue(JsonB const&, google::protobuf::Value const&,
551 google::spanner::v1::Type const&);
552 static StatusOr<Numeric> GetValue(Numeric const&,
553 google::protobuf::Value const&,
554 google::spanner::v1::Type const&);
555 static StatusOr<PgNumeric> GetValue(PgNumeric const&,
556 google::protobuf::Value const&,
557 google::spanner::v1::Type const&);
558 static StatusOr<Timestamp> GetValue(Timestamp, google::protobuf::Value const&,
559 google::spanner::v1::Type const&);
560 static StatusOr<CommitTimestamp> GetValue(CommitTimestamp,
561 google::protobuf::Value const&,
562 google::spanner::v1::Type const&);
563 static StatusOr<absl::CivilDay> GetValue(absl::CivilDay,
564 google::protobuf::Value const&,
565 google::spanner::v1::Type const&);
566 template <typename T, typename V>
567 static StatusOr<absl::optional<T>> GetValue(
568 absl::optional<T> const&, V&& pv, google::spanner::v1::Type const& pt) {
569 if (pv.kind_case() == google::protobuf::Value::kNullValue) {
570 return absl::optional<T>{};
571 }
572 auto value = GetValue(T{}, std::forward<V>(pv), pt);
573 if (!value) return std::move(value).status();
574 return absl::optional<T>{*std::move(value)};
575 }
576 template <typename T, typename V>
577 static StatusOr<std::vector<T>> GetValue(
578 std::vector<T> const&, V&& pv, google::spanner::v1::Type const& pt) {
579 if (pv.kind_case() != google::protobuf::Value::kListValue) {
580 return Status(StatusCode::kUnknown, "missing ARRAY");
581 }
582 std::vector<T> v;
583 for (int i = 0; i < pv.list_value().values().size(); ++i) {
584 auto&& e = GetProtoListValueElement(std::forward<V>(pv), i);
585 using ET = decltype(e);
586 auto value = GetValue(T{}, std::forward<ET>(e), pt.array_element_type());
587 if (!value) return std::move(value).status();
588 v.push_back(*std::move(value));
589 }
590 return v;
591 }
592 template <typename V, typename... Ts>
593 static StatusOr<std::tuple<Ts...>> GetValue(
594 std::tuple<Ts...> const&, V&& pv, google::spanner::v1::Type const& pt) {
595 if (pv.kind_case() != google::protobuf::Value::kListValue) {
596 return Status(StatusCode::kUnknown, "missing STRUCT");
597 }
598 std::tuple<Ts...> tup;
599 Status status; // OK
600 ExtractTupleValues<V> f{status, 0, std::forward<V>(pv), pt};
601 spanner_internal::ForEach(tup, f);
602 if (!status.ok()) return status;
603 return tup;
604 }
605
606 // A functor to be used with internal::ForEach to extract C++ types from a
607 // ListValue proto and store then in a tuple.
608 template <typename V>
609 struct ExtractTupleValues {
610 Status& status;
611 int i;
612 V&& pv;
613 google::spanner::v1::Type const& type;
614 template <typename T>
615 void operator()(T& t) {
616 auto&& e = GetProtoListValueElement(std::forward<V>(pv), i);
617 using ET = decltype(e);
618 auto value = GetValue(T{}, std::forward<ET>(e), type);
619 ++i;
620 if (!value) {
621 status = std::move(value).status();
622 } else {
623 t = *std::move(value);
624 }
625 }
626 template <typename T>
627 void operator()(std::pair<std::string, T>& p) {
628 p.first = type.struct_type().fields(i).name();
629 auto&& e = GetProtoListValueElement(std::forward<V>(pv), i);
630 using ET = decltype(e);
631 auto value = GetValue(T{}, std::forward<ET>(e), type);
632 ++i;
633 if (!value) {
634 status = std::move(value).status();
635 } else {
636 p.second = *std::move(value);
637 }
638 }
639 };
640
641 // Protocol buffers are not friendly to generic programming, because they use
642 // different syntax and different names for mutable and non-mutable
643 // functions. To make GetValue(vector<T>, ...) (above) work, we need split
644 // the different protobuf syntaxes into overloaded functions.
645 static google::protobuf::Value const& GetProtoListValueElement(
646 google::protobuf::Value const& pv, int pos) {
647 return pv.list_value().values(pos);
648 }
649 static google::protobuf::Value&& GetProtoListValueElement(
650 google::protobuf::Value&& pv, int pos) {
651 return std::move(*pv.mutable_list_value()->mutable_values(pos));
652 }
653
654 // A private templated constructor that is called by all the public
655 // constructors to set the type_ and value_ members. The `PrivateConstructor`
656 // type is used so that this overload is never chosen for
657 // non-member/non-friend callers. Otherwise, since visibility restrictions
658 // apply after overload resolution, users could get weird error messages if
659 // this constructor matched their arguments best.
660 struct PrivateConstructor {};
661 template <typename T>
662 Value(PrivateConstructor, T&& t)
663 : type_(MakeTypeProto(t)), value_(MakeValueProto(std::forward<T>(t))) {}
664
665 Value(google::spanner::v1::Type t, google::protobuf::Value v)
666 : type_(std::move(t)), value_(std::move(v)) {}
667
668 friend struct spanner_internal::ValueInternals;
669
670 google::spanner::v1::Type type_;
671 google::protobuf::Value value_;
672};
673
674/**
675 * Factory to construct a "null" Value of the specified type `T`.
676 *
677 * This is equivalent to passing an `absl::optional<T>` without a value to
678 * the constructor, though this factory may be easier to invoke and result
679 * in clearer code at the call site.
680 */
681template <typename T>
683 return Value(absl::optional<T>{});
684}
685
686GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END
687} // namespace spanner
688
689namespace spanner_internal {
690GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN
691
692struct ValueInternals {
693 static spanner::Value FromProto(google::spanner::v1::Type t,
694 google::protobuf::Value v) {
695 return spanner::Value(std::move(t), std::move(v));
696 }
697
698 static std::pair<google::spanner::v1::Type, google::protobuf::Value> ToProto(
699 spanner::Value v) {
700 return std::make_pair(std::move(v.type_), std::move(v.value_));
701 }
702};
703
704inline spanner::Value FromProto(google::spanner::v1::Type t,
705 google::protobuf::Value v) {
706 return ValueInternals::FromProto(std::move(t), std::move(v));
707}
708
709inline std::pair<google::spanner::v1::Type, google::protobuf::Value> ToProto(
710 spanner::Value v) {
711 return ValueInternals::ToProto(std::move(v));
712}
713
714GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END
715} // namespace spanner_internal
716} // namespace cloud
717} // namespace google
718
719#endif // GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_SPANNER_VALUE_H
Status(StatusCode code, std::string message, ErrorInfo info={})
A representation of the Spanner BYTES type: variable-length binary data.
Definition: bytes.h:43
JsonB is a variant of Json (see above).
Definition: json.h:101
A simple representation for the Spanner JSON type: a lightweight, text-based, language-independent da...
Definition: json.h:39
A representation of the Spanner TIMESTAMP type: An instant in time.
Definition: timestamp.h:54
The Value class represents a type-safe, nullable Spanner value.
Definition: value.h:170
friend void PrintTo(Value const &v, std::ostream *os)
Prints the same output as operator<<.
Definition: value.h:346
Value & operator=(Value const &)=default
Value(Numeric v)
Constructs an instance with the specified type and value.
Definition: value.h:200
Value(Value const &)=default
Value(absl::CivilDay v)
Constructs an instance with the specified type and value.
Definition: value.h:209
Value(CommitTimestamp v)
Constructs an instance with the specified type and value.
Definition: value.h:206
Value(bool v)
Constructs an instance with the specified type and value.
Definition: value.h:186
Value & operator=(Value &&)=default
Value(PgNumeric v)
Constructs an instance with the specified type and value.
Definition: value.h:202
Value(JsonB v)
Constructs an instance with the specified type and value.
Definition: value.h:198
friend bool operator!=(Value const &a, Value const &b)
Definition: value.h:271
Value(std::vector< T > v)
Constructs an instance from a Spanner ARRAY of the specified type and values.
Definition: value.h:254
Value(Timestamp v)
Constructs an instance with the specified type and value.
Definition: value.h:204
Value(Bytes v)
Constructs an instance with the specified type and value.
Definition: value.h:194
Value(double v)
Constructs an instance with the specified type and value.
Definition: value.h:190
StatusOr< T > get() const &
Returns the contained value wrapped in a google::cloud::StatusOr<T>.
Definition: value.h:303
Value(char const *v)
Constructs an instance from common C++ literal types that closely, though not exactly,...
Definition: value.h:231
Value(std::tuple< Ts... > tup)
Constructs an instance from a Spanner STRUCT with a type and values matching the given std::tuple.
Definition: value.h:267
Value(std::string v)
Constructs an instance with the specified type and value.
Definition: value.h:192
StatusOr< T > get() &&
Returns the contained value wrapped in a google::cloud::StatusOr<T>.
Definition: value.h:315
Value(int v)
Constructs an instance from common C++ literal types that closely, though not exactly,...
Definition: value.h:229
Value(std::int64_t v)
Constructs an instance with the specified type and value.
Definition: value.h:188
friend bool operator==(Value const &a, Value const &b)
Value(Json v)
Constructs an instance with the specified type and value.
Definition: value.h:196
Value(absl::optional< T > opt)
Constructs a non-null instance if opt has a value, otherwise constructs a null instance with the spec...
Definition: value.h:238
Value()=default
Constructs a Value that holds nothing.
Contains all the Cloud Spanner C++ client types and functions.
Definition: backoff_policy.h:23
Value MakeNullValue()
Factory to construct a "null" Value of the specified type T.
Definition: value.h:682
A sentinel type used to update a commit timestamp column.
Definition: timestamp.h:195