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