Skip to content

Commit 5b010b9

Browse files
authored
feat(sidekick): support aggregated pagination (#2432)
1 parent 4a3664a commit 5b010b9

File tree

4 files changed

+130
-2
lines changed

4 files changed

+130
-2
lines changed

internal/sidekick/internal/parser/disco_test.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,30 @@ func TestDisco_ParsePagination(t *testing.T) {
112112
}
113113
}
114114

115+
func TestDisco_ParsePaginationAggregate(t *testing.T) {
116+
model, err := ParseDisco(discoSourceFile, "", map[string]string{})
117+
if err != nil {
118+
t.Fatal(err)
119+
}
120+
updateMethodPagination(nil, model)
121+
wantID := "..machineTypes.aggregatedList"
122+
got, ok := model.State.MethodByID[wantID]
123+
if !ok {
124+
t.Fatalf("expected method %s in the API model", wantID)
125+
}
126+
wantPagination := &api.Field{
127+
Name: "pageToken",
128+
JSONName: "pageToken",
129+
ID: "..machineTypes.aggregatedListRequest.pageToken",
130+
Typez: api.STRING_TYPE,
131+
TypezID: "string",
132+
Optional: true,
133+
}
134+
if diff := cmp.Diff(wantPagination, got.Pagination, cmpopts.IgnoreFields(api.Field{}, "Documentation")); diff != "" {
135+
t.Errorf("mismatch (-want, +got):\n%s", diff)
136+
}
137+
}
138+
115139
func TestDisco_ParseDeprecatedEnum(t *testing.T) {
116140
model, err := ParseDisco(discoSourceFile, "", map[string]string{})
117141
if err != nil {

internal/sidekick/internal/parser/pagination.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,12 +122,16 @@ func paginationResponseItem(overrides []config.PaginationOverride, methodID stri
122122
return response.Fields[fieldIdx]
123123
}
124124

125+
var mapItems *api.Field
125126
for _, field := range response.Fields {
127+
if field.Map && mapItems == nil {
128+
mapItems = field
129+
}
126130
if field.Repeated && field.Typez == api.MESSAGE_TYPE {
127131
return field
128132
}
129133
}
130-
return nil
134+
return mapItems
131135
}
132136

133137
func paginationResponseNextPageToken(response *api.Message) *api.Field {

internal/sidekick/internal/parser/pagination_test.go

Lines changed: 91 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -536,7 +536,97 @@ func TestPaginationResponseErrors(t *testing.T) {
536536
}
537537
}
538538

539-
func TestPaginationResponseItem(t *testing.T) {
539+
func TestPaginationResponseItemMatching(t *testing.T) {
540+
for _, test := range []struct {
541+
Repeated bool
542+
Map bool
543+
Typez api.Typez
544+
Name string
545+
}{
546+
{false, true, api.MESSAGE_TYPE, "items"},
547+
{true, false, api.MESSAGE_TYPE, "items"},
548+
} {
549+
response := &api.Message{
550+
Name: "Response",
551+
ID: ".package.Response",
552+
Fields: []*api.Field{
553+
{
554+
Name: test.Name,
555+
JSONName: test.Name,
556+
Typez: test.Typez,
557+
Repeated: test.Repeated,
558+
Map: test.Map,
559+
},
560+
},
561+
}
562+
got := paginationResponseItem(nil, "package.Service.List", response)
563+
if diff := cmp.Diff(response.Fields[0], got); diff != "" {
564+
t.Errorf("mismatch (-want, +got):\n%s", diff)
565+
}
566+
}
567+
}
568+
569+
func TestPaginationResponseItemMatchingMany(t *testing.T) {
570+
for _, test := range []struct {
571+
Repeated bool
572+
Map bool
573+
}{
574+
{true, false},
575+
{false, true},
576+
} {
577+
response := &api.Message{
578+
Name: "Response",
579+
ID: ".package.Response",
580+
Fields: []*api.Field{
581+
{
582+
Name: "first",
583+
JSONName: "first",
584+
Typez: api.MESSAGE_TYPE,
585+
Repeated: test.Repeated,
586+
Map: test.Map,
587+
},
588+
{
589+
Name: "second",
590+
JSONName: "second",
591+
Typez: api.MESSAGE_TYPE,
592+
Repeated: test.Repeated,
593+
Map: test.Map,
594+
},
595+
},
596+
}
597+
got := paginationResponseItem(nil, "package.Service.List", response)
598+
if diff := cmp.Diff(response.Fields[0], got); diff != "" {
599+
t.Errorf("mismatch (-want, +got):\n%s", diff)
600+
}
601+
}
602+
}
603+
604+
func TestPaginationResponseItemMatchingPreferRepeatedOverMap(t *testing.T) {
605+
response := &api.Message{
606+
Name: "Response",
607+
ID: ".package.Response",
608+
Fields: []*api.Field{
609+
{
610+
Name: "map",
611+
JSONName: "map",
612+
Typez: api.MESSAGE_TYPE,
613+
Map: true,
614+
},
615+
{
616+
Name: "repeated",
617+
JSONName: "repeated",
618+
Typez: api.MESSAGE_TYPE,
619+
Repeated: true,
620+
},
621+
},
622+
}
623+
got := paginationResponseItem(nil, "package.Service.List", response)
624+
if diff := cmp.Diff(response.Fields[1], got); diff != "" {
625+
t.Errorf("mismatch (-want, +got):\n%s", diff)
626+
}
627+
}
628+
629+
func TestPaginationResponseItemNotMatching(t *testing.T) {
540630
overrides := []config.PaginationOverride{
541631
{ID: ".package.Service.List", ItemField: "--invalid--"},
542632
}

internal/sidekick/internal/rust/templates/common/message.mustache

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,11 +225,21 @@ impl wkt::message::Message for {{Codec.Name}} {
225225
#[doc(hidden)]
226226
impl gax::paginator::internal::PageableResponse for {{Codec.Name}} {
227227
{{#PageableItem}}
228+
{{^Map}}
228229
type PageItem = {{{Codec.PrimitiveFieldType}}};
229230
230231
fn items(self) -> std::vec::Vec<Self::PageItem> {
231232
self.{{{Codec.FieldName}}}
232233
}
234+
{{/Map}}
235+
{{#Map}}
236+
type PageItem = ({{Codec.KeyType}}, {{Codec.ValueType}});
237+
238+
fn items(self) -> std::vec::Vec<Self::PageItem> {
239+
use std::iter::{IntoIterator, Iterator};
240+
self.{{{Codec.FieldName}}}.into_iter().collect()
241+
}
242+
{{/Map}}
233243
234244
{{/PageableItem}}
235245
{{#NextPageToken}}

0 commit comments

Comments
 (0)