Verified Commit 90fce726 authored by Zubeen's avatar Zubeen 🤖 Committed by GitLab
Browse files

fix(pagination): stop ScanAndCollectN before fetching an unneeded page

Changelog: Improvements
parent 7f1dadc7
Loading
Loading
Loading
Loading
+8 −3
Changes for pagination.go: 8 added lines, 3 removed lines.
Original line number Diff line number Diff line
@@ -185,6 +185,10 @@ func ScanAndCollect[T any](f func(p PaginationOptionFunc) ([]T, *Response, error
// Attention: This API is experimental and may be subject to breaking changes to
// improve the API in the future.
func ScanAndCollectN[T any](f func(p PaginationOptionFunc) ([]T, *Response, error), n int) ([]T, error) {
	if n == 0 {
		return nil, nil
	}

	var items []T

	for item, err := range Scan2(f) {
@@ -192,11 +196,12 @@ func ScanAndCollectN[T any](f func(p PaginationOptionFunc) ([]T, *Response, erro
			return nil, err
		}

		if n >= 0 && len(items) >= n {
		items = append(items, item)

		// Stop once n items are collected, so no further page is requested.
		if n > 0 && len(items) >= n {
			break
		}

		items = append(items, item)
	}

	return items, nil
+38 −0
Changes for pagination_test.go: 38 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -215,6 +215,44 @@ func TestPagination_ScanAndCollectN_Zero(t *testing.T) {
	assert.Nil(t, projects)
}

func TestPagination_ScanAndCollectN_StopsBeforeNextPage(t *testing.T) {
	t.Parallel()

	// GIVEN a list endpoint whose second page fails
	mux, client := setup(t)
	handleTwoPagesWithFailure(t, mux)

	// WHEN collecting only as many items as the first page holds
	opt := &ListProjectsOptions{}
	projects, err := ScanAndCollectN(func(p PaginationOptionFunc) ([]*Project, *Response, error) {
		return client.Projects.ListProjects(opt, p)
	}, 1)

	// THEN the second page is never requested and the items are returned
	require.NoError(t, err)
	want := []*Project{{ID: 1}}
	assert.Equal(t, want, projects)
}

func TestPagination_ScanAndCollectN_ZeroMakesNoRequest(t *testing.T) {
	t.Parallel()

	// GIVEN a request function that counts its calls
	calls := 0
	f := func(p PaginationOptionFunc) ([]*Project, *Response, error) {
		calls++
		return []*Project{{ID: 1}}, &Response{}, nil
	}

	// WHEN collecting zero items
	projects, err := ScanAndCollectN(f, 0)

	// THEN no request is made and the result is a nil slice
	require.NoError(t, err)
	assert.Nil(t, projects)
	assert.Zero(t, calls)
}

func handleTwoPagesSuccessfully(t *testing.T, mux *http.ServeMux) {
	mux.HandleFunc("GET /api/v4/projects", func(w http.ResponseWriter, r *http.Request) {
		page := r.URL.Query().Get("page")