This is an automated email from the ASF dual-hosted git repository.
zeroshade pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/iceberg-go.git
The following commit(s) were added to refs/heads/main by this push:
new 3ce3b4bb fix(table): add pagination support to ListNamespaces (#694)
3ce3b4bb is described below
commit 3ce3b4bb51c0aa060d2bf6826dbbfd453c8067f9
Author: Sumisha <[email protected]>
AuthorDate: Fri Jan 23 23:31:46 2026 +0530
fix(table): add pagination support to ListNamespaces (#694)
Change ListNamespaces to support pagination.
---
catalog/rest/rest.go | 38 ++++++++++++++++++++++++++++++----
catalog/rest/rest_test.go | 52 +++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 86 insertions(+), 4 deletions(-)
diff --git a/catalog/rest/rest.go b/catalog/rest/rest.go
index 0a7e4700..e0d1c94b 100644
--- a/catalog/rest/rest.go
+++ b/catalog/rest/rest.go
@@ -997,23 +997,53 @@ func (r *Catalog) DropNamespace(ctx context.Context,
namespace table.Identifier)
}
func (r *Catalog) ListNamespaces(ctx context.Context, parent table.Identifier)
([]table.Identifier, error) {
+ var allNamespaces []table.Identifier
+ pageSize := r.getPageSize(ctx)
+ var pageToken string
+
+ for {
+ namespaces, nextPageToken, err := r.listNamespacesPage(ctx,
parent, pageToken, pageSize)
+ if err != nil {
+ return nil, err
+ }
+ allNamespaces = append(allNamespaces, namespaces...)
+ if nextPageToken == "" {
+ break
+ }
+ pageToken = nextPageToken
+ }
+
+ return allNamespaces, nil
+}
+
+func (r *Catalog) listNamespacesPage(ctx context.Context, parent
table.Identifier, pageToken string, pageSize int) ([]table.Identifier, string,
error) {
uri := r.baseURI.JoinPath("namespaces")
+
+ v := url.Values{}
if len(parent) != 0 {
- v := url.Values{}
v.Set("parent", strings.Join(parent, namespaceSeparator))
+ }
+ if pageSize >= 0 {
+ v.Set("pageSize", strconv.Itoa(pageSize))
+ }
+ if pageToken != "" {
+ v.Set("pageToken", pageToken)
+ }
+ if len(v) > 0 {
uri.RawQuery = v.Encode()
}
type rsptype struct {
- Namespaces []table.Identifier `json:"namespaces"`
+ Namespaces []table.Identifier `json:"namespaces"`
+ NextPageToken string
`json:"next-page-token,omitempty"`
}
rsp, err := doGet[rsptype](ctx, uri, []string{}, r.cl,
map[int]error{http.StatusNotFound: catalog.ErrNoSuchNamespace})
if err != nil {
- return nil, err
+ return nil, "", err
}
- return rsp.Namespaces, nil
+ return rsp.Namespaces, rsp.NextPageToken, nil
}
func (r *Catalog) LoadNamespaceProperties(ctx context.Context, namespace
table.Identifier) (iceberg.Properties, error) {
diff --git a/catalog/rest/rest_test.go b/catalog/rest/rest_test.go
index 5216d6be..91ae11c8 100644
--- a/catalog/rest/rest_test.go
+++ b/catalog/rest/rest_test.go
@@ -747,6 +747,58 @@ func (r *RestCatalogSuite) TestListNamespaces400() {
r.ErrorContains(err, "Namespace does not exist: personal in warehouse
8bcb0838-50fc-472d-9ddb-8feb89ef5f1e")
}
+func (r *RestCatalogSuite) TestListNamespacesPagination() {
+ // Track the number of requests and page tokens received
+ requestCount := 0
+
+ r.mux.HandleFunc("/v1/namespaces", func(w http.ResponseWriter, req
*http.Request) {
+ r.Require().Equal(http.MethodGet, req.Method)
+
+ for k, v := range TestHeaders {
+ r.Equal(v, req.Header.Values(k))
+ }
+
+ pageToken := req.URL.Query().Get("pageToken")
+ requestCount++
+
+ switch requestCount {
+ case 1:
+ // First request - no pageToken expected
+ r.Empty(pageToken)
+ json.NewEncoder(w).Encode(map[string]any{
+ "namespaces": []table.Identifier{{"ns1"},
{"ns2"}},
+ "next-page-token": "token1",
+ })
+ case 2:
+ // Second request - expect token1
+ r.Equal("token1", pageToken)
+ json.NewEncoder(w).Encode(map[string]any{
+ "namespaces": []table.Identifier{{"ns3"},
{"ns4"}},
+ "next-page-token": "token2",
+ })
+ case 3:
+ // Third request - expect token2, no next token (last
page)
+ r.Equal("token2", pageToken)
+ json.NewEncoder(w).Encode(map[string]any{
+ "namespaces": []table.Identifier{{"ns5"}},
+ })
+ default:
+ r.Fail("unexpected request count: %d", requestCount)
+ }
+ })
+
+ cat, err := rest.NewCatalog(context.Background(), "rest", r.srv.URL,
rest.WithOAuthToken(TestToken))
+ r.Require().NoError(err)
+
+ results, err := cat.ListNamespaces(context.Background(), nil)
+ r.Require().NoError(err)
+
+ // Verify all namespaces from all pages are returned
+ r.Equal([]table.Identifier{{"ns1"}, {"ns2"}, {"ns3"}, {"ns4"},
{"ns5"}}, results)
+ // Verify 3 requests were made (3 pages)
+ r.Equal(3, requestCount)
+}
+
func (r *RestCatalogSuite) TestCreateNamespace200() {
r.mux.HandleFunc("/v1/namespaces", func(w http.ResponseWriter, req
*http.Request) {
r.Require().Equal(http.MethodPost, req.Method)