-
Notifications
You must be signed in to change notification settings - Fork 7
/
pagination.go
93 lines (84 loc) · 2.04 KB
/
pagination.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
package openproject
import (
"fmt"
rbt "github.com/emirpasic/gods/trees/redblacktree"
)
type saveBox struct {
Index int
Res interface{}
}
// AutoPageTurn auto page turn
// @notice Use careful when dealing large amounts of data because it will set all objects in memory.
// Usage case:
//
// users, err := AutoPageTurn(nil, 10, testClient.User.GetList)
func AutoPageTurn[T IPaginationResponse](filter *FilterOptions, pageSize int,
fetch func(*FilterOptions, int, int) (T, *Response, error)) (T, error) {
var res T
offset := 1
if pageSize == 0 {
pageSize = 10
}
// First request get total count
var err error
res, _, err = fetch(filter, offset, pageSize)
if err != nil {
return res, err
}
if res.TotalPage() < 2 {
// less 2 page, return directly
return res, nil
}
totalPage := res.TotalPage()
box := make(chan saveBox)
// use more goroutine for speed up
for i := offset; i <= totalPage; i++ {
go request(box, filter, pageSize, i, fetch)
}
// Sort by red-black tree
t := addResToTree(box, res.TotalPage())
var tmpRes T
for _, key := range t.Keys() {
b, found := t.Get(key)
if found {
bx := b.(T)
if isInterfaceZero(tmpRes) {
tmpRes = bx
} else {
tmpRes.ConcatEmbed(bx)
}
}
}
return tmpRes, nil
}
func addResToTree(collection <-chan saveBox, size int) *rbt.Tree {
t := rbt.NewWithIntComparator()
for i := 0; i < size; i++ {
res := <-collection
fmt.Printf("get res %+v", res)
t.Put(res.Index, res.Res)
}
return t
}
func request[T IPaginationResponse](ch chan<- saveBox, filter *FilterOptions, pageSize int, idx int, fetch func(*FilterOptions, int, int) (T, *Response, error)) {
pageRes, _, err := fetch(filter, idx, pageSize)
if err != nil {
return
}
ch <- saveBox{Index: idx, Res: pageRes}
}
func isInterfaceZero[T any](val T) bool {
switch v := any(val).(type) {
case *SearchResultProject:
return v == nil
case *SearchResultQuery:
return v == nil
case *SearchResultStatus:
return v == nil
case *SearchResultUser:
return v == nil
case *SearchResultWP:
return v == nil
}
return false
}