Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
9ea1ae9
feat(spanner): add spanner::Value support for TypeCode::UUID
devbww Apr 9, 2025
eef4248
chore: update googleapis SHA circa 2025-04-09 (#15074)
cuiy0006 Apr 9, 2025
56142f7
cleanup: StorageBatchOperations comment changes introduced by googlea…
cuiy0006 Apr 9, 2025
cdc8fbe
ci(gha): split shard and disable debug build for storage_grpc (#15071)
cuiy0006 Apr 10, 2025
2a57e04
impl: add experimental client SSL certificate support (#15062)
scotthart Apr 10, 2025
2d61aef
feat(devicestreaming): generate library (#15079)
cuiy0006 Apr 10, 2025
05fc5e4
impl: add experimental ca store in memory (#15068)
scotthart Apr 11, 2025
51cde37
impl: add experimental support for providing an SSL_CTX_FUNCTION (#15…
scotthart Apr 15, 2025
9011f1a
impl: do not attempt to include openSSL headers in windows (#15087)
scotthart Apr 15, 2025
7403897
feat(spanner): add ISO8601 duration support to spanner::Interval (#15…
devbww Apr 16, 2025
4eaba95
ci: split gha windows shard2 (#15091)
scotthart Apr 16, 2025
78a9c3b
impl: prevent logging options from being overwritten (#15090)
scotthart Apr 16, 2025
a8fc7b4
fix: fix bug with customheadersoption (#15053)
eliekozah Apr 16, 2025
2647639
samples(storage): use istreambuf_iterator instead of istream_iterator…
eliasdaler Apr 17, 2025
e4ad24d
chore(compute): update discovery doc circa 20250415 (#15093)
scotthart Apr 18, 2025
cc3d1ed
chore: update googleapis SHA circa 2025-04-16 (#15092)
scotthart Apr 18, 2025
438f655
impl: add HttpHeader class (#15099)
scotthart Apr 21, 2025
d362957
ci: format compute service dirs bzl (#15098)
scotthart Apr 21, 2025
b0905f9
impl(rest): dedup and merge headers right before writing them to curl…
scotthart Apr 22, 2025
6619aff
build: leverage cmake and bazel to determine when to use OpenSSL API …
scotthart Apr 22, 2025
5813de4
impl(generator): remove unused variable (#15103)
scotthart Apr 23, 2025
e87d201
feat(chronicle): generate library (#15083)
cuiy0006 Apr 24, 2025
dc9477d
ci: enable pedantic in clang-tidy builds (#15107)
scotthart Apr 24, 2025
37af5a0
feat(spanner): add spanner::Value support for TypeCode::INTERVAL (#15…
devbww Apr 25, 2025
967c7cb
Merge branch 'main' into uuid
devbww Apr 25, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions google/cloud/spanner/value.cc
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ std::ostream& StreamHelper(std::ostream& os, // NOLINT(misc-no-recursion)
case google::spanner::v1::TypeCode::TIMESTAMP:
case google::spanner::v1::TypeCode::NUMERIC:
case google::spanner::v1::TypeCode::INTERVAL:
case google::spanner::v1::TypeCode::UUID:
return os << v.string_value();

case google::spanner::v1::TypeCode::DATE:
Expand Down Expand Up @@ -274,6 +275,10 @@ bool Value::TypeProtoIs(Interval, google::spanner::v1::Type const& type) {
return type.code() == google::spanner::v1::TypeCode::INTERVAL;
}

bool Value::TypeProtoIs(Uuid, google::spanner::v1::Type const& type) {
return type.code() == google::spanner::v1::TypeCode::UUID;
}

bool Value::TypeProtoIs(std::string const&,
google::spanner::v1::Type const& type) {
return type.code() == google::spanner::v1::TypeCode::STRING;
Expand Down Expand Up @@ -415,6 +420,12 @@ google::spanner::v1::Type Value::MakeTypeProto(Interval) {
return t;
}

google::spanner::v1::Type Value::MakeTypeProto(Uuid) {
google::spanner::v1::Type t;
t.set_code(google::spanner::v1::TypeCode::UUID);
return t;
}

google::spanner::v1::Type Value::MakeTypeProto(int) {
return MakeTypeProto(std::int64_t{});
}
Expand Down Expand Up @@ -537,6 +548,12 @@ google::protobuf::Value Value::MakeValueProto(Interval intvl) {
return v;
}

google::protobuf::Value Value::MakeValueProto(Uuid u) {
google::protobuf::Value v;
v.set_string_value(std::string(u));
return v;
}

google::protobuf::Value Value::MakeValueProto(int i) {
return MakeValueProto(std::int64_t{i});
}
Expand Down Expand Up @@ -736,6 +753,14 @@ StatusOr<Interval> Value::GetValue(Interval, google::protobuf::Value const& pv,
return MakeInterval(pv.string_value());
}

StatusOr<Uuid> Value::GetValue(Uuid, google::protobuf::Value const& pv,
google::spanner::v1::Type const&) {
if (pv.kind_case() != google::protobuf::Value::kStringValue) {
return Status(StatusCode::kUnknown, "missing UUID");
}
return MakeUuid(pv.string_value());
}

GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END
} // namespace spanner
} // namespace cloud
Expand Down
8 changes: 8 additions & 0 deletions google/cloud/spanner/value.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include "google/cloud/spanner/proto_enum.h"
#include "google/cloud/spanner/proto_message.h"
#include "google/cloud/spanner/timestamp.h"
#include "google/cloud/spanner/uuid.h"
#include "google/cloud/spanner/version.h"
#include "google/cloud/internal/base64_transforms.h"
#include "google/cloud/internal/make_status.h"
Expand Down Expand Up @@ -79,6 +80,7 @@ GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN
* TIMESTAMP | `google::cloud::spanner::Timestamp`
* DATE | `absl::CivilDay`
* INTERVAL | `google::cloud::spanner::Interval`
* UUID | `google::cloud::spanner::Uuid`
* ENUM | `google::cloud::spanner::ProtoEnum<E>`
* PROTO | `google::cloud::spanner::ProtoMessage<M>`
* ARRAY | `std::vector<T>` // [1]
Expand Down Expand Up @@ -225,6 +227,7 @@ class Value {
: Value(PrivateConstructor{}, std::move(v)) {}
/// @copydoc Value(bool)
explicit Value(Interval v) : Value(PrivateConstructor{}, std::move(v)) {}
explicit Value(Uuid v) : Value(PrivateConstructor{}, std::move(v)) {}
/// @copydoc Value(bool)
template <typename E>
explicit Value(ProtoEnum<E> v) : Value(PrivateConstructor{}, std::move(v)) {}
Expand Down Expand Up @@ -392,6 +395,7 @@ class Value {
static bool TypeProtoIs(CommitTimestamp, google::spanner::v1::Type const&);
static bool TypeProtoIs(absl::CivilDay, google::spanner::v1::Type const&);
static bool TypeProtoIs(Interval, google::spanner::v1::Type const&);
static bool TypeProtoIs(Uuid, google::spanner::v1::Type const&);
static bool TypeProtoIs(std::string const&, google::spanner::v1::Type const&);
static bool TypeProtoIs(Bytes const&, google::spanner::v1::Type const&);
static bool TypeProtoIs(Json const&, google::spanner::v1::Type const&);
Expand Down Expand Up @@ -466,6 +470,7 @@ class Value {
static google::spanner::v1::Type MakeTypeProto(CommitTimestamp);
static google::spanner::v1::Type MakeTypeProto(absl::CivilDay);
static google::spanner::v1::Type MakeTypeProto(Interval);
static google::spanner::v1::Type MakeTypeProto(Uuid);
template <typename E>
static google::spanner::v1::Type MakeTypeProto(ProtoEnum<E>) {
google::spanner::v1::Type t;
Expand Down Expand Up @@ -546,6 +551,7 @@ class Value {
static google::protobuf::Value MakeValueProto(CommitTimestamp ts);
static google::protobuf::Value MakeValueProto(absl::CivilDay d);
static google::protobuf::Value MakeValueProto(Interval intvl);
static google::protobuf::Value MakeValueProto(Uuid u);
template <typename E>
static google::protobuf::Value MakeValueProto(ProtoEnum<E> e) {
return MakeValueProto(std::int64_t{E{e}});
Expand Down Expand Up @@ -638,6 +644,8 @@ class Value {
google::spanner::v1::Type const&);
static StatusOr<Interval> GetValue(Interval, google::protobuf::Value const&,
google::spanner::v1::Type const&);
static StatusOr<Uuid> GetValue(Uuid, google::protobuf::Value const&,
google::spanner::v1::Type const&);
template <typename E>
static StatusOr<ProtoEnum<E>> GetValue(ProtoEnum<E>,
google::protobuf::Value const& pv,
Expand Down
51 changes: 51 additions & 0 deletions google/cloud/spanner/value_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,15 @@ TEST(Value, BasicSemantics) {
TestBasicSemantics(v);
}

for (auto x : {Uuid()}) {
SCOPED_TRACE("Testing: google::cloud::spanner::Uuid " + std::string{x});
TestBasicSemantics(x);
TestBasicSemantics(std::vector<Uuid>(5, x));
std::vector<absl::optional<Uuid>> v(5, x);
v.resize(10);
TestBasicSemantics(v);
}

for (auto x : {testing::Genre::POP, testing::Genre::JAZZ,
testing::Genre::FOLK, testing::Genre::ROCK}) {
SCOPED_TRACE("Testing: ProtoEnum<testing::Genre> " +
Expand Down Expand Up @@ -949,6 +958,20 @@ TEST(Value, ProtoConversionInterval) {
}
}

TEST(Value, ProtoConversionUuid) {
for (auto const& x : std::vector<Uuid>{
Uuid(),
Uuid(0x7bf8a7b819171919, 0x2625f208c5824254),
MakeUuid("{0b6ed04ca16dfc4652817f9978c13738}").value(),
}) {
Value const v(x);
auto const p = spanner_internal::ToProto(v);
EXPECT_EQ(v, spanner_internal::FromProto(p.first, p.second));
EXPECT_EQ(google::spanner::v1::TypeCode::UUID, p.first.code());
EXPECT_EQ(std::string{x}, p.second.string_value());
}
}

TEST(Value, ProtoConversionProtoEnum) {
for (auto e : {testing::Genre::POP, testing::Genre::JAZZ,
testing::Genre::FOLK, testing::Genre::ROCK}) {
Expand Down Expand Up @@ -1296,6 +1319,24 @@ TEST(Value, GetBadInterval) {
EXPECT_THAT(v.get<Interval>(), Not(IsOk()));
}

TEST(Value, GetBadUuid) {
Value v(Uuid{});
ClearProtoKind(v);
EXPECT_THAT(v.get<Uuid>(), Not(IsOk()));

SetProtoKind(v, google::protobuf::NULL_VALUE);
EXPECT_THAT(v.get<Uuid>(), Not(IsOk()));

SetProtoKind(v, true);
EXPECT_THAT(v.get<Uuid>(), Not(IsOk()));

SetProtoKind(v, 0.0);
EXPECT_THAT(v.get<Uuid>(), Not(IsOk()));

SetProtoKind(v, "blah");
EXPECT_THAT(v.get<Uuid>(), Not(IsOk()));
}

TEST(Value, GetBadProtoEnum) {
Value v(ProtoEnum<testing::Genre>{});
ClearProtoKind(v);
Expand Down Expand Up @@ -1475,6 +1516,7 @@ TEST(Value, OutputStream) {
{Value(absl::CivilDay()), "1970-01-01", normal},
{Value(Timestamp()), "1970-01-01T00:00:00Z", normal},
{Value(Interval()), "P0D", normal},
{Value(Uuid()), "00000000-0000-0000-0000-000000000000", normal},
{Value(ProtoEnum<testing::Genre>(testing::Genre::POP)),
"google.cloud.spanner.testing.POP", normal},
{Value(ProtoMessage<testing::SingerInfo>(singer)),
Expand Down Expand Up @@ -1509,6 +1551,7 @@ TEST(Value, OutputStream) {
{MakeNullValue<absl::CivilDay>(), "NULL", normal},
{MakeNullValue<Timestamp>(), "NULL", normal},
{MakeNullValue<Interval>(), "NULL", normal},
{MakeNullValue<Uuid>(), "NULL", normal},
{MakeNullValue<ProtoEnum<testing::Genre>>(), "NULL", normal},
{MakeNullValue<ProtoMessage<testing::SingerInfo>>(), "NULL", normal},

Expand All @@ -1530,6 +1573,8 @@ TEST(Value, OutputStream) {
normal},
{Value(std::vector<Timestamp>{1}), "[1970-01-01T00:00:00Z]", normal},
{Value(std::vector<Interval>{1}), "[P0D]", normal},
{Value(std::vector<Uuid>{1}), "[00000000-0000-0000-0000-000000000000]",
normal},
{Value(std::vector<ProtoEnum<testing::Genre>>{testing::JAZZ,
testing::FOLK}),
"[google.cloud.spanner.testing.JAZZ, google.cloud.spanner.testing.FOLK]",
Expand All @@ -1556,6 +1601,7 @@ TEST(Value, OutputStream) {
{MakeNullValue<std::vector<absl::CivilDay>>(), "NULL", normal},
{MakeNullValue<std::vector<Timestamp>>(), "NULL", normal},
{MakeNullValue<std::vector<Interval>>(), "NULL", normal},
{MakeNullValue<std::vector<Uuid>>(), "NULL", normal},
{MakeNullValue<std::vector<ProtoEnum<testing::Genre>>>(), "NULL", normal},
{MakeNullValue<std::vector<ProtoMessage<testing::SingerInfo>>>(), "NULL",
normal},
Expand Down Expand Up @@ -1710,6 +1756,11 @@ TEST(Value, OutputStreamMatchesT) {
StreamMatchesValueStream(Interval());
StreamMatchesValueStream(MakeInterval("P1Y2M3DT4H5M6.789S").value());

// Uuid
StreamMatchesValueStream(Uuid());
StreamMatchesValueStream(
MakeUuid("{0b6ed04ca16dfc4652817f9978c13738}").value());

// ProtoEnum
StreamMatchesValueStream(ProtoEnum<testing::Genre>());
StreamMatchesValueStream(ProtoEnum<testing::Genre>(testing::ROCK));
Expand Down
Loading