|
21 | 21 | #include "google/cloud/spanner/json.h" |
22 | 22 | #include "google/cloud/spanner/numeric.h" |
23 | 23 | #include "google/cloud/spanner/oid.h" |
| 24 | +#include "google/cloud/spanner/proto_enum.h" |
| 25 | +#include "google/cloud/spanner/proto_message.h" |
24 | 26 | #include "google/cloud/spanner/timestamp.h" |
25 | 27 | #include "google/cloud/spanner/version.h" |
| 28 | +#include "google/cloud/internal/base64_transforms.h" |
26 | 29 | #include "google/cloud/internal/throw_delegate.h" |
27 | 30 | #include "google/cloud/optional.h" |
28 | 31 | #include "google/cloud/status_or.h" |
@@ -72,6 +75,8 @@ GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN |
72 | 75 | * OID(PG) | `google::cloud::spanner::PgOid` |
73 | 76 | * TIMESTAMP | `google::cloud::spanner::Timestamp` |
74 | 77 | * DATE | `absl::CivilDay` |
| 78 | + * ENUM | `google::cloud::spanner::ProtoEnum<E>` |
| 79 | + * PROTO | `google::cloud::spanner::ProtoMessage<M>` |
75 | 80 | * ARRAY | `std::vector<T>` // [1] |
76 | 81 | * STRUCT | `std::tuple<Ts...>` |
77 | 82 | * |
@@ -212,6 +217,13 @@ class Value { |
212 | 217 | /// @copydoc Value(bool) |
213 | 218 | explicit Value(absl::CivilDay v) |
214 | 219 | : Value(PrivateConstructor{}, std::move(v)) {} |
| 220 | + /// @copydoc Value(bool) |
| 221 | + template <typename E> |
| 222 | + explicit Value(ProtoEnum<E> v) : Value(PrivateConstructor{}, std::move(v)) {} |
| 223 | + /// @copydoc Value(bool) |
| 224 | + template <typename M> |
| 225 | + explicit Value(ProtoMessage<M> v) |
| 226 | + : Value(PrivateConstructor{}, std::move(v)) {} |
215 | 227 |
|
216 | 228 | /** |
217 | 229 | * Constructs an instance from common C++ literal types that closely, though |
@@ -377,6 +389,18 @@ class Value { |
377 | 389 | static bool TypeProtoIs(Numeric const&, google::spanner::v1::Type const&); |
378 | 390 | static bool TypeProtoIs(PgNumeric const&, google::spanner::v1::Type const&); |
379 | 391 | static bool TypeProtoIs(PgOid const&, google::spanner::v1::Type const&); |
| 392 | + template <typename E> |
| 393 | + static bool TypeProtoIs(ProtoEnum<E> const&, |
| 394 | + google::spanner::v1::Type const& type) { |
| 395 | + return type.code() == google::spanner::v1::TypeCode::ENUM && |
| 396 | + type.proto_type_fqn() == ProtoEnum<E>::TypeName(); |
| 397 | + } |
| 398 | + template <typename M> |
| 399 | + static bool TypeProtoIs(ProtoMessage<M> const&, |
| 400 | + google::spanner::v1::Type const& type) { |
| 401 | + return type.code() == google::spanner::v1::TypeCode::PROTO && |
| 402 | + type.proto_type_fqn() == ProtoMessage<M>::TypeName(); |
| 403 | + } |
380 | 404 | template <typename T> |
381 | 405 | static bool TypeProtoIs(absl::optional<T>, |
382 | 406 | google::spanner::v1::Type const& type) { |
@@ -430,6 +454,20 @@ class Value { |
430 | 454 | static google::spanner::v1::Type MakeTypeProto(Timestamp); |
431 | 455 | static google::spanner::v1::Type MakeTypeProto(CommitTimestamp); |
432 | 456 | static google::spanner::v1::Type MakeTypeProto(absl::CivilDay); |
| 457 | + template <typename E> |
| 458 | + static google::spanner::v1::Type MakeTypeProto(ProtoEnum<E>) { |
| 459 | + google::spanner::v1::Type t; |
| 460 | + t.set_code(google::spanner::v1::TypeCode::ENUM); |
| 461 | + t.set_proto_type_fqn(ProtoEnum<E>::TypeName()); |
| 462 | + return t; |
| 463 | + } |
| 464 | + template <typename M> |
| 465 | + static google::spanner::v1::Type MakeTypeProto(ProtoMessage<M>) { |
| 466 | + google::spanner::v1::Type t; |
| 467 | + t.set_code(google::spanner::v1::TypeCode::PROTO); |
| 468 | + t.set_proto_type_fqn(ProtoMessage<M>::TypeName()); |
| 469 | + return t; |
| 470 | + } |
433 | 471 | static google::spanner::v1::Type MakeTypeProto(int); |
434 | 472 | static google::spanner::v1::Type MakeTypeProto(char const*); |
435 | 473 | template <typename T> |
@@ -494,6 +532,16 @@ class Value { |
494 | 532 | static google::protobuf::Value MakeValueProto(Timestamp ts); |
495 | 533 | static google::protobuf::Value MakeValueProto(CommitTimestamp ts); |
496 | 534 | static google::protobuf::Value MakeValueProto(absl::CivilDay d); |
| 535 | + template <typename E> |
| 536 | + static google::protobuf::Value MakeValueProto(ProtoEnum<E> e) { |
| 537 | + return MakeValueProto(std::int64_t{E{e}}); |
| 538 | + } |
| 539 | + template <typename M> |
| 540 | + static google::protobuf::Value MakeValueProto(ProtoMessage<M> m) { |
| 541 | + internal::Base64Encoder encoder; |
| 542 | + for (auto c : std::string{m}) encoder.PushBack(c); |
| 543 | + return MakeValueProto(std::move(encoder).FlushAndPad()); |
| 544 | + } |
497 | 545 | static google::protobuf::Value MakeValueProto(int i); |
498 | 546 | static google::protobuf::Value MakeValueProto(char const* s); |
499 | 547 | template <typename T> |
@@ -572,6 +620,32 @@ class Value { |
572 | 620 | static StatusOr<absl::CivilDay> GetValue(absl::CivilDay, |
573 | 621 | google::protobuf::Value const&, |
574 | 622 | google::spanner::v1::Type const&); |
| 623 | + template <typename E> |
| 624 | + static StatusOr<ProtoEnum<E>> GetValue(ProtoEnum<E>, |
| 625 | + google::protobuf::Value const& pv, |
| 626 | + google::spanner::v1::Type const& pt) { |
| 627 | + if (pv.kind_case() != google::protobuf::Value::kStringValue) { |
| 628 | + return Status(StatusCode::kUnknown, "missing ENUM"); |
| 629 | + } |
| 630 | + auto value = GetValue(std::int64_t{}, pv, pt); |
| 631 | + if (!value) return std::move(value).status(); |
| 632 | + if (static_cast<typename std::underlying_type_t<E>>(*value) != *value) { |
| 633 | + return Status(StatusCode::kUnknown, |
| 634 | + "Value out of range: " + pv.string_value()); |
| 635 | + } |
| 636 | + return ProtoEnum<E>(static_cast<E>(*std::move(value))); |
| 637 | + } |
| 638 | + template <typename M> |
| 639 | + static StatusOr<ProtoMessage<M>> GetValue(ProtoMessage<M>, |
| 640 | + google::protobuf::Value const& pv, |
| 641 | + google::spanner::v1::Type const&) { |
| 642 | + if (pv.kind_case() != google::protobuf::Value::kStringValue) { |
| 643 | + return Status(StatusCode::kUnknown, "missing PROTO"); |
| 644 | + } |
| 645 | + auto bytes = internal::Base64DecodeToBytes(pv.string_value()); |
| 646 | + if (!bytes) return std::move(bytes).status(); |
| 647 | + return ProtoMessage<M>(std::string(bytes->begin(), bytes->end())); |
| 648 | + } |
575 | 649 | template <typename T, typename V> |
576 | 650 | static StatusOr<absl::optional<T>> GetValue( |
577 | 651 | absl::optional<T> const&, V&& pv, google::spanner::v1::Type const& pt) { |
|
0 commit comments