Skip to content

Commit f7a7c8e

Browse files
authored
feat(sidekick): add paginator for services proto wrap maxResults (#2208)
1 parent 2a20b7c commit f7a7c8e

File tree

3 files changed

+145
-4
lines changed

3 files changed

+145
-4
lines changed

internal/sidekick/internal/parser/pagination.go

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@
1414

1515
package parser
1616

17-
import "github.com/googleapis/librarian/internal/sidekick/internal/api"
17+
import (
18+
"github.com/googleapis/librarian/internal/sidekick/internal/api"
19+
)
1820

1921
const (
2022
pageSize = "pageSize"
@@ -41,15 +43,16 @@ func updateMethodPagination(a *api.API) {
4143
// Some legacy services (e.g. sqladmin.googleapis.com)
4244
// predate AIP-4233 and use `maxResults` instead of
4345
// `pageSize` for the field name.
44-
// Furthermore, some of these services use both
45-
// `uint32` and `int32` for the `maxResults` field type.
4646
switch f.JSONName {
4747
case pageSize:
4848
if f.Typez == api.INT32_TYPE {
4949
hasPageSize = true
5050
}
5151
case maxResults:
52-
if f.Typez == api.INT32_TYPE || f.Typez == api.UINT32_TYPE {
52+
// Legacy maxResults types can be int32/uint32, and protobuf wrappers Int32Value/UInt32Value.
53+
if f.Typez == api.INT32_TYPE || f.Typez == api.UINT32_TYPE ||
54+
(f.Typez == api.MESSAGE_TYPE &&
55+
(f.TypezID == ".google.protobuf.Int32Value" || f.TypezID == ".google.protobuf.UInt32Value")) {
5356
hasPageSize = true
5457
}
5558
}

internal/sidekick/internal/parser/protobuf_test.go

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1174,6 +1174,83 @@ func TestProtobuf_Pagination(t *testing.T) {
11741174
Behavior: []api.FieldBehavior{api.FIELD_BEHAVIOR_OPTIONAL},
11751175
},
11761176
},
1177+
{
1178+
Name: "ListFooWithMaxResultsUInt32Value",
1179+
ID: ".test.TestService.ListFooWithMaxResultsUInt32Value",
1180+
SourceServiceID: ".test.TestService",
1181+
InputTypeID: ".test.ListFooMaxResultsUInt32ValueRequest",
1182+
OutputTypeID: ".test.ListFooResponse",
1183+
PathInfo: &api.PathInfo{
1184+
Bindings: []*api.PathBinding{
1185+
{
1186+
Verb: "GET",
1187+
PathTemplate: api.NewPathTemplate().
1188+
WithLiteral("v1").
1189+
WithVariable(api.NewPathVariable("parent").
1190+
WithLiteral("projects").
1191+
WithMatch()).
1192+
WithLiteral("foos"),
1193+
QueryParameters: map[string]bool{"max_results": true, "page_token": true},
1194+
},
1195+
},
1196+
},
1197+
Pagination: &api.Field{
1198+
Name: "page_token",
1199+
ID: ".test.ListFooMaxResultsUInt32ValueRequest.page_token",
1200+
Typez: 9,
1201+
JSONName: "pageToken",
1202+
Behavior: []api.FieldBehavior{api.FIELD_BEHAVIOR_OPTIONAL},
1203+
},
1204+
},
1205+
{
1206+
Name: "ListFooWithMaxResultsInt32Value",
1207+
ID: ".test.TestService.ListFooWithMaxResultsInt32Value",
1208+
SourceServiceID: ".test.TestService",
1209+
InputTypeID: ".test.ListFooMaxResultsInt32ValueRequest",
1210+
OutputTypeID: ".test.ListFooResponse",
1211+
PathInfo: &api.PathInfo{
1212+
Bindings: []*api.PathBinding{
1213+
{
1214+
Verb: "GET",
1215+
PathTemplate: api.NewPathTemplate().
1216+
WithLiteral("v1").
1217+
WithVariable(api.NewPathVariable("parent").
1218+
WithLiteral("projects").
1219+
WithMatch()).
1220+
WithLiteral("foos"),
1221+
QueryParameters: map[string]bool{"max_results": true, "page_token": true},
1222+
},
1223+
},
1224+
},
1225+
Pagination: &api.Field{
1226+
Name: "page_token",
1227+
ID: ".test.ListFooMaxResultsInt32ValueRequest.page_token",
1228+
Typez: 9,
1229+
JSONName: "pageToken",
1230+
Behavior: []api.FieldBehavior{api.FIELD_BEHAVIOR_OPTIONAL},
1231+
},
1232+
},
1233+
{
1234+
Name: "ListFooWithMaxResultsIncorrectMessageType",
1235+
ID: ".test.TestService.ListFooWithMaxResultsIncorrectMessageType",
1236+
SourceServiceID: ".test.TestService",
1237+
InputTypeID: ".test.ListFooMaxResultIncorrectMessageTypeRequest",
1238+
OutputTypeID: ".test.ListFooResponse",
1239+
PathInfo: &api.PathInfo{
1240+
Bindings: []*api.PathBinding{
1241+
{
1242+
Verb: "GET",
1243+
PathTemplate: api.NewPathTemplate().
1244+
WithLiteral("v1").
1245+
WithVariable(api.NewPathVariable("parent").
1246+
WithLiteral("projects").
1247+
WithMatch()).
1248+
WithLiteral("foos"),
1249+
QueryParameters: map[string]bool{"max_results": true, "page_token": true},
1250+
},
1251+
},
1252+
},
1253+
},
11771254
{
11781255
Name: "ListFooMissingNextPageToken",
11791256
ID: ".test.TestService.ListFooMissingNextPageToken",

internal/sidekick/internal/parser/testdata/pagination.proto

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import "google/api/annotations.proto";
1919
import "google/api/client.proto";
2020
import "google/api/field_behavior.proto";
2121
import "google/api/resource.proto";
22+
import "google/protobuf/wrappers.proto";
2223

2324
service TestService {
2425
option (google.api.default_host) = "test.googleapis.com";
@@ -73,6 +74,27 @@ service TestService {
7374
};
7475
option (google.api.method_signature) = "parent";
7576
}
77+
78+
rpc ListFooWithMaxResultsUInt32Value(ListFooMaxResultsUInt32ValueRequest) returns (ListFooResponse) {
79+
option (google.api.http) = {
80+
get: "/v1/{parent=projects/*}/foos"
81+
};
82+
option (google.api.method_signature) = "parent";
83+
}
84+
85+
rpc ListFooWithMaxResultsInt32Value(ListFooMaxResultsInt32ValueRequest) returns (ListFooResponse) {
86+
option (google.api.http) = {
87+
get: "/v1/{parent=projects/*}/foos"
88+
};
89+
option (google.api.method_signature) = "parent";
90+
}
91+
92+
rpc ListFooWithMaxResultsIncorrectMessageType(ListFooMaxResultIncorrectMessageTypeRequest) returns (ListFooResponse) {
93+
option (google.api.http) = {
94+
get: "/v1/{parent=projects/*}/foos"
95+
};
96+
option (google.api.method_signature) = "parent";
97+
}
7698
}
7799

78100
message ListFooMissingPageSizeRequest {
@@ -136,6 +158,45 @@ message ListFooMaxResultsUInt32Request {
136158
string page_token = 3 [(google.api.field_behavior) = OPTIONAL];
137159
}
138160

161+
message ListFooMaxResultsInt32ValueRequest {
162+
string parent = 1 [
163+
(google.api.field_behavior) = REQUIRED,
164+
(google.api.resource_reference) = {
165+
child_type: "test.googleapis.com/Foo"
166+
}
167+
];
168+
169+
google.protobuf.Int32Value max_results = 2 [(google.api.field_behavior) = OPTIONAL];
170+
171+
string page_token = 3 [(google.api.field_behavior) = OPTIONAL];
172+
}
173+
174+
message ListFooMaxResultsUInt32ValueRequest {
175+
string parent = 1 [
176+
(google.api.field_behavior) = REQUIRED,
177+
(google.api.resource_reference) = {
178+
child_type: "test.googleapis.com/Foo"
179+
}
180+
];
181+
182+
google.protobuf.UInt32Value max_results = 2 [(google.api.field_behavior) = OPTIONAL];
183+
184+
string page_token = 3 [(google.api.field_behavior) = OPTIONAL];
185+
}
186+
187+
message ListFooMaxResultIncorrectMessageTypeRequest {
188+
string parent = 1 [
189+
(google.api.field_behavior) = REQUIRED,
190+
(google.api.resource_reference) = {
191+
child_type: "test.googleapis.com/Foo"
192+
}
193+
];
194+
195+
google.protobuf.StringValue max_results = 2 [(google.api.field_behavior) = OPTIONAL];
196+
197+
string page_token = 3 [(google.api.field_behavior) = OPTIONAL];
198+
}
199+
139200
message ListFooMissingNextPageTokenResponse {
140201
repeated Foo foos = 1;
141202

0 commit comments

Comments
 (0)