Skip to content

Commit

Permalink
feat(spanner): add samples for proto columns (#13759)
Browse files Browse the repository at this point in the history
Also add "singer_cc_proto" dependencies to the tests that use
it directly, as would be required if strict checking was enabled.
  • Loading branch information
devbww committed Mar 9, 2024
1 parent 3dad8a5 commit 801cd33
Show file tree
Hide file tree
Showing 4 changed files with 322 additions and 1 deletion.
6 changes: 5 additions & 1 deletion google/cloud/spanner/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,10 @@ proto_library(

cc_proto_library(
name = "singer_cc_proto",
visibility = ["//:__pkg__"],
visibility = [
":__subpackages__",
"//:__pkg__",
],
deps = [":singer_proto"],
)

Expand Down Expand Up @@ -142,6 +145,7 @@ cc_library(
deps = [
":google_cloud_cpp_spanner",
":google_cloud_cpp_spanner_mocks",
":singer_cc_proto",
":spanner_client_testing_private",
"//:common",
"//google/cloud:google_cloud_cpp_mocks",
Expand Down
1 change: 1 addition & 0 deletions google/cloud/spanner/integration_tests/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ licenses(["notice"]) # Apache 2.0
"//:common",
"//:spanner",
"//:spanner_mocks",
"//google/cloud/spanner:singer_cc_proto",
"//google/cloud/spanner:spanner_client_testing_private",
"//google/cloud/testing_util:google_cloud_cpp_testing_grpc_private",
"//google/cloud/testing_util:google_cloud_cpp_testing_private",
Expand Down
1 change: 1 addition & 0 deletions google/cloud/spanner/samples/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ licenses(["notice"]) # Apache 2.0
deps = [
"//:common",
"//:spanner",
"//google/cloud/spanner:singer_cc_proto",
"//google/cloud/spanner:spanner_client_testing_private",
"//google/cloud/testing_util:google_cloud_cpp_testing_private",
],
Expand Down
315 changes: 315 additions & 0 deletions google/cloud/spanner/samples/samples.cc
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include "google/cloud/spanner/testing/random_backup_name.h"
#include "google/cloud/spanner/testing/random_database_name.h"
#include "google/cloud/spanner/testing/random_instance_name.h"
#include "google/cloud/spanner/testing/singer.pb.h"
#include "google/cloud/spanner/update_instance_request_builder.h"
#include "google/cloud/internal/getenv.h"
#include "google/cloud/internal/random.h"
Expand Down Expand Up @@ -989,6 +990,22 @@ void AddTimestampColumn(
}
// [END spanner_add_timestamp_column]

//! [drop-column]
void DropColumn(google::cloud::spanner_admin::DatabaseAdminClient client,
std::string const& project_id, std::string const& instance_id,
std::string const& database_id) {
google::cloud::spanner::Database database(project_id, instance_id,
database_id);
auto metadata =
client
.UpdateDatabaseDdl(database.FullName(),
{"ALTER TABLE Singers DROP COLUMN SingerInfo"})
.get();
if (!metadata) throw std::move(metadata).status();
std::cout << "Dropped SingerInfo column\n";
}
//! [drop-column]

// [START spanner_create_storing_index]
void AddStoringIndex(google::cloud::spanner_admin::DatabaseAdminClient client,
std::string const& project_id,
Expand Down Expand Up @@ -3649,6 +3666,250 @@ void DropForeignKeyConstraintDeleteCascade(
}
// [END spanner_drop_foreign_key_constraint_delete_cascade]

// [START spanner_add_proto_type_columns]
void AddProtoTypeColumns(
google::cloud::spanner_admin::DatabaseAdminClient client,
std::string const& project_id, std::string const& instance_id,
std::string const& database_id) {
google::cloud::spanner::Database database(project_id, instance_id,
database_id);
google::spanner::admin::database::v1::UpdateDatabaseDdlRequest request;
request.set_database(database.FullName());
google::protobuf::FileDescriptorSet fds;
google::cloud::spanner::testing::SingerInfo::default_instance()
.GetMetadata()
.descriptor->file()
->CopyTo(fds.add_file());
fds.SerializeToString(request.mutable_proto_descriptors());
request.add_statements(R"""(
CREATE PROTO BUNDLE (
google.cloud.spanner.testing.SingerInfo,
google.cloud.spanner.testing.Genre,
)
)""");
request.add_statements(R"""(
ALTER TABLE Singers ADD COLUMN
SingerInfo google.cloud.spanner.testing.SingerInfo
)""");
request.add_statements(R"""(
ALTER TABLE Singers ADD COLUMN
SingerInfoArray ARRAY<google.cloud.spanner.testing.SingerInfo>
)""");
request.add_statements(R"""(
ALTER TABLE Singers ADD COLUMN
SingerGenre google.cloud.spanner.testing.Genre
)""");
request.add_statements(R"""(
ALTER TABLE Singers ADD COLUMN
SingerGenreArray ARRAY<google.cloud.spanner.testing.Genre>
)""");
auto metadata = client.UpdateDatabaseDdl(request).get();
if (!metadata) throw std::move(metadata).status();
std::cout << "`Singers` table altered, new DDL:\n" << metadata->DebugString();
}
// [END spanner_add_proto_type_columns]

// [START spanner_update_data_with_proto_message_column]
void UpdateDataWithProtoMessageColumn(google::cloud::spanner::Client client) {
google::cloud::spanner::testing::SingerInfo singer_proto;
singer_proto.set_singer_id(2);
singer_proto.set_birth_date("1942-06-18");
singer_proto.set_nationality("British");
singer_proto.set_genre(google::cloud::spanner::testing::Genre::POP);

using SingerInfoMessage = google::cloud::spanner::ProtoMessage<
google::cloud::spanner::testing::SingerInfo>;
auto singer_info = SingerInfoMessage(singer_proto);
auto commit_results =
client.CommitAtLeastOnce({google::cloud::spanner::Mutations{
google::cloud::spanner::InsertOrUpdateMutationBuilder(
"Singers", {"SingerId", "SingerInfo", "SingerInfoArray"})
.EmplaceRow(2, singer_info,
std::vector<SingerInfoMessage>{singer_info})
.EmplaceRow(3, absl::optional<SingerInfoMessage>(),
absl::optional<std::vector<SingerInfoMessage>>())
.Build()}});
for (auto& commit_result : commit_results) {
if (!commit_result) throw std::move(commit_result).status();
}
std::cout << "Update was successful "
<< "[spanner_update_data_with_proto_message_column]\n";
}
// [END spanner_update_data_with_proto_message_column]

// [START spanner_update_data_with_proto_message_column_with_dml]
void UpdateDataWithProtoMessageColumnWithDml(
google::cloud::spanner::Client client) {
std::int64_t rows_modified = 0;
auto commit_result = client.Commit(
[&client, &rows_modified](google::cloud::spanner::Transaction txn)
-> google::cloud::StatusOr<google::cloud::spanner::Mutations> {
google::cloud::spanner::testing::SingerInfo singer_proto;
singer_proto.set_singer_id(1);
singer_proto.set_birth_date("1943-06-15");
singer_proto.set_nationality("French");
singer_proto.set_genre(google::cloud::spanner::testing::Genre::ROCK);

using SingerInfoMessage = google::cloud::spanner::ProtoMessage<
google::cloud::spanner::testing::SingerInfo>;
auto singer_info = SingerInfoMessage(singer_proto);
auto update = client.ExecuteDml(
std::move(txn),
google::cloud::spanner::SqlStatement(
"UPDATE Singers"
" SET SingerInfo = @singer_info,"
" SingerInfoArray = @singer_info_array"
" WHERE SingerId = 1",
{{"singer_info", google::cloud::spanner::Value(singer_info)},
{"singer_info_array",
google::cloud::spanner::Value(
std::vector<SingerInfoMessage>{singer_info})}}));
if (!update) return std::move(update).status();
rows_modified = update->RowsModified();
return google::cloud::spanner::Mutations{};
});
if (!commit_result) throw std::move(commit_result).status();
std::cout << "Updated " << rows_modified << " row(s) "
<< "[spanner_update_data_with_proto_message_column_with_dml]\n";
}
// [END spanner_update_data_with_proto_message_column_with_dml]

// [START spanner_query_with_proto_message_parameter]
void QueryWithProtoMessageParameter(google::cloud::spanner::Client client) {
google::cloud::spanner::SqlStatement select(
"SELECT SingerId, SingerInfo, SingerInfoArray FROM Singers"
" WHERE SingerInfo.Nationality = @nationality",
{{"nationality", google::cloud::spanner::Value("British")}});
using SingerInfoMessage = google::cloud::spanner::ProtoMessage<
google::cloud::spanner::testing::SingerInfo>;
using RowType = std::tuple<std::int64_t, absl::optional<SingerInfoMessage>,
absl::optional<std::vector<SingerInfoMessage>>>;
auto rows = client.ExecuteQuery(std::move(select));
for (auto& row : google::cloud::spanner::StreamOf<RowType>(rows)) {
if (!row) throw std::move(row).status();
std::cout << "SingerId: " << std::get<0>(*row);
std::cout << ", SingerInfo: ";
auto singer_info = std::get<1>(*row);
if (!singer_info) {
std::cout << "NULL";
} else {
std::cout << *singer_info;
}
std::cout << ", SingerInfoArray: ";
auto singer_info_array = std::get<2>(*row);
if (!singer_info_array) {
std::cout << "NULL";
} else {
std::cout << "{";
char const* sep = " ";
for (auto const& singer_info : *singer_info_array) {
std::cout << sep << singer_info;
sep = ", ";
}
std::cout << " }";
}
std::cout << "\n";
}
std::cout << "Query completed for "
<< "[spanner_query_with_proto_message_parameter]\n";
}
// [END spanner_query_with_proto_message_parameter]

// [START spanner_update_data_with_proto_enum_column]
void UpdateDataWithProtoEnumColumn(google::cloud::spanner::Client client) {
using GenreEnum =
google::cloud::spanner::ProtoEnum<google::cloud::spanner::testing::Genre>;
auto singer_genre = GenreEnum(google::cloud::spanner::testing::Genre::FOLK);
auto commit_results =
client.CommitAtLeastOnce({google::cloud::spanner::Mutations{
google::cloud::spanner::InsertOrUpdateMutationBuilder(
"Singers", {"SingerId", "SingerGenre", "SingerGenreArray"})
.EmplaceRow(2, singer_genre, std::vector<GenreEnum>{singer_genre})
.EmplaceRow(3, absl::optional<GenreEnum>(),
absl::optional<std::vector<GenreEnum>>())
.Build()}});
for (auto& commit_result : commit_results) {
if (!commit_result) throw std::move(commit_result).status();
}
std::cout << "Update was successful "
<< "[spanner_update_data_with_proto_enum_column]\n";
}
// [END spanner_update_data_with_proto_enum_column]

// [START spanner_update_data_with_proto_enum_column_with_dml]
void UpdateDataWithProtoEnumColumnWithDml(
google::cloud::spanner::Client client) {
std::int64_t rows_modified = 0;
auto commit_result = client.Commit(
[&client, &rows_modified](google::cloud::spanner::Transaction txn)
-> google::cloud::StatusOr<google::cloud::spanner::Mutations> {
using GenreEnum = google::cloud::spanner::ProtoEnum<
google::cloud::spanner::testing::Genre>;
auto singer_genre =
GenreEnum(google::cloud::spanner::testing::Genre::ROCK);
auto update = client.ExecuteDml(
std::move(txn),
google::cloud::spanner::SqlStatement(
"UPDATE Singers"
" SET SingerGenre = @singer_genre,"
" SingerGenreArray = @singer_genre_array"
" WHERE SingerId = 1",
{{"singer_genre", google::cloud::spanner::Value(singer_genre)},
{"singer_genre_array",
google::cloud::spanner::Value(
std::vector<GenreEnum>{singer_genre})}}));
if (!update) return std::move(update).status();
rows_modified = update->RowsModified();
return google::cloud::spanner::Mutations{};
});
if (!commit_result) throw std::move(commit_result).status();
std::cout << "Updated " << rows_modified << " row(s) "
<< "[spanner_update_data_with_proto_enum_column_with_dml]\n";
}
// [END spanner_update_data_with_proto_enum_column_with_dml]

// [START spanner_query_with_proto_enum_parameter]
void QueryWithProtoEnumParameter(google::cloud::spanner::Client client) {
using GenreEnum =
google::cloud::spanner::ProtoEnum<google::cloud::spanner::testing::Genre>;
auto singer_genre = GenreEnum(google::cloud::spanner::testing::Genre::ROCK);
google::cloud::spanner::SqlStatement select(
"SELECT SingerId, SingerGenre, SingerGenreArray FROM Singers"
" WHERE SingerGenre = @singer_genre",
{{"singer_genre", google::cloud::spanner::Value(singer_genre)}});
using RowType = std::tuple<std::int64_t, absl::optional<GenreEnum>,
absl::optional<std::vector<GenreEnum>>>;
auto rows = client.ExecuteQuery(std::move(select));
for (auto& row : google::cloud::spanner::StreamOf<RowType>(rows)) {
if (!row) throw std::move(row).status();
std::cout << "SingerId: " << std::get<0>(*row);
std::cout << ", SingerGenre: ";
auto singer_genre = std::get<1>(*row);
if (!singer_genre) {
std::cout << "NULL";
} else {
std::cout << *singer_genre;
}
std::cout << ", SingerGenreArray: ";
auto singer_genre_array = std::get<2>(*row);
if (!singer_genre_array) {
std::cout << "NULL";
} else {
std::cout << "{";
char const* sep = " ";
for (auto const& singer_genre : *singer_genre_array) {
std::cout << sep << singer_genre;
sep = ", ";
}
std::cout << " }";
}
std::cout << "\n";
}
std::cout << "Query completed for "
<< "[spanner_query_with_proto_enum_parameter]\n";
}
// [END spanner_query_with_proto_enum_parameter]

void ExampleStatusOr(google::cloud::spanner::Client client) {
//! [example-status-or]
namespace spanner = ::google::cloud::spanner;
Expand Down Expand Up @@ -4292,6 +4553,7 @@ int RunOneCommand(std::vector<std::string> argv) {
make_database_command_entry("list-database-roles", ListDatabaseRoles),
make_database_command_entry("add-column", AddColumn),
make_database_command_entry("add-timestamp-column", AddTimestampColumn),
make_database_command_entry("drop-column", DropColumn),
{"list-databases", ListDatabasesCommand},
{"create-backup", CreateBackupCommand},
{"restore-database", RestoreDatabaseCommand},
Expand Down Expand Up @@ -4411,6 +4673,21 @@ int RunOneCommand(std::vector<std::string> argv) {
make_command_entry("make-delete-mutation", MakeDeleteMutation),
make_command_entry("query-information-schema-database-options",
QueryInformationSchemaDatabaseOptions),
make_database_command_entry("spanner_add_proto_type_columns",
AddProtoTypeColumns),
make_command_entry("spanner_update_data_with_proto_message_column",
UpdateDataWithProtoMessageColumn),
make_command_entry(
"spanner_update_data_with_proto_message_column_with_dml",
UpdateDataWithProtoMessageColumnWithDml),
make_command_entry("spanner_query_with_proto_message_parameter",
QueryWithProtoMessageParameter),
make_command_entry("spanner_update_data_with_proto_enum_column",
UpdateDataWithProtoEnumColumn),
make_command_entry("spanner_update_data_with_proto_enum_column_with_dml",
UpdateDataWithProtoEnumColumnWithDml),
make_command_entry("spanner_query_with_proto_enum_parameter",
QueryWithProtoEnumParameter),
};

static std::string usage_msg = [&argv, &commands] {
Expand Down Expand Up @@ -5231,6 +5508,44 @@ void RunAll(bool emulator) {
SampleBanner("spanner_drop_database");
DropDatabase(database_admin_client, project_id, instance_id, database_id);
}

if (!emulator) { // proto columns and enums
SampleBanner("spanner_create_database");
CreateDatabase(database_admin_client, project_id, instance_id, database_id);

SampleBanner("drop-column");
DropColumn(database_admin_client, project_id, instance_id, database_id);

SampleBanner("spanner_add_proto_type_columns");
AddProtoTypeColumns(database_admin_client, project_id, instance_id,
database_id);

client = MakeSampleClient(project_id, instance_id, database_id);

SampleBanner("insert-mutation-builder");
InsertMutationBuilder(client);

SampleBanner("spanner_update_data_with_proto_message_column");
UpdateDataWithProtoMessageColumn(client);

SampleBanner("spanner_update_data_with_proto_message_column_with_dml");
UpdateDataWithProtoMessageColumnWithDml(client);

SampleBanner("spanner_query_with_proto_message_parameter");
QueryWithProtoMessageParameter(client);

SampleBanner("spanner_update_data_with_proto_enum_column");
UpdateDataWithProtoEnumColumn(client);

SampleBanner("spanner_update_data_with_proto_enum_column_with_dml");
UpdateDataWithProtoEnumColumnWithDml(client);

SampleBanner("spanner_query_with_proto_enum_parameter");
QueryWithProtoEnumParameter(client);

SampleBanner("spanner_drop_database");
DropDatabase(database_admin_client, project_id, instance_id, database_id);
}
}

bool AutoRun() {
Expand Down

0 comments on commit 801cd33

Please sign in to comment.