-
Notifications
You must be signed in to change notification settings - Fork 1
/
pager.go
157 lines (131 loc) · 3.29 KB
/
pager.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
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
// Package gopager provides pagination for slices.
package gopager
import "reflect"
// Pageable is the interface that wraps Len method.
//
// Len returns the length of slice.
type Pageable interface {
Len() int
}
// Paginater is the interface that supports retrieving iterator items a page at a time.
type Paginater interface {
Next(slicePtr interface{})
Current(slicePtr interface{})
Previous(slicePtr interface{})
HasNext() bool
HasPrevious() bool
Page(num int) Paginater
CurrentPage() int
MaxPage() int
}
// Paginate is the struct that has page information necessary for paging.
type Paginate struct {
items Pageable
pageSize int
current int
maxSize int
currentPage int
maxPage int
}
// NewPaginater returns a paginater.
func NewPaginater(items Pageable, pageSize int) Paginater {
p := &Paginate{
items: items,
pageSize: pageSize,
current: 0,
maxSize: items.Len(),
currentPage: 0,
}
if p.maxSize == 0 {
p.maxPage = 0
} else {
p.maxPage = ((p.maxSize - 1) / pageSize) + 1
}
return p
}
// Page changes the current page to the number specified in the argument `num`.
func (p *Paginate) Page(num int) Paginater {
if num < 0 {
num = 0
}
p.currentPage = num
p.current = num * p.pageSize
return p
}
// CurrentPage returns the current page number.
func (p *Paginate) CurrentPage() int {
return p.currentPage
}
// MaxPage returns the maxinum value of pages.
func (p *Paginate) MaxPage() int {
return p.maxPage
}
// Next retrieves a sequence of items in next page from the iterator
// and appends them to slicePtr, which must be a pointer to a slice
// of the iterator's item type.
func (p *Paginate) Next(slicePtr interface{}) {
if !p.HasNext() {
return
}
e := reflect.ValueOf(slicePtr).Elem()
from := p.current
to := p.current + p.pageSize
if to > p.maxSize {
to = p.maxSize
}
e.Set(reflect.AppendSlice(e, reflect.ValueOf(p.items).Slice(from, to)))
p.current = p.current + p.pageSize
p.currentPage++
}
// Current retrieves a sequence of items in current page from the iterator
// and appends them to slicePtr, which must be a pointer to a slice
// of the iterator's item type.
func (p *Paginate) Current(slicePtr interface{}) {
if p.CurrentPage() == 0 {
return
}
e := reflect.ValueOf(slicePtr).Elem()
from := p.current - p.pageSize
if from < 0 {
from = 0
}
to := p.current
if to > p.maxSize {
to = p.maxSize
}
e.Set(reflect.AppendSlice(e, reflect.ValueOf(p.items).Slice(from, to)))
}
// Previous retrieves a sequence of items in previous page from the iterator
// and appends them to slicePtr, which must be a pointer to a slice
// of the iterator's item type.
func (p *Paginate) Previous(slicePtr interface{}) {
if !p.HasPrevious() {
return
}
e := reflect.ValueOf(slicePtr).Elem()
from := p.current - p.pageSize*2
if from < 0 {
from = 0
}
to := p.current - p.pageSize
if to > p.maxSize {
to = p.maxSize
}
e.Set(reflect.AppendSlice(e, reflect.ValueOf(p.items).Slice(from, to)))
p.currentPage--
p.current = to
}
// HasNext returns whether the next page exists.
func (p *Paginate) HasNext() bool {
if p.current >= p.maxSize {
return false
}
return true
}
// HasPrevious returns whether the previous page exists.
func (p *Paginate) HasPrevious() bool {
if p.current-p.pageSize <= 0 {
return false
}
return true
}