-
Notifications
You must be signed in to change notification settings - Fork 1
/
paginator.go
146 lines (116 loc) · 4.34 KB
/
paginator.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
package pagination
import (
"net/url"
"strconv"
"github.com/zheeeng/pagination/pager"
"github.com/zheeeng/pagination/queries"
)
// Truncatable is used for feeding Paginator::Wrap and Paginator::WrapWithTruncate, to wrap items into paginated result
type Truncatable interface {
Len() int
Slice(startIndex, endIndex int) Truncatable
}
// Paginator provides methods to manipulate pagination fields
type Paginator struct {
pager *pager.Pager
basePath string
queries queries.PaginationQueries
defaultPageSize int
hasPage bool
hasPageSize bool
}
func (p *Paginator) buildFields() *PageFields {
nav := p.pager.GetNavigation()
fields := &PageFields{
Page: nav.Page,
PageSize: nav.PageSize,
Total: nav.Total,
Query: p.queries.Query,
}
p.queries.Query.Set("page", strconv.Itoa(nav.Page))
p.queries.Query.Set("page_size", strconv.Itoa(nav.PageSize))
p.queries.FirstQuery.Set("page", strconv.Itoa(nav.First))
p.queries.FirstQuery.Set("page_size", strconv.Itoa(nav.PageSize))
fields.First = p.basePath + "?" + p.queries.FirstQuery.Encode()
if nav.Last > 0 {
p.queries.LastQuery.Set("page", strconv.Itoa(nav.Last))
p.queries.LastQuery.Set("page_size", strconv.Itoa(nav.PageSize))
fields.Last = p.basePath + "?" + p.queries.LastQuery.Encode()
}
p.queries.PrevQuery.Set("page", strconv.Itoa(nav.Prev))
p.queries.PrevQuery.Set("page_size", strconv.Itoa(nav.PageSize))
fields.Prev = p.basePath + "?" + p.queries.PrevQuery.Encode()
p.queries.NextQuery.Set("page", strconv.Itoa(nav.Next))
p.queries.NextQuery.Set("page_size", strconv.Itoa(nav.PageSize))
fields.Next = p.basePath + "?" + p.queries.NextQuery.Encode()
return fields
}
// Wrap is used for putting the input items to Result field of the Paginated struct.
func (p *Paginator) Wrap(items Truncatable, total int) Paginated {
p.pager.SetTotal(total)
fields := p.buildFields()
return Paginated{
Pagination: fields,
Result: items,
}
}
// WrapWithTruncate does the same thing with Wrap,
// and it truncates the input items by the pagination range.
// It may cause a panic if items is not Slice kind
func (p *Paginator) WrapWithTruncate(items Truncatable, total int) Paginated {
p.pager.SetTotal(total)
fields := p.buildFields()
length := items.Len()
startIndex, endIndex := p.GetRange()
if endIndex > length {
endIndex = length
}
return Paginated{
Pagination: fields,
Result: items.Slice(startIndex, endIndex),
}
}
// Query returns queries manipulation interface
func (p *Paginator) Query() url.Values {
return p.queries.Query
}
// SetPageInfo resets page and pageSize to pager
func (p *Paginator) SetPageInfo(page, pageSize int) *Paginator {
p.pager.SetPageInfo(page, pageSize)
return p
}
// GetRangeByIndex returns the corresponding start and end offsets by a specific item index number
func (p *Paginator) GetRangeByIndex(index int) (start, end int) {
return p.pager.ClonePagerWithCursor(index, p.pager.GetNavigation().PageSize).GetRange()
}
// GetRange returns the corresponding start and end offsets by Paginator context
func (p *Paginator) GetRange() (start, end int) {
return p.pager.GetRange()
}
// GetOffsetRangeByIndex returns the corresponding offset and range length by a specific item index number
func (p *Paginator) GetOffsetRangeByIndex(index int) (offset, length int) {
return p.pager.ClonePagerWithCursor(index, p.pager.GetNavigation().PageSize).GetOffsetRange()
}
// GetOffsetRange returns the corresponding offset and range length by Paginator context
func (p *Paginator) GetOffsetRange() (offset, length int) {
return p.pager.GetOffsetRange()
}
// GetIndicator returns current page, pageSize, total and tother info in its context
func (p *Paginator) GetIndicator() pager.Navigation {
return p.pager.GetNavigation()
}
// HasRawPagination returns whether the test link contains pagination fields
func (p *Paginator) HasRawPagination() bool {
// if link contains page, coz we assigned default page_size
// or if link contains page_size, we assigned default page 1,
// we think there has a specificed pagination infomation.
return p.hasPage || p.hasPageSize
}
// HasRawPage returns whether the test link contains 'page' field
func (p *Paginator) HasRawPage() bool {
return p.hasPage
}
// HasRawPageSize returns whether the test link contains 'page_size' field
func (p *Paginator) HasRawPageSize() bool {
return p.hasPageSize
}