From d3fae841c253034ce0a3e5f8489dbb40eccc43ee Mon Sep 17 00:00:00 2001 From: Gui Iribarren Date: Mon, 8 Jul 2024 09:59:03 +0200 Subject: [PATCH] squash! api: refactor pagination api: return Pagination instead of just Total --- api/accounts.go | 4 ++-- api/api_types.go | 19 ++++++++++++++----- api/chain.go | 2 +- api/elections.go | 2 +- api/helpers.go | 20 ++++++++++++++++++++ test/api_test.go | 16 ++++++++-------- 6 files changed, 46 insertions(+), 17 deletions(-) diff --git a/api/accounts.go b/api/accounts.go index 3f369b0f4..c11b63f6e 100644 --- a/api/accounts.go +++ b/api/accounts.go @@ -575,8 +575,8 @@ func (a *API) sendAccountList(ctx *httprouter.HTTPContext, paramPage string) err return ErrIndexerQueryFailed.WithErr(err) } list := &AccountsList{ - Accounts: accounts, - Total: total, + Accounts: accounts, + Pagination: calculatePagination(page, total), } return marshalAndSend(ctx, list) } diff --git a/api/api_types.go b/api/api_types.go index 3f2e6e2fa..1cde64aa1 100644 --- a/api/api_types.go +++ b/api/api_types.go @@ -17,6 +17,15 @@ type CountResult struct { Count uint64 `json:"count" example:"10"` } +// Pagination contains all the values needed for the UI to easily organize the returned data +type Pagination struct { + TotalItems uint64 `json:"total_items"` + TotalPages uint64 `json:"total_pages"` + PreviousPage uint64 `json:"previous_page"` + CurrentPage uint64 `json:"current_page"` + NextPage uint64 `json:"next_page"` +} + type OrganizationSummary struct { OrganizationID types.HexBytes `json:"organizationID" example:"0x370372b92514d81a0e3efb8eba9d036ae0877653"` ElectionCount uint64 `json:"electionCount" example:"1"` @@ -26,7 +35,7 @@ type OrganizationSummary struct { // and return an empty object if the list does not contains any result type OrganizationsList struct { Organizations []OrganizationSummary `json:"organizations"` - Total uint64 `json:"total"` + Pagination *Pagination `json:"pagination"` } type ElectionSummary struct { @@ -45,8 +54,8 @@ type ElectionSummary struct { // ElectionsList wraps the elections list to consistently return the list inside an object, // and return an empty object if the list does not contains any result type ElectionsList struct { - Elections []ElectionSummary `json:"elections"` - Total uint64 `json:"total"` + Elections []ElectionSummary `json:"elections"` + Pagination *Pagination `json:"pagination"` } // ElectionResults is the struct used to wrap the results of an election @@ -246,8 +255,8 @@ type Account struct { } type AccountsList struct { - Accounts []indexertypes.Account `json:"accounts"` - Total uint64 `json:"total"` + Accounts []indexertypes.Account `json:"accounts"` + Pagination *Pagination `json:"pagination"` } type AccountSet struct { diff --git a/api/chain.go b/api/chain.go index a4dba0299..a26361d67 100644 --- a/api/chain.go +++ b/api/chain.go @@ -312,7 +312,7 @@ func (a *API) sendOrganizationList(ctx *httprouter.HTTPContext, } list := &OrganizationsList{ - Total: total, + Pagination: calculatePagination(page, total), } for _, org := range entities { list.Organizations = append(list.Organizations, OrganizationSummary{ diff --git a/api/elections.go b/api/elections.go index e179f14aa..f613e57a2 100644 --- a/api/elections.go +++ b/api/elections.go @@ -276,7 +276,7 @@ func (a *API) sendElectionList(ctx *httprouter.HTTPContext, params *ElectionFilt } list := &ElectionsList{ - Total: total, + Pagination: calculatePagination(params.Page, total), } for _, eid := range eids { e, err := a.indexer.ProcessInfo(eid) diff --git a/api/helpers.go b/api/helpers.go index 2c78df79e..64eed8c40 100644 --- a/api/helpers.go +++ b/api/helpers.go @@ -5,6 +5,7 @@ import ( "encoding/json" "errors" "fmt" + "math" "math/big" "strconv" "strings" @@ -235,3 +236,22 @@ func parseBool(s string) (bool, error) { } return b, nil } + +func calculatePagination(page int, totalItems uint64) *Pagination { + totalp := math.Ceil(float64(totalItems) / ItemsPerPage) + prevp := page - 1 + if prevp < 0 { + prevp = 0 + } + nextp := page + 1 + if nextp > int(totalp) { + nextp = int(totalp) + } + return &Pagination{ + TotalItems: totalItems, + TotalPages: uint64(totalp), + PreviousPage: uint64(prevp), + CurrentPage: uint64(page), + NextPage: uint64(nextp), + } +} diff --git a/test/api_test.go b/test/api_test.go index 01c18d697..f9e433976 100644 --- a/test/api_test.go +++ b/test/api_test.go @@ -263,10 +263,10 @@ func TestAPIAccountsList(t *testing.T) { qt.Assert(t, el["1"], qt.DeepEquals, el["p1"]) // 2 accounts pre-exist: the faucet account, and the burn address - qt.Assert(t, el["0"].Total, qt.Equals, uint64(2+20)) - qt.Assert(t, el["1"].Total, qt.Equals, el["0"].Total) - qt.Assert(t, el["p0"].Total, qt.Equals, el["0"].Total) - qt.Assert(t, el["p1"].Total, qt.Equals, el["0"].Total) + qt.Assert(t, el["0"].Pagination.TotalItems, qt.Equals, uint64(2+20)) + qt.Assert(t, el["1"].Pagination.TotalItems, qt.Equals, el["0"].Pagination.TotalItems) + qt.Assert(t, el["p0"].Pagination.TotalItems, qt.Equals, el["0"].Pagination.TotalItems) + qt.Assert(t, el["p1"].Pagination.TotalItems, qt.Equals, el["0"].Pagination.TotalItems) for _, item := range el { qt.Assert(t, len(item.Accounts), qt.Equals, api.ItemsPerPage) @@ -943,10 +943,10 @@ func TestAPIElectionsList(t *testing.T) { qt.Assert(t, el["0"], qt.DeepEquals, el["p0"]) qt.Assert(t, el["1"], qt.DeepEquals, el["p1"]) - qt.Assert(t, el["0"].Total, qt.Equals, uint64(20)) - qt.Assert(t, el["1"].Total, qt.Equals, el["0"].Total) - qt.Assert(t, el["p0"].Total, qt.Equals, el["0"].Total) - qt.Assert(t, el["p1"].Total, qt.Equals, el["0"].Total) + qt.Assert(t, el["0"].Pagination.TotalItems, qt.Equals, uint64(20)) + qt.Assert(t, el["1"].Pagination.TotalItems, qt.Equals, el["0"].Pagination.TotalItems) + qt.Assert(t, el["p0"].Pagination.TotalItems, qt.Equals, el["0"].Pagination.TotalItems) + qt.Assert(t, el["p1"].Pagination.TotalItems, qt.Equals, el["0"].Pagination.TotalItems) for _, item := range el { qt.Assert(t, len(item.Elections), qt.Equals, api.ItemsPerPage)