diff --git a/google/cloud/bigtable/CMakeLists.txt b/google/cloud/bigtable/CMakeLists.txt index 05eb9ba4c70cf..60290e65f356c 100644 --- a/google/cloud/bigtable/CMakeLists.txt +++ b/google/cloud/bigtable/CMakeLists.txt @@ -239,6 +239,8 @@ add_library( table_admin.h table_config.cc table_config.h + table_resource.cc + table_resource.h version.cc version.h version_info.h @@ -381,6 +383,7 @@ if (BUILD_TESTING) table_readmodifywriterow_test.cc table_readrow_test.cc table_readrows_test.cc + table_resource_test.cc table_sample_row_keys_test.cc table_test.cc testing/cleanup_stale_resources_test.cc diff --git a/google/cloud/bigtable/bigtable_client_unit_tests.bzl b/google/cloud/bigtable/bigtable_client_unit_tests.bzl index 783e8c04e212c..be3bcab35cb78 100644 --- a/google/cloud/bigtable/bigtable_client_unit_tests.bzl +++ b/google/cloud/bigtable/bigtable_client_unit_tests.bzl @@ -80,6 +80,7 @@ bigtable_client_unit_tests = [ "table_readmodifywriterow_test.cc", "table_readrow_test.cc", "table_readrows_test.cc", + "table_resource_test.cc", "table_sample_row_keys_test.cc", "table_test.cc", "testing/cleanup_stale_resources_test.cc", diff --git a/google/cloud/bigtable/google_cloud_cpp_bigtable.bzl b/google/cloud/bigtable/google_cloud_cpp_bigtable.bzl index fcb5fa5e3be73..8b2875f04e52a 100644 --- a/google/cloud/bigtable/google_cloud_cpp_bigtable.bzl +++ b/google/cloud/bigtable/google_cloud_cpp_bigtable.bzl @@ -115,6 +115,7 @@ google_cloud_cpp_bigtable_hdrs = [ "table.h", "table_admin.h", "table_config.h", + "table_resource.h", "version.h", "version_info.h", "wait_for_consistency.h", @@ -194,6 +195,7 @@ google_cloud_cpp_bigtable_srcs = [ "table.cc", "table_admin.cc", "table_config.cc", + "table_resource.cc", "version.cc", "wait_for_consistency.cc", ] diff --git a/google/cloud/bigtable/table_resource.cc b/google/cloud/bigtable/table_resource.cc new file mode 100644 index 0000000000000..42c70a59d32be --- /dev/null +++ b/google/cloud/bigtable/table_resource.cc @@ -0,0 +1,58 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "google/cloud/bigtable/table_resource.h" +#include +#include + +namespace google { +namespace cloud { +namespace bigtable { +GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN + +TableResource::TableResource(InstanceResource instance, std::string table_id) + : instance_(std::move(instance)), table_id_(std::move(table_id)) {} + +std::string TableResource::FullName() const { + return instance_.FullName() + "/tables/" + table_id_; +} + +bool operator==(TableResource const& a, TableResource const& b) { + return a.instance_ == b.instance_ && a.table_id_ == b.table_id_; +} + +bool operator!=(TableResource const& a, TableResource const& b) { + return !(a == b); +} + +std::ostream& operator<<(std::ostream& os, TableResource const& db) { + return os << db.FullName(); +} + +StatusOr MakeTableResource(std::string const& full_name) { + std::regex re("projects/([^/]+)/instances/([^/]+)/tables/([^/]+)"); + std::smatch matches; + if (!std::regex_match(full_name, matches, re)) { + return Status(StatusCode::kInvalidArgument, + "Improperly formatted TableResource: " + full_name); + } + return TableResource( + InstanceResource(Project(std::move(matches[1])), std::move(matches[2])), + std::move(matches[3])); +} + +GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END +} // namespace bigtable +} // namespace cloud +} // namespace google diff --git a/google/cloud/bigtable/table_resource.h b/google/cloud/bigtable/table_resource.h new file mode 100644 index 0000000000000..3b2f917076cc3 --- /dev/null +++ b/google/cloud/bigtable/table_resource.h @@ -0,0 +1,89 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_BIGTABLE_TABLE_RESOURCE_H +#define GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_BIGTABLE_TABLE_RESOURCE_H + +#include "google/cloud/bigtable/instance_resource.h" +#include "google/cloud/bigtable/version.h" +#include "google/cloud/status_or.h" +#include +#include + +namespace google { +namespace cloud { +namespace bigtable { +GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN + +/** + * This class identifies a Cloud Bigtable Table. + * + * Bigtable stores data in massively scalable tables, each of which is a sorted + * key/value map. A Cloud Bigtable table is identified by the instance it is + * contained in and its `table_id`. + * + * @note This class makes no effort to validate the components of the + * table name. It is the application's responsibility to provide valid + * project, instance, and table ids. Passing invalid values will not be + * checked until the table name is used in a RPC to Bigtable. + * + * @see https://cloud.google.com/bigtable/docs/overview for an overview of the + * Cloud Bigtable data model. + */ +class TableResource { + public: + /** + * Constructs a TableResource object identified by the given @p instance and + * @p table_id. + */ + TableResource(InstanceResource instance, std::string table_id); + + /// Returns the `InstanceResource` containing this table. + InstanceResource const& instance() const { return instance_; } + + /// Returns the Table ID. + std::string const& table_id() const { return table_id_; } + + /** + * Returns the fully qualified table name as a string of the form: + * "projects//instances//tables/" + */ + std::string FullName() const; + + /// @name Equality operators + //@{ + friend bool operator==(TableResource const& a, TableResource const& b); + friend bool operator!=(TableResource const& a, TableResource const& b); + //@} + + /// Output the `FullName()` format. + friend std::ostream& operator<<(std::ostream&, TableResource const&); + + private: + InstanceResource instance_; + std::string table_id_; +}; + +/** + * Constructs a `TableResource` from the given @p full_name. + * Returns a non-OK Status if `full_name` is improperly formed. + */ +StatusOr MakeTableResource(std::string const& full_name); + +GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END +} // namespace bigtable +} // namespace cloud +} // namespace google + +#endif // GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_BIGTABLE_TABLE_RESOURCE_H diff --git a/google/cloud/bigtable/table_resource_test.cc b/google/cloud/bigtable/table_resource_test.cc new file mode 100644 index 0000000000000..cd8d9c30da177 --- /dev/null +++ b/google/cloud/bigtable/table_resource_test.cc @@ -0,0 +1,90 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "google/cloud/bigtable/table_resource.h" +#include "google/cloud/testing_util/status_matchers.h" +#include +#include +#include + +namespace google { +namespace cloud { +namespace bigtable { +GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN +namespace { + +using ::google::cloud::testing_util::StatusIs; + +TEST(TableResource, Basics) { + InstanceResource in(Project("p1"), "i1"); + TableResource tr(in, "t1"); + EXPECT_EQ("t1", tr.table_id()); + EXPECT_EQ(in, tr.instance()); + EXPECT_EQ("projects/p1/instances/i1/tables/t1", tr.FullName()); + + auto copy = tr; + EXPECT_EQ(copy, tr); + EXPECT_EQ("t1", copy.table_id()); + EXPECT_EQ(in, copy.instance()); + EXPECT_EQ("projects/p1/instances/i1/tables/t1", copy.FullName()); + + auto moved = std::move(copy); + EXPECT_EQ(moved, tr); + EXPECT_EQ("t1", moved.table_id()); + EXPECT_EQ(in, moved.instance()); + EXPECT_EQ("projects/p1/instances/i1/tables/t1", moved.FullName()); + + InstanceResource in2(Project("p2"), "i2"); + TableResource tr2(in2, "t2"); + EXPECT_NE(tr2, tr); + EXPECT_EQ("t2", tr2.table_id()); + EXPECT_EQ(in2, tr2.instance()); + EXPECT_EQ("projects/p2/instances/i2/tables/t2", tr2.FullName()); +} + +TEST(TableResource, OutputStream) { + InstanceResource in(Project("p1"), "i1"); + TableResource tr(in, "t1"); + std::ostringstream os; + os << tr; + EXPECT_EQ("projects/p1/instances/i1/tables/t1", os.str()); +} + +TEST(TableResource, MakeTableResource) { + auto tr = TableResource(InstanceResource(Project("p1"), "i1"), "t1"); + EXPECT_EQ(tr, MakeTableResource(tr.FullName()).value()); + + for (std::string invalid : { + "", + "projects/", + "projects/p1", + "projects/p1/instances/", + "projects/p1/instances/i1", + "projects/p1/instances/i1/tables", + "projects/p1/instances/i1/tables/", + "/projects/p1/instances/i1/tables/t1", + "projects/p1/instances/i1/tables/t1/", + "projects/p1/instances/i1/tables/t1/etc", + }) { + auto tr = MakeTableResource(invalid); + EXPECT_THAT(tr, StatusIs(StatusCode::kInvalidArgument, + "Improperly formatted TableResource: " + invalid)); + } +} + +} // namespace +GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END +} // namespace bigtable +} // namespace cloud +} // namespace google