-
Notifications
You must be signed in to change notification settings - Fork 103
/
page.go
148 lines (135 loc) · 4.45 KB
/
page.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
package twilio
import (
"errors"
"net/url"
"strings"
"time"
types "github.com/kevinburke/go-types"
"golang.org/x/net/context"
)
type Page struct {
FirstPageURI string `json:"first_page_uri"`
Start uint `json:"start"`
End uint `json:"end"`
NumPages uint `json:"num_pages"`
Total uint `json:"total"`
NextPageURI types.NullString `json:"next_page_uri"`
PreviousPageURI types.NullString `json:"previous_page_uri"`
PageSize uint `json:"page_size"`
}
type Meta struct {
FirstPageURL string `json:"first_page_url"`
NextPageURL types.NullString `json:"next_page_url"`
PreviousPageURL types.NullString `json:"previous_page_url"`
Key string `json:"key"`
Page uint `json:"page"`
PageSize uint `json:"page_size"`
}
// NoMoreResults is returned if you reach the end of the result set while
// paging through resources.
var NoMoreResults = errors.New("twilio: No more results")
type PageIterator struct {
client *Client
nextPageURI types.NullString
data url.Values
count uint
pathPart string
}
func (p *PageIterator) SetNextPageURI(npuri types.NullString) {
if npuri.Valid == false {
p.nextPageURI = npuri
return
}
if strings.HasPrefix(npuri.String, p.client.Base) {
npuri.String = npuri.String[len(p.client.Base):]
}
p.nextPageURI = npuri
}
// Next asks for the next page of resources and decodes the results into v.
func (p *PageIterator) Next(ctx context.Context, v interface{}) error {
var err error
switch {
case p.nextPageURI.Valid:
err = p.client.GetNextPage(ctx, p.nextPageURI.String, v)
case p.count == 0:
err = p.client.ListResource(ctx, p.pathPart, p.data, v)
default:
return NoMoreResults
}
if err != nil {
return err
}
p.count++
return nil
}
// NewPageIterator returns a PageIterator that can be used to iterate through
// values. Call Next() to get the first page of values (and again to get
// subsequent pages). If there are no more results, NoMoreResults is returned.
func NewPageIterator(client *Client, data url.Values, pathPart string) *PageIterator {
return &PageIterator{
data: data,
client: client,
count: 0,
nextPageURI: types.NullString{},
pathPart: pathPart,
}
}
// NewNextPageIterator returns a PageIterator based on the provided
// nextPageURI, and is designed for iterating if you have a nextPageURI and not
// a list of query values.
//
// NewNextPageIterator panics if nextPageURI is empty.
func NewNextPageIterator(client *Client, nextPageURI string) *PageIterator {
if nextPageURI == "" {
panic("nextpageuri is empty")
}
return &PageIterator{
data: url.Values{},
client: client,
nextPageURI: types.NullString{Valid: true, String: nextPageURI},
pathPart: "",
count: 0,
}
}
// containsResultsInRange returns true if any results are in the range
// [start, end).
func containsResultsInRange(start time.Time, end time.Time, results []time.Time) bool {
for _, result := range results {
if (result.Equal(start) || result.After(start)) && result.Before(end) {
return true
}
}
return false
}
// shouldContinuePaging returns true if fetching more results (that have
// earlier timestamps than the provided results) could possibly return results
// in the range. shouldContinuePaging assumes results is sorted so the first
// result in the slice has the latest timestamp, and the last result in the
// slice has the earliest timestamp. shouldContinuePaging panics if results is
// empty.
func shouldContinuePaging(start time.Time, results []time.Time) bool {
// the last result in results is the earliest. if the earliest result is
// before the start, fetching more resources may return more results.
if len(results) == 0 {
panic("zero length result set")
}
last := results[len(results)-1]
return last.After(start)
}
// indexesOutsideRange returns the indexes of times in results that are outside
// of [start, end). indexesOutsideRange panics if start is later than end.
func indexesOutsideRange(start time.Time, end time.Time, results []time.Time) []int {
if start.After(end) {
panic("start date is after end date")
}
indexes := make([]int, 0, len(results))
for i, result := range results {
if result.Equal(end) || result.After(end) {
indexes = append(indexes, i)
}
if result.Before(start) {
indexes = append(indexes, i)
}
}
return indexes
}