From ea68ba1e8e77686639c60be9397ef1bf889dfba5 Mon Sep 17 00:00:00 2001 From: dbolduc Date: Sat, 25 Jun 2022 17:43:27 -0400 Subject: [PATCH] feat(bigtable): instance name as a class --- google/cloud/bigtable/CMakeLists.txt | 3 + .../bigtable/bigtable_client_unit_tests.bzl | 1 + .../bigtable/google_cloud_cpp_bigtable.bzl | 2 + google/cloud/bigtable/instance_resource.cc | 57 ++++++++++++ google/cloud/bigtable/instance_resource.h | 86 +++++++++++++++++++ .../cloud/bigtable/instance_resource_test.cc | 85 ++++++++++++++++++ 6 files changed, 234 insertions(+) create mode 100644 google/cloud/bigtable/instance_resource.cc create mode 100644 google/cloud/bigtable/instance_resource.h create mode 100644 google/cloud/bigtable/instance_resource_test.cc diff --git a/google/cloud/bigtable/CMakeLists.txt b/google/cloud/bigtable/CMakeLists.txt index 59749ed3ac3b9..05eb9ba4c70cf 100644 --- a/google/cloud/bigtable/CMakeLists.txt +++ b/google/cloud/bigtable/CMakeLists.txt @@ -145,6 +145,8 @@ add_library( instance_config.cc instance_config.h instance_list_responses.h + instance_resource.cc + instance_resource.h instance_update_config.cc instance_update_config.h internal/admin_client_params.cc @@ -334,6 +336,7 @@ if (BUILD_TESTING) instance_admin_client_test.cc instance_admin_test.cc instance_config_test.cc + instance_resource_test.cc instance_update_config_test.cc internal/admin_client_params_test.cc internal/async_bulk_apply_test.cc diff --git a/google/cloud/bigtable/bigtable_client_unit_tests.bzl b/google/cloud/bigtable/bigtable_client_unit_tests.bzl index e6758c460cc8d..e3fb3393c91f5 100644 --- a/google/cloud/bigtable/bigtable_client_unit_tests.bzl +++ b/google/cloud/bigtable/bigtable_client_unit_tests.bzl @@ -32,6 +32,7 @@ bigtable_client_unit_tests = [ "iam_binding_test.cc", "iam_policy_test.cc", "idempotent_mutation_policy_test.cc", + "instance_resource_test.cc", "instance_admin_client_test.cc", "instance_admin_test.cc", "instance_config_test.cc", diff --git a/google/cloud/bigtable/google_cloud_cpp_bigtable.bzl b/google/cloud/bigtable/google_cloud_cpp_bigtable.bzl index 1c1d024b9dc65..e883728e32def 100644 --- a/google/cloud/bigtable/google_cloud_cpp_bigtable.bzl +++ b/google/cloud/bigtable/google_cloud_cpp_bigtable.bzl @@ -57,6 +57,7 @@ google_cloud_cpp_bigtable_hdrs = [ "iam_binding.h", "iam_policy.h", "idempotent_mutation_policy.h", + "instance_resource.h", "instance_admin.h", "instance_admin_client.h", "instance_config.h", @@ -150,6 +151,7 @@ google_cloud_cpp_bigtable_srcs = [ "iam_binding.cc", "iam_policy.cc", "idempotent_mutation_policy.cc", + "instance_resource.cc", "instance_admin.cc", "instance_admin_client.cc", "instance_config.cc", diff --git a/google/cloud/bigtable/instance_resource.cc b/google/cloud/bigtable/instance_resource.cc new file mode 100644 index 0000000000000..a55c17b349b91 --- /dev/null +++ b/google/cloud/bigtable/instance_resource.cc @@ -0,0 +1,57 @@ +// 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/instance_resource.h" +#include +#include + +namespace google { +namespace cloud { +namespace bigtable { +GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN + +InstanceResource::InstanceResource(Project project, std::string instance_id) + : project_(std::move(project)), instance_id_(std::move(instance_id)) {} + +std::string InstanceResource::FullName() const { + return project_.FullName() + "/instances/" + instance_id_; +} + +bool operator==(InstanceResource const& a, InstanceResource const& b) { + return a.project_ == b.project_ && a.instance_id_ == b.instance_id_; +} + +bool operator!=(InstanceResource const& a, InstanceResource const& b) { + return !(a == b); +} + +std::ostream& operator<<(std::ostream& os, InstanceResource const& in) { + return os << in.FullName(); +} + +StatusOr MakeInstanceResource(std::string const& full_name) { + std::regex re("projects/([^/]+)/instances/([^/]+)"); + std::smatch matches; + if (!std::regex_match(full_name, matches, re)) { + return Status(StatusCode::kInvalidArgument, + "Improperly formatted InstanceResource: " + full_name); + } + return InstanceResource(Project(std::move(matches[1])), + std::move(matches[2])); +} + +GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END +} // namespace bigtable +} // namespace cloud +} // namespace google diff --git a/google/cloud/bigtable/instance_resource.h b/google/cloud/bigtable/instance_resource.h new file mode 100644 index 0000000000000..7e6400ebb814d --- /dev/null +++ b/google/cloud/bigtable/instance_resource.h @@ -0,0 +1,86 @@ +// 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_INSTANCE_RESOURCE_H +#define GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_BIGTABLE_INSTANCE_RESOURCE_H + +#include "google/cloud/bigtable/version.h" +#include "google/cloud/project.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 Instance. + * + * A Cloud Bigtable instance is identified by its `project_id` and + * `instance_id`. + * + * @note This class makes no effort to validate the components of the + * database name. It is the application's responsibility to provide valid + * project, and instance ids. Passing invalid values will not be checked + * until the instance name is used in an RPC to Bigtable. + */ +class InstanceResource { + public: + /** + * Constructs an InstanceResource object identified by the given @p project + * and @p instance_id. + */ + InstanceResource(Project project, std::string instance_id); + + /// Returns the `Project` containing this instance. + Project const& project() const { return project_; } + std::string const& project_id() const { return project_.project_id(); } + + /// Returns the Instance ID. + std::string const& instance_id() const { return instance_id_; } + + /** + * Returns the fully qualified instance name as a string of the form: + * "projects//instances/" + */ + std::string FullName() const; + + /// @name Equality operators + //@{ + friend bool operator==(InstanceResource const& a, InstanceResource const& b); + friend bool operator!=(InstanceResource const& a, InstanceResource const& b); + //@} + + /// Output the `FullName()` format. + friend std::ostream& operator<<(std::ostream&, InstanceResource const&); + + private: + Project project_; + std::string instance_id_; +}; + +/** + * Constructs an `InstanceResource` from the given @p full_name. + * Returns a non-OK Status if `full_name` is improperly formed. + */ +StatusOr MakeInstanceResource(std::string const& full_name); + +GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END +} // namespace bigtable +} // namespace cloud +} // namespace google + +#endif // GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_BIGTABLE_INSTANCE_RESOURCE_H diff --git a/google/cloud/bigtable/instance_resource_test.cc b/google/cloud/bigtable/instance_resource_test.cc new file mode 100644 index 0000000000000..ba9c53dd68f15 --- /dev/null +++ b/google/cloud/bigtable/instance_resource_test.cc @@ -0,0 +1,85 @@ +// 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/instance_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(InstanceResource, Basics) { + InstanceResource in(Project("p1"), "i1"); + EXPECT_EQ("p1", in.project_id()); + EXPECT_EQ("i1", in.instance_id()); + EXPECT_EQ("projects/p1/instances/i1", in.FullName()); + + auto copy = in; + EXPECT_EQ(copy, in); + EXPECT_EQ("p1", copy.project_id()); + EXPECT_EQ("i1", copy.instance_id()); + EXPECT_EQ("projects/p1/instances/i1", copy.FullName()); + + auto moved = std::move(copy); + EXPECT_EQ(moved, in); + EXPECT_EQ("p1", moved.project_id()); + EXPECT_EQ("i1", moved.instance_id()); + EXPECT_EQ("projects/p1/instances/i1", moved.FullName()); + + InstanceResource in2(Project("p2"), "i2"); + EXPECT_NE(in2, in); + EXPECT_EQ("p2", in2.project_id()); + EXPECT_EQ("i2", in2.instance_id()); + EXPECT_EQ("projects/p2/instances/i2", in2.FullName()); +} + +TEST(InstanceResource, OutputStream) { + InstanceResource in(Project("p1"), "i1"); + std::ostringstream os; + os << in; + EXPECT_EQ("projects/p1/instances/i1", os.str()); +} + +TEST(InstanceResource, MakeInstanceResource) { + auto in = InstanceResource(Project("p1"), "i1"); + EXPECT_EQ(in, MakeInstanceResource(in.FullName()).value()); + + for (std::string invalid : { + "", + "projects/", + "projects/p1", + "projects/p1/instances/", + "/projects/p1/instances/i1", + "projects/p1/instances/i1/", + "projects/p1/instances/i1/etc", + }) { + auto in = MakeInstanceResource(invalid); + EXPECT_THAT(in, + StatusIs(StatusCode::kInvalidArgument, + "Improperly formatted InstanceResource: " + invalid)); + } +} + +} // namespace +GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END +} // namespace bigtable +} // namespace cloud +} // namespace google