forked from airheartdev/duffel
-
Notifications
You must be signed in to change notification settings - Fork 0
/
iter.go
118 lines (99 loc) · 2.47 KB
/
iter.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
// Copyright 2021-present Airheart, Inc. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
package duffel
// Iter is an iterator for a list of items.
// Based on the iterator used in https://github.com/stripe/stripe-go
type Iter[T any] struct {
cur *T
err error
list ListContainer[T]
meta *ListMeta
nextPage PageFn[T]
values []*T
}
func Collect[T any](it *Iter[T]) ([]*T, error) {
if it == nil {
return nil, nil
}
collection := make([]*T, 0)
for it.Next() {
collection = append(collection, it.Current())
}
return collection, it.Err()
}
type PageFn[T any] func(meta *ListMeta) (*List[T], error)
// Current returns the most recent item
// visited by a call to Next.
func (it *Iter[T]) Current() *T {
if it == nil {
return nil
}
return it.cur
}
// Err returns the error, if any,
// that caused the Iter to stop.
// It must be inspected
// after Next returns false.
func (it *Iter[T]) Err() error {
if it == nil {
return nil
}
return it.err
}
func (it *Iter[T]) LastRequestID() (string, bool) {
return it.list.LastRequestID()
}
// List returns the current list object which the iterator is currently using.
// List objects will change as new API calls are made to continue pagination.
func (it *Iter[T]) List() ListContainer[T] {
return it.list
}
// Meta returns the list metadata.
func (it *Iter[T]) Meta() *ListMeta {
if it == nil {
return nil
}
return it.meta
}
// Next advances the Iter to the next item in the list,
// which will then be available
// through the Current method.
// It returns false when the iterator stops
// at the end of the list.
func (it *Iter[T]) Next() bool {
if it.err != nil {
return false
}
if len(it.values) == 0 && it.meta.HasMore() {
it.getPage()
}
if len(it.values) == 0 {
return false
}
it.cur = it.values[0]
it.values = it.values[1:]
return true
}
func (it *Iter[T]) getPage() {
it.list, it.err = it.nextPage(it.meta)
if it.err == nil {
it.values = it.list.GetItems()
it.meta = it.list.GetListMeta()
}
}
// GetIter returns a new Iter for a given query and type.
func GetIter[T any](pager PageFn[T]) *Iter[T] {
iter := &Iter[T]{
nextPage: pager,
meta: &ListMeta{},
}
iter.getPage()
return iter
}
// ErrIter creates an iterators that always returns the given error.
func ErrIter[T any](err error) *Iter[T] {
return GetIter(func(*ListMeta) (*List[T], error) {
return nil, err
})
}