Skip to content

Commit 801cd33

Browse files
authored
feat(spanner): add samples for proto columns (#13759)
Also add "singer_cc_proto" dependencies to the tests that use it directly, as would be required if strict checking was enabled.
1 parent 3dad8a5 commit 801cd33

File tree

4 files changed

+322
-1
lines changed

4 files changed

+322
-1
lines changed

google/cloud/spanner/BUILD.bazel

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,10 @@ proto_library(
101101

102102
cc_proto_library(
103103
name = "singer_cc_proto",
104-
visibility = ["//:__pkg__"],
104+
visibility = [
105+
":__subpackages__",
106+
"//:__pkg__",
107+
],
105108
deps = [":singer_proto"],
106109
)
107110

@@ -142,6 +145,7 @@ cc_library(
142145
deps = [
143146
":google_cloud_cpp_spanner",
144147
":google_cloud_cpp_spanner_mocks",
148+
":singer_cc_proto",
145149
":spanner_client_testing_private",
146150
"//:common",
147151
"//google/cloud:google_cloud_cpp_mocks",

google/cloud/spanner/integration_tests/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ licenses(["notice"]) # Apache 2.0
2929
"//:common",
3030
"//:spanner",
3131
"//:spanner_mocks",
32+
"//google/cloud/spanner:singer_cc_proto",
3233
"//google/cloud/spanner:spanner_client_testing_private",
3334
"//google/cloud/testing_util:google_cloud_cpp_testing_grpc_private",
3435
"//google/cloud/testing_util:google_cloud_cpp_testing_private",

google/cloud/spanner/samples/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ licenses(["notice"]) # Apache 2.0
3131
deps = [
3232
"//:common",
3333
"//:spanner",
34+
"//google/cloud/spanner:singer_cc_proto",
3435
"//google/cloud/spanner:spanner_client_testing_private",
3536
"//google/cloud/testing_util:google_cloud_cpp_testing_private",
3637
],

google/cloud/spanner/samples/samples.cc

Lines changed: 315 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include "google/cloud/spanner/testing/random_backup_name.h"
3131
#include "google/cloud/spanner/testing/random_database_name.h"
3232
#include "google/cloud/spanner/testing/random_instance_name.h"
33+
#include "google/cloud/spanner/testing/singer.pb.h"
3334
#include "google/cloud/spanner/update_instance_request_builder.h"
3435
#include "google/cloud/internal/getenv.h"
3536
#include "google/cloud/internal/random.h"
@@ -989,6 +990,22 @@ void AddTimestampColumn(
989990
}
990991
// [END spanner_add_timestamp_column]
991992

993+
//! [drop-column]
994+
void DropColumn(google::cloud::spanner_admin::DatabaseAdminClient client,
995+
std::string const& project_id, std::string const& instance_id,
996+
std::string const& database_id) {
997+
google::cloud::spanner::Database database(project_id, instance_id,
998+
database_id);
999+
auto metadata =
1000+
client
1001+
.UpdateDatabaseDdl(database.FullName(),
1002+
{"ALTER TABLE Singers DROP COLUMN SingerInfo"})
1003+
.get();
1004+
if (!metadata) throw std::move(metadata).status();
1005+
std::cout << "Dropped SingerInfo column\n";
1006+
}
1007+
//! [drop-column]
1008+
9921009
// [START spanner_create_storing_index]
9931010
void AddStoringIndex(google::cloud::spanner_admin::DatabaseAdminClient client,
9941011
std::string const& project_id,
@@ -3649,6 +3666,250 @@ void DropForeignKeyConstraintDeleteCascade(
36493666
}
36503667
// [END spanner_drop_foreign_key_constraint_delete_cascade]
36513668

3669+
// [START spanner_add_proto_type_columns]
3670+
void AddProtoTypeColumns(
3671+
google::cloud::spanner_admin::DatabaseAdminClient client,
3672+
std::string const& project_id, std::string const& instance_id,
3673+
std::string const& database_id) {
3674+
google::cloud::spanner::Database database(project_id, instance_id,
3675+
database_id);
3676+
google::spanner::admin::database::v1::UpdateDatabaseDdlRequest request;
3677+
request.set_database(database.FullName());
3678+
google::protobuf::FileDescriptorSet fds;
3679+
google::cloud::spanner::testing::SingerInfo::default_instance()
3680+
.GetMetadata()
3681+
.descriptor->file()
3682+
->CopyTo(fds.add_file());
3683+
fds.SerializeToString(request.mutable_proto_descriptors());
3684+
request.add_statements(R"""(
3685+
CREATE PROTO BUNDLE (
3686+
google.cloud.spanner.testing.SingerInfo,
3687+
google.cloud.spanner.testing.Genre,
3688+
)
3689+
)""");
3690+
request.add_statements(R"""(
3691+
ALTER TABLE Singers ADD COLUMN
3692+
SingerInfo google.cloud.spanner.testing.SingerInfo
3693+
)""");
3694+
request.add_statements(R"""(
3695+
ALTER TABLE Singers ADD COLUMN
3696+
SingerInfoArray ARRAY<google.cloud.spanner.testing.SingerInfo>
3697+
)""");
3698+
request.add_statements(R"""(
3699+
ALTER TABLE Singers ADD COLUMN
3700+
SingerGenre google.cloud.spanner.testing.Genre
3701+
)""");
3702+
request.add_statements(R"""(
3703+
ALTER TABLE Singers ADD COLUMN
3704+
SingerGenreArray ARRAY<google.cloud.spanner.testing.Genre>
3705+
)""");
3706+
auto metadata = client.UpdateDatabaseDdl(request).get();
3707+
if (!metadata) throw std::move(metadata).status();
3708+
std::cout << "`Singers` table altered, new DDL:\n" << metadata->DebugString();
3709+
}
3710+
// [END spanner_add_proto_type_columns]
3711+
3712+
// [START spanner_update_data_with_proto_message_column]
3713+
void UpdateDataWithProtoMessageColumn(google::cloud::spanner::Client client) {
3714+
google::cloud::spanner::testing::SingerInfo singer_proto;
3715+
singer_proto.set_singer_id(2);
3716+
singer_proto.set_birth_date("1942-06-18");
3717+
singer_proto.set_nationality("British");
3718+
singer_proto.set_genre(google::cloud::spanner::testing::Genre::POP);
3719+
3720+
using SingerInfoMessage = google::cloud::spanner::ProtoMessage<
3721+
google::cloud::spanner::testing::SingerInfo>;
3722+
auto singer_info = SingerInfoMessage(singer_proto);
3723+
auto commit_results =
3724+
client.CommitAtLeastOnce({google::cloud::spanner::Mutations{
3725+
google::cloud::spanner::InsertOrUpdateMutationBuilder(
3726+
"Singers", {"SingerId", "SingerInfo", "SingerInfoArray"})
3727+
.EmplaceRow(2, singer_info,
3728+
std::vector<SingerInfoMessage>{singer_info})
3729+
.EmplaceRow(3, absl::optional<SingerInfoMessage>(),
3730+
absl::optional<std::vector<SingerInfoMessage>>())
3731+
.Build()}});
3732+
for (auto& commit_result : commit_results) {
3733+
if (!commit_result) throw std::move(commit_result).status();
3734+
}
3735+
std::cout << "Update was successful "
3736+
<< "[spanner_update_data_with_proto_message_column]\n";
3737+
}
3738+
// [END spanner_update_data_with_proto_message_column]
3739+
3740+
// [START spanner_update_data_with_proto_message_column_with_dml]
3741+
void UpdateDataWithProtoMessageColumnWithDml(
3742+
google::cloud::spanner::Client client) {
3743+
std::int64_t rows_modified = 0;
3744+
auto commit_result = client.Commit(
3745+
[&client, &rows_modified](google::cloud::spanner::Transaction txn)
3746+
-> google::cloud::StatusOr<google::cloud::spanner::Mutations> {
3747+
google::cloud::spanner::testing::SingerInfo singer_proto;
3748+
singer_proto.set_singer_id(1);
3749+
singer_proto.set_birth_date("1943-06-15");
3750+
singer_proto.set_nationality("French");
3751+
singer_proto.set_genre(google::cloud::spanner::testing::Genre::ROCK);
3752+
3753+
using SingerInfoMessage = google::cloud::spanner::ProtoMessage<
3754+
google::cloud::spanner::testing::SingerInfo>;
3755+
auto singer_info = SingerInfoMessage(singer_proto);
3756+
auto update = client.ExecuteDml(
3757+
std::move(txn),
3758+
google::cloud::spanner::SqlStatement(
3759+
"UPDATE Singers"
3760+
" SET SingerInfo = @singer_info,"
3761+
" SingerInfoArray = @singer_info_array"
3762+
" WHERE SingerId = 1",
3763+
{{"singer_info", google::cloud::spanner::Value(singer_info)},
3764+
{"singer_info_array",
3765+
google::cloud::spanner::Value(
3766+
std::vector<SingerInfoMessage>{singer_info})}}));
3767+
if (!update) return std::move(update).status();
3768+
rows_modified = update->RowsModified();
3769+
return google::cloud::spanner::Mutations{};
3770+
});
3771+
if (!commit_result) throw std::move(commit_result).status();
3772+
std::cout << "Updated " << rows_modified << " row(s) "
3773+
<< "[spanner_update_data_with_proto_message_column_with_dml]\n";
3774+
}
3775+
// [END spanner_update_data_with_proto_message_column_with_dml]
3776+
3777+
// [START spanner_query_with_proto_message_parameter]
3778+
void QueryWithProtoMessageParameter(google::cloud::spanner::Client client) {
3779+
google::cloud::spanner::SqlStatement select(
3780+
"SELECT SingerId, SingerInfo, SingerInfoArray FROM Singers"
3781+
" WHERE SingerInfo.Nationality = @nationality",
3782+
{{"nationality", google::cloud::spanner::Value("British")}});
3783+
using SingerInfoMessage = google::cloud::spanner::ProtoMessage<
3784+
google::cloud::spanner::testing::SingerInfo>;
3785+
using RowType = std::tuple<std::int64_t, absl::optional<SingerInfoMessage>,
3786+
absl::optional<std::vector<SingerInfoMessage>>>;
3787+
auto rows = client.ExecuteQuery(std::move(select));
3788+
for (auto& row : google::cloud::spanner::StreamOf<RowType>(rows)) {
3789+
if (!row) throw std::move(row).status();
3790+
std::cout << "SingerId: " << std::get<0>(*row);
3791+
std::cout << ", SingerInfo: ";
3792+
auto singer_info = std::get<1>(*row);
3793+
if (!singer_info) {
3794+
std::cout << "NULL";
3795+
} else {
3796+
std::cout << *singer_info;
3797+
}
3798+
std::cout << ", SingerInfoArray: ";
3799+
auto singer_info_array = std::get<2>(*row);
3800+
if (!singer_info_array) {
3801+
std::cout << "NULL";
3802+
} else {
3803+
std::cout << "{";
3804+
char const* sep = " ";
3805+
for (auto const& singer_info : *singer_info_array) {
3806+
std::cout << sep << singer_info;
3807+
sep = ", ";
3808+
}
3809+
std::cout << " }";
3810+
}
3811+
std::cout << "\n";
3812+
}
3813+
std::cout << "Query completed for "
3814+
<< "[spanner_query_with_proto_message_parameter]\n";
3815+
}
3816+
// [END spanner_query_with_proto_message_parameter]
3817+
3818+
// [START spanner_update_data_with_proto_enum_column]
3819+
void UpdateDataWithProtoEnumColumn(google::cloud::spanner::Client client) {
3820+
using GenreEnum =
3821+
google::cloud::spanner::ProtoEnum<google::cloud::spanner::testing::Genre>;
3822+
auto singer_genre = GenreEnum(google::cloud::spanner::testing::Genre::FOLK);
3823+
auto commit_results =
3824+
client.CommitAtLeastOnce({google::cloud::spanner::Mutations{
3825+
google::cloud::spanner::InsertOrUpdateMutationBuilder(
3826+
"Singers", {"SingerId", "SingerGenre", "SingerGenreArray"})
3827+
.EmplaceRow(2, singer_genre, std::vector<GenreEnum>{singer_genre})
3828+
.EmplaceRow(3, absl::optional<GenreEnum>(),
3829+
absl::optional<std::vector<GenreEnum>>())
3830+
.Build()}});
3831+
for (auto& commit_result : commit_results) {
3832+
if (!commit_result) throw std::move(commit_result).status();
3833+
}
3834+
std::cout << "Update was successful "
3835+
<< "[spanner_update_data_with_proto_enum_column]\n";
3836+
}
3837+
// [END spanner_update_data_with_proto_enum_column]
3838+
3839+
// [START spanner_update_data_with_proto_enum_column_with_dml]
3840+
void UpdateDataWithProtoEnumColumnWithDml(
3841+
google::cloud::spanner::Client client) {
3842+
std::int64_t rows_modified = 0;
3843+
auto commit_result = client.Commit(
3844+
[&client, &rows_modified](google::cloud::spanner::Transaction txn)
3845+
-> google::cloud::StatusOr<google::cloud::spanner::Mutations> {
3846+
using GenreEnum = google::cloud::spanner::ProtoEnum<
3847+
google::cloud::spanner::testing::Genre>;
3848+
auto singer_genre =
3849+
GenreEnum(google::cloud::spanner::testing::Genre::ROCK);
3850+
auto update = client.ExecuteDml(
3851+
std::move(txn),
3852+
google::cloud::spanner::SqlStatement(
3853+
"UPDATE Singers"
3854+
" SET SingerGenre = @singer_genre,"
3855+
" SingerGenreArray = @singer_genre_array"
3856+
" WHERE SingerId = 1",
3857+
{{"singer_genre", google::cloud::spanner::Value(singer_genre)},
3858+
{"singer_genre_array",
3859+
google::cloud::spanner::Value(
3860+
std::vector<GenreEnum>{singer_genre})}}));
3861+
if (!update) return std::move(update).status();
3862+
rows_modified = update->RowsModified();
3863+
return google::cloud::spanner::Mutations{};
3864+
});
3865+
if (!commit_result) throw std::move(commit_result).status();
3866+
std::cout << "Updated " << rows_modified << " row(s) "
3867+
<< "[spanner_update_data_with_proto_enum_column_with_dml]\n";
3868+
}
3869+
// [END spanner_update_data_with_proto_enum_column_with_dml]
3870+
3871+
// [START spanner_query_with_proto_enum_parameter]
3872+
void QueryWithProtoEnumParameter(google::cloud::spanner::Client client) {
3873+
using GenreEnum =
3874+
google::cloud::spanner::ProtoEnum<google::cloud::spanner::testing::Genre>;
3875+
auto singer_genre = GenreEnum(google::cloud::spanner::testing::Genre::ROCK);
3876+
google::cloud::spanner::SqlStatement select(
3877+
"SELECT SingerId, SingerGenre, SingerGenreArray FROM Singers"
3878+
" WHERE SingerGenre = @singer_genre",
3879+
{{"singer_genre", google::cloud::spanner::Value(singer_genre)}});
3880+
using RowType = std::tuple<std::int64_t, absl::optional<GenreEnum>,
3881+
absl::optional<std::vector<GenreEnum>>>;
3882+
auto rows = client.ExecuteQuery(std::move(select));
3883+
for (auto& row : google::cloud::spanner::StreamOf<RowType>(rows)) {
3884+
if (!row) throw std::move(row).status();
3885+
std::cout << "SingerId: " << std::get<0>(*row);
3886+
std::cout << ", SingerGenre: ";
3887+
auto singer_genre = std::get<1>(*row);
3888+
if (!singer_genre) {
3889+
std::cout << "NULL";
3890+
} else {
3891+
std::cout << *singer_genre;
3892+
}
3893+
std::cout << ", SingerGenreArray: ";
3894+
auto singer_genre_array = std::get<2>(*row);
3895+
if (!singer_genre_array) {
3896+
std::cout << "NULL";
3897+
} else {
3898+
std::cout << "{";
3899+
char const* sep = " ";
3900+
for (auto const& singer_genre : *singer_genre_array) {
3901+
std::cout << sep << singer_genre;
3902+
sep = ", ";
3903+
}
3904+
std::cout << " }";
3905+
}
3906+
std::cout << "\n";
3907+
}
3908+
std::cout << "Query completed for "
3909+
<< "[spanner_query_with_proto_enum_parameter]\n";
3910+
}
3911+
// [END spanner_query_with_proto_enum_parameter]
3912+
36523913
void ExampleStatusOr(google::cloud::spanner::Client client) {
36533914
//! [example-status-or]
36543915
namespace spanner = ::google::cloud::spanner;
@@ -4292,6 +4553,7 @@ int RunOneCommand(std::vector<std::string> argv) {
42924553
make_database_command_entry("list-database-roles", ListDatabaseRoles),
42934554
make_database_command_entry("add-column", AddColumn),
42944555
make_database_command_entry("add-timestamp-column", AddTimestampColumn),
4556+
make_database_command_entry("drop-column", DropColumn),
42954557
{"list-databases", ListDatabasesCommand},
42964558
{"create-backup", CreateBackupCommand},
42974559
{"restore-database", RestoreDatabaseCommand},
@@ -4411,6 +4673,21 @@ int RunOneCommand(std::vector<std::string> argv) {
44114673
make_command_entry("make-delete-mutation", MakeDeleteMutation),
44124674
make_command_entry("query-information-schema-database-options",
44134675
QueryInformationSchemaDatabaseOptions),
4676+
make_database_command_entry("spanner_add_proto_type_columns",
4677+
AddProtoTypeColumns),
4678+
make_command_entry("spanner_update_data_with_proto_message_column",
4679+
UpdateDataWithProtoMessageColumn),
4680+
make_command_entry(
4681+
"spanner_update_data_with_proto_message_column_with_dml",
4682+
UpdateDataWithProtoMessageColumnWithDml),
4683+
make_command_entry("spanner_query_with_proto_message_parameter",
4684+
QueryWithProtoMessageParameter),
4685+
make_command_entry("spanner_update_data_with_proto_enum_column",
4686+
UpdateDataWithProtoEnumColumn),
4687+
make_command_entry("spanner_update_data_with_proto_enum_column_with_dml",
4688+
UpdateDataWithProtoEnumColumnWithDml),
4689+
make_command_entry("spanner_query_with_proto_enum_parameter",
4690+
QueryWithProtoEnumParameter),
44144691
};
44154692

44164693
static std::string usage_msg = [&argv, &commands] {
@@ -5231,6 +5508,44 @@ void RunAll(bool emulator) {
52315508
SampleBanner("spanner_drop_database");
52325509
DropDatabase(database_admin_client, project_id, instance_id, database_id);
52335510
}
5511+
5512+
if (!emulator) { // proto columns and enums
5513+
SampleBanner("spanner_create_database");
5514+
CreateDatabase(database_admin_client, project_id, instance_id, database_id);
5515+
5516+
SampleBanner("drop-column");
5517+
DropColumn(database_admin_client, project_id, instance_id, database_id);
5518+
5519+
SampleBanner("spanner_add_proto_type_columns");
5520+
AddProtoTypeColumns(database_admin_client, project_id, instance_id,
5521+
database_id);
5522+
5523+
client = MakeSampleClient(project_id, instance_id, database_id);
5524+
5525+
SampleBanner("insert-mutation-builder");
5526+
InsertMutationBuilder(client);
5527+
5528+
SampleBanner("spanner_update_data_with_proto_message_column");
5529+
UpdateDataWithProtoMessageColumn(client);
5530+
5531+
SampleBanner("spanner_update_data_with_proto_message_column_with_dml");
5532+
UpdateDataWithProtoMessageColumnWithDml(client);
5533+
5534+
SampleBanner("spanner_query_with_proto_message_parameter");
5535+
QueryWithProtoMessageParameter(client);
5536+
5537+
SampleBanner("spanner_update_data_with_proto_enum_column");
5538+
UpdateDataWithProtoEnumColumn(client);
5539+
5540+
SampleBanner("spanner_update_data_with_proto_enum_column_with_dml");
5541+
UpdateDataWithProtoEnumColumnWithDml(client);
5542+
5543+
SampleBanner("spanner_query_with_proto_enum_parameter");
5544+
QueryWithProtoEnumParameter(client);
5545+
5546+
SampleBanner("spanner_drop_database");
5547+
DropDatabase(database_admin_client, project_id, instance_id, database_id);
5548+
}
52345549
}
52355550

52365551
bool AutoRun() {

0 commit comments

Comments
 (0)