Search Apps Documentation Source Content File Folder Download Copy Actions Download

jsonpage.gno

1.56 Kb · 72 lines
 1package jsonpage
 2
 3import (
 4	"strconv"
 5
 6	"gno.land/p/nt/bptree/v0"
 7	"gno.land/p/nt/mux/v0"
 8	"gno.land/p/onbloc/json"
 9)
10
11type JSONRenderer interface {
12	RenderJSON() *json.Node
13}
14
15const (
16	maxLimit     = 100
17	defaultLimit = 20
18)
19
20// Render returns a paginated JSON output.
21// CONTRACT: provide non-nil renderer func or values from the bptree.BPTree must
22// implement JSONRenderer.
23func Render(t bptree.ITree, r *mux.Request, renderer func(string, any) *json.Node) *json.Node {
24	var (
25		page  = 1
26		limit = defaultLimit
27	)
28	p, err := strconv.Atoi(r.Query.Get("page"))
29	if err == nil && p > 0 {
30		page = p
31	}
32	l, err := strconv.Atoi(r.Query.Get("limit"))
33	if err == nil && l > 0 {
34		limit = l
35	}
36	return render(t, page, limit, renderer, false)
37}
38
39func render(t bptree.ITree, page, limit int, renderer func(string, any) *json.Node, reverse bool) *json.Node {
40	total := t.Size()
41	if limit == 0 || limit > total {
42		limit = total
43	}
44	if limit > maxLimit {
45		limit = maxLimit
46	}
47	var (
48		offset  = (page - 1) * limit
49		items   []*json.Node
50		iterate = t.IterateByOffset
51	)
52	if reverse {
53		iterate = t.ReverseIterateByOffset
54	}
55	iterate(offset, limit, func(k string, v any) bool {
56		if renderer != nil {
57			items = append(items, renderer(k, v))
58		} else {
59			items = append(items, v.(JSONRenderer).RenderJSON())
60		}
61		return false
62	})
63	totalPages := 1
64	if limit > 0 {
65		totalPages = (total + limit - 1) / limit
66	}
67	return json.ObjectNode("", map[string]*json.Node{
68		"items": json.ArrayNode("", items),
69		"page":  json.NumberNode("", float64(page)),
70		"total": json.NumberNode("", float64(totalPages)),
71	})
72}