7 "github.com/aws/aws-sdk-go/aws"
8 "github.com/aws/aws-sdk-go/aws/awsutil"
11 // A Pagination provides paginating of SDK API operations which are paginatable.
12 // Generally you should not use this type directly, but use the "Pages" API
13 // operations method to automatically perform pagination for you. Such as,
14 // "S3.ListObjectsPages", and "S3.ListObjectsPagesWithContext" methods.
16 // Pagination differs from a Paginator type in that pagination is the type that
17 // does the pagination between API operations, and Paginator defines the
18 // configuration that will be used per page request.
21 // for p.Next() && cont {
22 // data := p.Page().(*s3.ListObjectsOutput)
23 // // process the page's data
27 // See service client API operation Pages methods for examples how the SDK will
28 // use the Pagination type.
29 type Pagination struct {
30 // Function to return a Request value for each pagination request.
31 // Any configuration or handlers that need to be applied to the request
32 // prior to getting the next page should be done here before the request
35 // NewRequest should always be built from the same API operations. It is
36 // undefined if different API operations are returned on subsequent calls.
37 NewRequest func() (*Request, error)
40 nextTokens []interface{}
46 // HasNextPage will return true if Pagination is able to determine that the API
47 // operation has additional pages. False will be returned if there are no more
50 // Will always return true if Next has not been called yet.
51 func (p *Pagination) HasNextPage() bool {
52 return !(p.started && len(p.nextTokens) == 0)
55 // Err returns the error Pagination encountered when retrieving the next page.
56 func (p *Pagination) Err() error {
60 // Page returns the current page. Page should only be called after a successful
61 // call to Next. It is undefined what Page will return if Page is called after
62 // Next returns false.
63 func (p *Pagination) Page() interface{} {
67 // Next will attempt to retrieve the next page for the API operation. When a page
68 // is retrieved true will be returned. If the page cannot be retrieved, or there
69 // are no more pages false will be returned.
71 // Use the Page method to retrieve the current page data. The data will need
72 // to be cast to the API operation's output type.
74 // Use the Err method to determine if an error occurred if Page returns false.
75 func (p *Pagination) Next() bool {
80 req, err := p.NewRequest()
87 for i, intok := range req.Operation.InputTokens {
88 awsutil.SetValueAtPath(req.Params, intok, p.nextTokens[i])
99 p.nextTokens = req.nextPageTokens()
105 // A Paginator is the configuration data that defines how an API operation
106 // should be paginated. This type is used by the API service models to define
107 // the generated pagination config for service APIs.
109 // The Pagination type is what provides iterating between pages of an API. It
110 // is only used to store the token metadata the SDK should use for performing
112 type Paginator struct {
114 OutputTokens []string
116 TruncationToken string
119 // nextPageTokens returns the tokens to use when asking for the next page of data.
120 func (r *Request) nextPageTokens() []interface{} {
121 if r.Operation.Paginator == nil {
124 if r.Operation.TruncationToken != "" {
125 tr, _ := awsutil.ValuesAtPath(r.Data, r.Operation.TruncationToken)
130 switch v := tr[0].(type) {
132 if !aws.BoolValue(v) {
142 tokens := []interface{}{}
144 for _, outToken := range r.Operation.OutputTokens {
145 v, _ := awsutil.ValuesAtPath(r.Data, outToken)
147 tokens = append(tokens, v[0])
150 tokens = append(tokens, nil)
160 // Ensure a deprecated item is only logged once instead of each time its used.
161 func logDeprecatedf(logger aws.Logger, flag *int32, msg string) {
165 if atomic.CompareAndSwapInt32(flag, 0, 1) {
171 logDeprecatedHasNextPage int32
172 logDeprecatedNextPage int32
173 logDeprecatedEachPage int32
176 // HasNextPage returns true if this request has more pages of data available.
178 // Deprecated Use Pagination type for configurable pagination of API operations
179 func (r *Request) HasNextPage() bool {
180 logDeprecatedf(r.Config.Logger, &logDeprecatedHasNextPage,
181 "Request.HasNextPage deprecated. Use Pagination type for configurable pagination of API operations")
183 return len(r.nextPageTokens()) > 0
186 // NextPage returns a new Request that can be executed to return the next
187 // page of result data. Call .Send() on this request to execute it.
189 // Deprecated Use Pagination type for configurable pagination of API operations
190 func (r *Request) NextPage() *Request {
191 logDeprecatedf(r.Config.Logger, &logDeprecatedNextPage,
192 "Request.NextPage deprecated. Use Pagination type for configurable pagination of API operations")
194 tokens := r.nextPageTokens()
195 if len(tokens) == 0 {
199 data := reflect.New(reflect.TypeOf(r.Data).Elem()).Interface()
200 nr := New(r.Config, r.ClientInfo, r.Handlers, r.Retryer, r.Operation, awsutil.CopyOf(r.Params), data)
201 for i, intok := range nr.Operation.InputTokens {
202 awsutil.SetValueAtPath(nr.Params, intok, tokens[i])
207 // EachPage iterates over each page of a paginated request object. The fn
208 // parameter should be a function with the following sample signature:
210 // func(page *T, lastPage bool) bool {
211 // return true // return false to stop iterating
214 // Where "T" is the structure type matching the output structure of the given
215 // operation. For example, a request object generated by
216 // DynamoDB.ListTablesRequest() would expect to see dynamodb.ListTablesOutput
217 // as the structure "T". The lastPage value represents whether the page is
218 // the last page of data or not. The return value of this function should
219 // return true to keep iterating or false to stop.
221 // Deprecated Use Pagination type for configurable pagination of API operations
222 func (r *Request) EachPage(fn func(data interface{}, isLastPage bool) (shouldContinue bool)) error {
223 logDeprecatedf(r.Config.Logger, &logDeprecatedEachPage,
224 "Request.EachPage deprecated. Use Pagination type for configurable pagination of API operations")
226 for page := r; page != nil; page = page.NextPage() {
227 if err := page.Send(); err != nil {
230 if getNextPage := fn(page.Data, !page.HasNextPage()); !getNextPage {