Skip to content

Instantly share code, notes, and snippets.

@narqo

narqo/pager.go Secret

Last active April 6, 2024 21:21
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save narqo/48a4e6d492912195b3340dbecc65c2b0 to your computer and use it in GitHub Desktop.
Save narqo/48a4e6d492912195b3340dbecc65c2b0 to your computer and use it in GitHub Desktop.
package pager
import "errors"
var PagerDone = errors.New("no more pages to iterate")
type pageIter[T any] interface {
NextPage() ([]T, error)
}
type fetchPageFunc[T any] func(page int) ([]T, PageInfo, error)
type Pager[T any] struct {
page int
pageInfo PageInfo
err error
fetchPage fetchPageFunc[T]
}
func NewPager[T any](page int, fetchPage fetchPageFunc[T]) *Pager[T] {
if page == 0 {
page = 1
}
p := &Pager[T]{
page: page,
fetchPage: fetchPage,
}
// hasNext must be set before the first interation
p.pageInfo.HasNext = true
return p
}
var _ pageIter[any] = (*Pager[any])(nil)
func (p *Pager[T]) NextPage() ([]T, error) {
var list []T
for len(list) == 0 {
if p.err != nil {
return nil, p.err
}
if !p.pageInfo.HasNext {
p.err = PagerDone
return nil, p.err
}
list, p.pageInfo, p.err = p.fetchPage(p.page)
p.page++
}
return list, nil
}
func (p *Pager[T]) PageInfo() PageInfo {
return p.pageInfo
}
package pager
import (
"math/rand"
"testing"
)
func TestPager(t *testing.T) {
pager := newTestPager(0)
n := rand.Intn(50)
for i := 1; i < n; i++ {
list, err := pager.NextPage()
if err != nil {
t.Fatal(err)
}
if len(list) != i {
t.Fatalf("page info: got list %+v", list)
}
pageInfo := pager.PageInfo()
if !pageInfo.HasNext {
t.Fatalf("pager: got page info %+v", pageInfo)
}
}
}
func newTestPager(init int) *Pager[int] {
var list []int
fetch := func(page int) ([]int, PageInfo, error) {
pageInfo := PageInfo{
HasNext: true,
}
list = append(list, init+page)
return list, pageInfo, nil
}
return NewPager(0, fetch)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment