15 #ifndef GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_SPANNER_VALUE_H 16 #define GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_SPANNER_VALUE_H 20 #include "google/cloud/spanner/internal/tuple_utils.h" 23 #include "google/cloud/internal/throw_delegate.h" 26 #include <google/protobuf/struct.pb.h> 27 #include <google/protobuf/util/message_differencer.h> 28 #include <google/spanner/v1/type.pb.h> 32 #include <type_traits> 44 Value FromProto(google::spanner::v1::Type t, google::protobuf::Value v);
45 std::pair<google::spanner::v1::Type, google::protobuf::Value> ToProto(Value v);
180 explicit Value(std::int64_t v) :
Value(PrivateConstructor{}, v) {}
184 explicit Value(std::string v) :
Value(PrivateConstructor{}, std::move(v)) {}
191 :
Value(PrivateConstructor{}, std::move(v)) {}
214 explicit Value(
char const* v) :
Value(PrivateConstructor{}, v) {}
220 template <
typename T>
222 :
Value(PrivateConstructor{}, std::move(opt)) {}
236 template <
typename T>
237 explicit Value(std::vector<T> v) :
Value(PrivateConstructor{}, std::move(v)) {
238 static_assert(!IsVector<
typename std::decay<T>::type>::value,
239 "vector of vector not allowed. See value.h documentation.");
249 template <
typename... Ts>
250 explicit Value(std::tuple<Ts...> tup)
251 :
Value(PrivateConstructor{}, std::move(tup)) {}
253 friend bool operator==(Value
const& a, Value
const& b);
285 template <
typename T>
286 StatusOr<T>
get() const& {
287 if (!TypeProtoIs(T{}, type_))
288 return Status(StatusCode::kUnknown,
"wrong type");
289 if (value_.kind_case() == google::protobuf::Value::kNullValue) {
290 if (IsOptional<T>::value)
return T{};
291 return Status(StatusCode::kUnknown,
"null value");
293 return GetValue(T{}, value_, type_);
297 template <
typename T>
299 if (!TypeProtoIs(T{}, type_))
300 return Status(StatusCode::kUnknown,
"wrong type");
301 if (value_.kind_case() == google::protobuf::Value::kNullValue) {
302 if (IsOptional<T>::value)
return T{};
303 return Status(StatusCode::kUnknown,
"null value");
306 return GetValue(std::move(tag), std::move(value_), type_);
333 template <
typename T>
334 struct IsOptional : std::false_type {};
335 template <
typename T>
336 struct IsOptional<optional<T>> : std::true_type {};
339 template <
typename T>
340 struct IsVector : std::false_type {};
341 template <
typename... Ts>
342 struct IsVector<std::vector<Ts...>> : std::true_type {};
346 static bool TypeProtoIs(
bool, google::spanner::v1::Type
const&);
347 static bool TypeProtoIs(std::int64_t, google::spanner::v1::Type
const&);
348 static bool TypeProtoIs(
double, google::spanner::v1::Type
const&);
349 static bool TypeProtoIs(Timestamp, google::spanner::v1::Type
const&);
350 static bool TypeProtoIs(CommitTimestamp, google::spanner::v1::Type
const&);
351 static bool TypeProtoIs(Date, google::spanner::v1::Type
const&);
352 static bool TypeProtoIs(std::string
const&, google::spanner::v1::Type
const&);
353 static bool TypeProtoIs(Bytes
const&, google::spanner::v1::Type
const&);
354 template <
typename T>
355 static bool TypeProtoIs(optional<T>, google::spanner::v1::Type
const& type) {
356 return TypeProtoIs(T{}, type);
358 template <
typename T>
359 static bool TypeProtoIs(std::vector<T>
const&,
360 google::spanner::v1::Type
const& type) {
361 return type.code() == google::spanner::v1::TypeCode::ARRAY &&
362 TypeProtoIs(T{}, type.array_element_type());
364 template <
typename... Ts>
365 static bool TypeProtoIs(std::tuple<Ts...>
const& tup,
366 google::spanner::v1::Type
const& type) {
367 bool ok = type.code() == google::spanner::v1::TypeCode::STRUCT;
368 ok = ok && type.struct_type().fields().size() ==
sizeof...(Ts);
369 internal::ForEach(tup, IsStructTypeProto{ok, 0}, type.struct_type());
375 struct IsStructTypeProto {
378 template <
typename T>
379 void operator()(T
const&, google::spanner::v1::StructType
const& type) {
380 ok = ok && TypeProtoIs(T{}, type.fields(field).type());
383 template <
typename T>
384 void operator()(std::pair<std::string, T>
const&,
385 google::spanner::v1::StructType
const& type) {
386 operator()(T{}, type);
392 static google::spanner::v1::Type MakeTypeProto(
bool);
393 static google::spanner::v1::Type MakeTypeProto(std::int64_t);
394 static google::spanner::v1::Type MakeTypeProto(
double);
395 static google::spanner::v1::Type MakeTypeProto(std::string
const&);
396 static google::spanner::v1::Type MakeTypeProto(Bytes
const&);
397 static google::spanner::v1::Type MakeTypeProto(Timestamp);
398 static google::spanner::v1::Type MakeTypeProto(CommitTimestamp);
399 static google::spanner::v1::Type MakeTypeProto(Date);
400 static google::spanner::v1::Type MakeTypeProto(
int);
401 static google::spanner::v1::Type MakeTypeProto(
char const*);
402 template <
typename T>
403 static google::spanner::v1::Type MakeTypeProto(optional<T>
const&) {
404 return MakeTypeProto(T{});
406 template <
typename T>
407 static google::spanner::v1::Type MakeTypeProto(std::vector<T>
const& v) {
408 google::spanner::v1::Type t;
409 t.set_code(google::spanner::v1::TypeCode::ARRAY);
410 *t.mutable_array_element_type() = MakeTypeProto(v.empty() ? T{} : v[0]);
413 for (
auto const& e : v) {
414 if (!google::protobuf::util::MessageDifferencer::Equals(
415 MakeTypeProto(e), t.array_element_type())) {
416 google::cloud::internal::ThrowInvalidArgument(
"Mismatched types");
421 template <
typename... Ts>
422 static google::spanner::v1::Type MakeTypeProto(std::tuple<Ts...>
const& tup) {
423 google::spanner::v1::Type t;
424 t.set_code(google::spanner::v1::TypeCode::STRUCT);
425 internal::ForEach(tup, AddStructTypes{}, *t.mutable_struct_type());
431 struct AddStructTypes {
432 template <
typename T>
433 void operator()(T
const& t,
434 google::spanner::v1::StructType& struct_type)
const {
435 auto* field = struct_type.add_fields();
436 *field->mutable_type() = MakeTypeProto(t);
438 template <
typename S,
typename T,
439 typename std::enable_if<
440 std::is_convertible<S, std::string>::value,
int>::type = 0>
441 void operator()(std::pair<S, T>
const& p,
442 google::spanner::v1::StructType& struct_type)
const {
443 auto* field = struct_type.add_fields();
444 field->set_name(p.first);
445 *field->mutable_type() = MakeTypeProto(p.second);
451 static google::protobuf::Value MakeValueProto(
bool b);
452 static google::protobuf::Value MakeValueProto(std::int64_t i);
453 static google::protobuf::Value MakeValueProto(
double d);
454 static google::protobuf::Value MakeValueProto(std::string s);
455 static google::protobuf::Value MakeValueProto(Bytes b);
456 static google::protobuf::Value MakeValueProto(Timestamp ts);
457 static google::protobuf::Value MakeValueProto(CommitTimestamp ts);
458 static google::protobuf::Value MakeValueProto(Date d);
459 static google::protobuf::Value MakeValueProto(
int i);
460 static google::protobuf::Value MakeValueProto(
char const* s);
461 template <
typename T>
462 static google::protobuf::Value MakeValueProto(optional<T> opt) {
463 if (opt.has_value())
return MakeValueProto(*std::move(opt));
464 google::protobuf::Value v;
465 v.set_null_value(google::protobuf::NullValue::NULL_VALUE);
468 template <
typename T>
469 static google::protobuf::Value MakeValueProto(std::vector<T> vec) {
470 google::protobuf::Value v;
471 auto& list = *v.mutable_list_value();
472 for (
auto&& e : vec) {
473 *list.add_values() = MakeValueProto(std::move(e));
477 template <
typename... Ts>
478 static google::protobuf::Value MakeValueProto(std::tuple<Ts...> tup) {
479 google::protobuf::Value v;
480 internal::ForEach(tup, AddStructValues{}, *v.mutable_list_value());
486 struct AddStructValues {
487 template <
typename T>
488 void operator()(T& t, google::protobuf::ListValue& list_value)
const {
489 *list_value.add_values() = MakeValueProto(std::move(t));
491 template <
typename S,
typename T,
492 typename std::enable_if<
493 std::is_convertible<S, std::string>::value,
int>::type = 0>
494 void operator()(std::pair<S, T> p,
495 google::protobuf::ListValue& list_value)
const {
496 *list_value.add_values() = MakeValueProto(std::move(p.second));
502 static StatusOr<bool> GetValue(
bool, google::protobuf::Value
const&,
503 google::spanner::v1::Type
const&);
504 static StatusOr<std::int64_t> GetValue(std::int64_t,
505 google::protobuf::Value
const&,
506 google::spanner::v1::Type
const&);
507 static StatusOr<double> GetValue(
double, google::protobuf::Value
const&,
508 google::spanner::v1::Type
const&);
509 static StatusOr<std::string> GetValue(std::string
const&,
510 google::protobuf::Value
const&,
511 google::spanner::v1::Type
const&);
512 static StatusOr<std::string> GetValue(std::string
const&,
513 google::protobuf::Value&&,
514 google::spanner::v1::Type
const&);
515 static StatusOr<Bytes> GetValue(Bytes
const&, google::protobuf::Value
const&,
516 google::spanner::v1::Type
const&);
517 static StatusOr<Timestamp> GetValue(Timestamp, google::protobuf::Value
const&,
518 google::spanner::v1::Type
const&);
519 static StatusOr<CommitTimestamp> GetValue(CommitTimestamp,
520 google::protobuf::Value
const&,
521 google::spanner::v1::Type
const&);
522 static StatusOr<Date> GetValue(Date, google::protobuf::Value
const&,
523 google::spanner::v1::Type
const&);
524 template <
typename T,
typename V>
525 static StatusOr<optional<T>> GetValue(optional<T>
const&, V&& pv,
526 google::spanner::v1::Type
const& pt) {
527 if (pv.kind_case() == google::protobuf::Value::kNullValue) {
528 return optional<T>{};
530 auto value = GetValue(T{}, std::forward<V>(pv), pt);
531 if (!value)
return std::move(value).status();
532 return optional<T>{*std::move(value)};
534 template <
typename T,
typename V>
535 static StatusOr<std::vector<T>> GetValue(
536 std::vector<T>
const&, V&& pv, google::spanner::v1::Type
const& pt) {
537 if (pv.kind_case() != google::protobuf::Value::kListValue) {
538 return Status(StatusCode::kUnknown,
"missing ARRAY");
541 for (
int i = 0; i < pv.list_value().values().size(); ++i) {
542 auto&& e = GetProtoListValueElement(std::forward<V>(pv), i);
543 using ET = decltype(e);
544 auto value = GetValue(T{}, std::forward<ET>(e), pt.array_element_type());
545 if (!value)
return std::move(value).status();
546 v.push_back(*std::move(value));
550 template <
typename V,
typename... Ts>
551 static StatusOr<std::tuple<Ts...>> GetValue(
552 std::tuple<Ts...>
const&, V&& pv, google::spanner::v1::Type
const& pt) {
553 if (pv.kind_case() != google::protobuf::Value::kListValue) {
554 return Status(StatusCode::kUnknown,
"missing STRUCT");
556 std::tuple<Ts...> tup;
558 ExtractTupleValues<V> f{status, 0, std::forward<V>(pv), pt};
559 internal::ForEach(tup, f);
560 if (!status.ok())
return status;
566 template <
typename V>
567 struct ExtractTupleValues {
571 google::spanner::v1::Type
const& type;
572 template <
typename T>
573 void operator()(T& t) {
574 auto&& e = GetProtoListValueElement(std::forward<V>(pv), i);
575 using ET = decltype(e);
576 auto value = GetValue(T{}, std::forward<ET>(e), type);
579 status = std::move(value).status();
581 t = *std::move(value);
584 template <
typename T>
585 void operator()(std::pair<std::string, T>& p) {
586 p.first = type.struct_type().fields(i).name();
587 auto&& e = GetProtoListValueElement(std::forward<V>(pv), i);
588 using ET = decltype(e);
589 auto value = GetValue(T{}, std::forward<ET>(e), type);
592 status = std::move(value).status();
594 p.second = *std::move(value);
603 static google::protobuf::Value
const& GetProtoListValueElement(
604 google::protobuf::Value
const& pv,
int pos) {
605 return pv.list_value().values(pos);
607 static google::protobuf::Value&& GetProtoListValueElement(
608 google::protobuf::Value&& pv,
int pos) {
609 return std::move(*pv.mutable_list_value()->mutable_values(pos));
618 struct PrivateConstructor {};
619 template <
typename T>
620 Value(PrivateConstructor, T&& t)
621 : type_(MakeTypeProto(t)), value_(MakeValueProto(std::forward<T>(t))) {}
623 Value(google::spanner::v1::Type t, google::protobuf::Value v)
624 : type_(std::move(t)), value_(std::move(v)) {}
626 friend Value internal::FromProto(google::spanner::v1::Type,
627 google::protobuf::Value);
628 friend std::pair<google::spanner::v1::Type, google::protobuf::Value>
629 internal::ToProto(Value);
631 google::spanner::v1::Type type_;
632 google::protobuf::Value value_;
642 template <
typename T>
644 return Value(optional<T>{});
652 #endif // GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_SPANNER_VALUE_H Value(std::tuple< Ts... > tup)
Constructs an instance from a Spanner STRUCT with a type and values matching the given std::tuple.
A sentinel type used to update a commit timestamp column.
The Value class represents a type-safe, nullable Spanner value.
Value(int v)
Constructs an instance from common C++ literal types that closely, though not exactly,...
Value(Bytes v)
Constructs an instance with the specified type and value.
Value MakeNullValue()
Factory to construct a "null" Value of the specified type T.
bool operator==(Backup const &a, Backup const &b)
friend void PrintTo(Value const &v, std::ostream *os)
Prints the same output as operator<<.
Value(std::string v)
Constructs an instance with the specified type and value.
Value(char const *v)
Constructs an instance from common C++ literal types that closely, though not exactly,...
Contains all the Cloud Spanner C++ client types and functions.
Value(bool v)
Constructs an instance with the specified type and value.
Value(double v)
Constructs an instance with the specified type and value.
A representation of the Spanner BYTES type: variable-length binary data.
Represents a date in the proleptic Gregorian calendar as a triple of year, month (1-12),...
Value(std::int64_t v)
Constructs an instance with the specified type and value.
Value(std::vector< T > v)
Constructs an instance from a Spanner ARRAY of the specified type and values.
StatusOr< T > get() const &
Returns the contained value wrapped in a google::cloud::StatusOr<T>.
#define SPANNER_CLIENT_NS
Value(optional< T > opt)
Constructs a non-null instance if opt has a value, otherwise constructs a null instance with the spec...
Value(Timestamp v)
Constructs an instance with the specified type and value.
StatusOr< T > get() &&
Returns the contained value wrapped in a google::cloud::StatusOr<T>.
Value(CommitTimestamp v)
Constructs an instance with the specified type and value.
friend bool operator!=(Value const &a, Value const &b)
Value(Date v)
Constructs an instance with the specified type and value.
A representation of the Spanner TIMESTAMP type: An instant in time.
std::ostream & operator<<(std::ostream &os, Backup const &bn)