Skip to content

Commit 42255e3

Browse files
committed
impl(v3): add generator support for bespoke WaitForConsistency method
1 parent 9429a07 commit 42255e3

9 files changed

Lines changed: 153 additions & 0 deletions

generator/generator_config.proto

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,21 @@ message ServiceConfiguration {
167167
// RPCs. If set to false (the default), a no-op resumption function will be
168168
// generated.
169169
bool omit_streaming_updater = 29;
170+
171+
message BespokeMethod {
172+
string name = 1;
173+
string return_type = 2;
174+
string parameters = 3;
175+
}
176+
177+
// Only added to maintain feature parity when migrating from the handwritten
178+
// Bigtable Table Admin class to the generated class. While some attempts were
179+
// made to generalize this feature, it currently only supports the
180+
// WaitForConsistency method. This functionality can be enhanced later if we
181+
// ever need to use this again.
182+
// The implementation for this method in the ConnectionImpl class is not
183+
// generated and must be handwritten in a separate .cc file.
184+
repeated BespokeMethod bespoke_methods = 30;
170185
}
171186

172187
message DiscoveryDocumentDefinedProduct {

generator/integration_tests/golden_config.textproto

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,13 @@ service {
5959
]
6060
override_service_config_yaml_name: "generator/integration_tests/test2.yaml"
6161
endpoint_location_style: LOCATION_OPTIONALLY_DEPENDENT
62+
bespoke_methods : [
63+
{
64+
name: "WaitForConsistency",
65+
return_type: "StatusOr<google::protobuf::Empty>",
66+
parameters: "(google::protobuf::Empty const& request, Options opts = {})"
67+
}
68+
]
6269
}
6370
6471
service {

generator/internal/client_generator.cc

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,51 @@
2121
#include "generator/internal/predicate_utils.h"
2222
#include "generator/internal/printer.h"
2323
#include "absl/strings/str_cat.h"
24+
#include "absl/strings/str_replace.h"
2425
#include "google/api/client.pb.h"
2526
#include <google/protobuf/descriptor.h>
2627

2728
namespace google {
2829
namespace cloud {
2930
namespace generator_internal {
31+
namespace {
32+
std::string FormatBespokeMethodComments(std::string const& method_name) {
33+
if (method_name == "WaitForConsistency") {
34+
return R"""(
35+
// clang-format off
36+
///
37+
/// Polls a table until it is consistent or the RetryPolicy is exhausted based
38+
/// on a consistency token, that is, if replication has caught up based on the
39+
/// provided conditions specified in the token and the check request.
40+
///
41+
/// @param request Unary RPCs, such as the one wrapped by this
42+
/// function, receive a single `request` proto message which includes all
43+
/// the inputs for the RPC. In this case, the proto message is a
44+
/// [google.bigtable.admin.v2.CheckConsistencyRequest].
45+
/// Proto messages are converted to C++ classes by Protobuf, using the
46+
/// [Protobuf mapping rules].
47+
/// @param opts Optional. Override the class-level options, such as retry and
48+
/// backoff policies.
49+
/// @return the result of the RPC. The response message type
50+
/// ([google.bigtable.admin.v2.CheckConsistencyResponse])
51+
/// is mapped to a C++ class using the [Protobuf mapping rules].
52+
/// If the request fails, the [`StatusOr`] contains the error details.
53+
///
54+
/// [Protobuf mapping rules]: https://protobuf.dev/reference/cpp/cpp-generated/
55+
/// [input iterator requirements]: https://en.cppreference.com/w/cpp/named_req/InputIterator
56+
/// [`std::string`]: https://en.cppreference.com/w/cpp/string/basic_string
57+
/// [`future`]: @ref google::cloud::future
58+
/// [`StatusOr`]: @ref google::cloud::StatusOr
59+
/// [`Status`]: @ref google::cloud::Status
60+
/// [google.bigtable.admin.v2.CheckConsistencyRequest]: @googleapis_reference_link{google/bigtable/admin/v2/bigtable_table_admin.proto#L909}
61+
/// [google.bigtable.admin.v2.CheckConsistencyResponse]: @googleapis_reference_link{google/bigtable/admin/v2/bigtable_table_admin.proto#L948}
62+
///
63+
// clang-format on
64+
)""";
65+
}
66+
return "";
67+
}
68+
} // namespace
3069

3170
ClientGenerator::ClientGenerator(
3271
google::protobuf::ServiceDescriptor const* service_descriptor,
@@ -380,6 +419,13 @@ R"""( std::unique_ptr<::google::cloud::AsyncStreamingReadWriteRpc<
380419
__FILE__, __LINE__);
381420
}
382421

422+
for (auto const& method : bespoke_methods()) {
423+
HeaderPrint("\n");
424+
HeaderPrint(FormatBespokeMethodComments(method.name()));
425+
HeaderPrint(absl::StrCat(method.return_type(), " ", method.name(),
426+
method.parameters(), ";"));
427+
}
428+
383429
HeaderPrint( // clang-format off
384430
"\n"
385431
" private:\n"
@@ -716,6 +762,19 @@ std::unique_ptr<::google::cloud::AsyncStreamingReadWriteRpc<
716762
__FILE__, __LINE__);
717763
}
718764

765+
for (auto const& method : bespoke_methods()) {
766+
CcPrint("\n");
767+
CcPrint(absl::StrCat(
768+
method.return_type(), R"""( $client_class_name$::)""", method.name(),
769+
absl::StrReplaceAll(method.parameters(), {{" = {}", ""}}),
770+
absl::StrFormat(R"""( {
771+
internal::OptionsSpan span(internal::MergeOptions(std::move(opts), options_));
772+
return connection_->%s(request);
773+
}
774+
)""",
775+
method.name())));
776+
}
777+
719778
CcCloseNamespaces();
720779
return {};
721780
}

generator/internal/codegen_utils.cc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,11 @@ void ProcessArgOmitRpc(
111111
ProcessRepeated("omit_rpc", "omitted_rpcs", command_line_args);
112112
}
113113

114+
void ProcessArgBespokeMethod(
115+
std::vector<std::pair<std::string, std::string>>& command_line_args) {
116+
ProcessRepeated("bespoke_method", "bespoke_methods", command_line_args);
117+
}
118+
114119
void ProcessArgServiceEndpointEnvVar(
115120
std::vector<std::pair<std::string, std::string>>& command_line_args) {
116121
auto service_endpoint_env_var =
@@ -269,6 +274,7 @@ ProcessCommandLineArgs(std::string const& parameters) {
269274
ProcessArgCopyrightYear(command_line_args);
270275
ProcessArgOmitService(command_line_args);
271276
ProcessArgOmitRpc(command_line_args);
277+
ProcessArgBespokeMethod(command_line_args);
272278
ProcessArgServiceEndpointEnvVar(command_line_args);
273279
ProcessArgEmulatorEndpointEnvVar(command_line_args);
274280
ProcessArgEndpointLocationStyle(command_line_args);

generator/internal/connection_generator.cc

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "generator/internal/pagination.h"
2020
#include "generator/internal/predicate_utils.h"
2121
#include "generator/internal/printer.h"
22+
#include "absl/strings/str_replace.h"
2223
#include "absl/strings/str_split.h"
2324
#include <google/protobuf/descriptor.h>
2425

@@ -315,6 +316,14 @@ class $connection_class_name$ {
315316
__FILE__, __LINE__);
316317
}
317318

319+
for (auto const& method : bespoke_methods()) {
320+
HeaderPrint("\n");
321+
HeaderPrint(absl::StrCat(
322+
"virtual ", method.return_type(), " ", method.name(),
323+
absl::StrReplaceAll(method.parameters(), {{", Options opts = {}", ""}}),
324+
";"));
325+
}
326+
318327
// close abstract interface Connection base class
319328
HeaderPrint("};\n");
320329

@@ -490,6 +499,26 @@ future<StatusOr<$response_type$>>
490499
__FILE__, __LINE__);
491500
}
492501

502+
for (auto const& method : bespoke_methods()) {
503+
CcPrint("\n");
504+
std::string make_return =
505+
absl::StrContains(method.return_type(), "future")
506+
? absl::StrCat("google::cloud::make_ready_", method.return_type())
507+
: method.return_type();
508+
509+
CcPrint(
510+
absl::StrCat(method.return_type(), R"""( $connection_class_name$::)""",
511+
method.name(),
512+
absl::StrReplaceAll(method.parameters(),
513+
{{" request, Options opts = {}", ""}}),
514+
" {\n",
515+
absl::StrFormat(R"""( return %s(
516+
Status(StatusCode::kUnimplemented, "not implemented"));
517+
}
518+
)""",
519+
make_return)));
520+
}
521+
493522
if (HasGenerateGrpcTransport()) {
494523
EmitFactoryFunctionDefinition(EndpointLocationStyle());
495524
}

generator/internal/connection_impl_generator.cc

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "generator/internal/predicate_utils.h"
2020
#include "generator/internal/printer.h"
2121
#include "absl/strings/str_cat.h"
22+
#include "absl/strings/str_replace.h"
2223
#include <google/protobuf/descriptor.h>
2324

2425
namespace google {
@@ -120,6 +121,14 @@ class $connection_class_name$Impl
120121
HeaderPrintMethod(method, __FILE__, __LINE__, AsyncMethodDeclaration());
121122
}
122123

124+
for (auto const& method : bespoke_methods()) {
125+
HeaderPrint("\n");
126+
HeaderPrint(absl::StrCat(
127+
method.return_type(), " ", method.name(),
128+
absl::StrReplaceAll(method.parameters(), {{", Options opts = {}", ""}}),
129+
" override;"));
130+
}
131+
123132
HeaderPrint(R"""(
124133
private:
125134
std::unique_ptr<google::cloud::BackgroundThreads> background_;

generator/internal/service_code_generator.cc

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -482,6 +482,20 @@ void ServiceCodeGenerator::SetMethods() {
482482
for (auto const& mixin_method : mixin_methods_) {
483483
methods_.emplace_back(mixin_method.method.get());
484484
}
485+
486+
auto bespoke_methods_var = service_vars_.find("bespoke_methods");
487+
if (bespoke_methods_var != service_vars_.end()) {
488+
auto methods = absl::StrSplit(bespoke_methods_var->second, ',');
489+
for (auto const& method : methods) {
490+
std::vector<std::string> pieces = absl::StrSplit(method, "@@");
491+
assert(pieces.size() == 3);
492+
cpp::generator::ServiceConfiguration::BespokeMethod bespoke_method;
493+
bespoke_method.set_name(SafeReplaceAll(pieces[0], "@", ","));
494+
bespoke_method.set_return_type(SafeReplaceAll(pieces[1], "@", ","));
495+
bespoke_method.set_parameters(SafeReplaceAll(pieces[2], "@", ","));
496+
bespoke_methods_.emplace_back(std::move(bespoke_method));
497+
}
498+
}
485499
}
486500

487501
std::string ServiceCodeGenerator::GetPbIncludeByTransport() const {

generator/internal/service_code_generator.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,10 @@ class ServiceCodeGenerator : public GeneratorInterface {
6868
std::string vars(std::string const& key) const;
6969
MethodDescriptorList const& methods() const { return methods_; }
7070
MethodDescriptorList const& async_methods() const { return async_methods_; }
71+
std::vector<cpp::generator::ServiceConfiguration::BespokeMethod> const&
72+
bespoke_methods() const {
73+
return bespoke_methods_;
74+
}
7175
void SetVars(absl::string_view header_path);
7276
VarsDictionary MergeServiceAndMethodVars(
7377
google::protobuf::MethodDescriptor const& method) const;
@@ -268,6 +272,8 @@ class ServiceCodeGenerator : public GeneratorInterface {
268272
bool pb_h_system_includes_ = false;
269273
MethodDescriptorList methods_;
270274
MethodDescriptorList async_methods_;
275+
std::vector<cpp::generator::ServiceConfiguration::BespokeMethod>
276+
bespoke_methods_;
271277
Printer header_;
272278
Printer cc_;
273279
std::vector<MixinMethod> mixin_methods_;

generator/standalone_main.cc

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,14 @@ std::vector<std::future<google::cloud::Status>> GenerateCodeFromProtos(
281281
args.emplace_back(absl::StrCat("--cpp_codegen_opt=omit_rpc=",
282282
SafeReplaceAll(omit_rpc, ",", "@")));
283283
}
284+
for (auto const& bespoke_method : service.bespoke_methods()) {
285+
args.emplace_back(absl::StrCat(
286+
"--cpp_codegen_opt=bespoke_method=",
287+
absl::StrJoin({SafeReplaceAll(bespoke_method.name(), ",", "@"),
288+
SafeReplaceAll(bespoke_method.return_type(), ",", "@"),
289+
SafeReplaceAll(bespoke_method.parameters(), ",", "@")},
290+
"@@")));
291+
}
284292
for (auto const& retry_code : service.retryable_status_codes()) {
285293
args.emplace_back("--cpp_codegen_opt=retry_status_code=" + retry_code);
286294
}

0 commit comments

Comments
 (0)