1package pagination
2
3import "context"
4
5type Page struct {
6 Offset int // where to start from
7 Limit int // number of items in a page
8}
9
10func FirstPage() Page {
11 return Page{
12 Offset: 0,
13 Limit: 30,
14 }
15}
16
17type ctxKey struct{}
18
19func IntoContext(ctx context.Context, page Page) context.Context {
20 return context.WithValue(ctx, ctxKey{}, page)
21}
22
23func FromContext(ctx context.Context) Page {
24 if ctx == nil {
25 return FirstPage()
26 }
27 v := ctx.Value(ctxKey{})
28 if v == nil {
29 return FirstPage()
30 }
31 page, ok := v.(Page)
32 if !ok {
33 return FirstPage()
34 }
35 return page
36}
37
38func (p Page) Previous() Page {
39 if p.Offset-p.Limit < 0 {
40 return FirstPage()
41 } else {
42 return Page{
43 Offset: p.Offset - p.Limit,
44 Limit: p.Limit,
45 }
46 }
47}
48
49func (p Page) Next() Page {
50 return Page{
51 Offset: p.Offset + p.Limit,
52 Limit: p.Limit,
53 }
54}
55
56func IterateAll[T any](
57 fetch func(page Page) ([]T, error),
58 handle func(items []T) error,
59) error {
60 page := FirstPage()
61 for {
62 items, err := fetch(page)
63 if err != nil {
64 return err
65 }
66
67 err = handle(items)
68 if err != nil {
69 return err
70 }
71 if len(items) < page.Limit {
72 break
73 }
74 page = page.Next()
75 }
76 return nil
77}