go.temporal.io/server@v1.23.0/common/collection/paging_iterator.go (about)

     1  // The MIT License
     2  //
     3  // Copyright (c) 2020 Temporal Technologies Inc.  All rights reserved.
     4  //
     5  // Copyright (c) 2020 Uber Technologies, Inc.
     6  //
     7  // Permission is hereby granted, free of charge, to any person obtaining a copy
     8  // of this software and associated documentation files (the "Software"), to deal
     9  // in the Software without restriction, including without limitation the rights
    10  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    11  // copies of the Software, and to permit persons to whom the Software is
    12  // furnished to do so, subject to the following conditions:
    13  //
    14  // The above copyright notice and this permission notice shall be included in
    15  // all copies or substantial portions of the Software.
    16  //
    17  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    18  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    19  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    20  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    21  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    22  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    23  // THE SOFTWARE.
    24  
    25  package collection
    26  
    27  type (
    28  	// PaginationFn is the function which get a page of results
    29  	PaginationFn[V any] func(paginationToken []byte) ([]V, []byte, error)
    30  
    31  	// PagingIteratorImpl is the implementation of PagingIterator
    32  	PagingIteratorImpl[V any] struct {
    33  		paginationFn      PaginationFn[V]
    34  		pageToken         []byte
    35  		pageErr           error
    36  		pageItems         []V
    37  		nextPageItemIndex int
    38  	}
    39  )
    40  
    41  // NewPagingIterator create a new paging iterator
    42  func NewPagingIterator[V any](
    43  	paginationFn PaginationFn[V],
    44  ) Iterator[V] {
    45  	iter := &PagingIteratorImpl[V]{
    46  		paginationFn:      paginationFn,
    47  		pageToken:         nil,
    48  		pageErr:           nil,
    49  		pageItems:         nil,
    50  		nextPageItemIndex: 0,
    51  	}
    52  	iter.getNextPage() // this will initialize the paging iterator
    53  	return iter
    54  }
    55  
    56  // NewPagingIteratorWithToken create a new paging iterator with initial token
    57  func NewPagingIteratorWithToken[V any](
    58  	paginationFn PaginationFn[V],
    59  	pageToken []byte,
    60  ) Iterator[V] {
    61  	iter := &PagingIteratorImpl[V]{
    62  		paginationFn:      paginationFn,
    63  		pageToken:         pageToken,
    64  		pageErr:           nil,
    65  		pageItems:         nil,
    66  		nextPageItemIndex: 0,
    67  	}
    68  	iter.getNextPage() // this will initialize the paging iterator
    69  	return iter
    70  }
    71  
    72  // HasNext return whether has next item or err
    73  func (iter *PagingIteratorImpl[V]) HasNext() bool {
    74  	// pagination encounters error
    75  	if iter.pageErr != nil {
    76  		return true
    77  	}
    78  
    79  	// still have local cached item to return
    80  	if iter.nextPageItemIndex < len(iter.pageItems) {
    81  		return true
    82  	}
    83  
    84  	if len(iter.pageToken) != 0 {
    85  		iter.getNextPage()
    86  		return iter.HasNext()
    87  	}
    88  
    89  	return false
    90  }
    91  
    92  // Next return next item or err
    93  func (iter *PagingIteratorImpl[V]) Next() (V, error) {
    94  	if !iter.HasNext() {
    95  		panic("HistoryEventIterator Next() called without checking HasNext()")
    96  	}
    97  
    98  	if iter.pageErr != nil {
    99  		err := iter.pageErr
   100  		iter.pageErr = nil
   101  		var v V
   102  		return v, err
   103  	}
   104  
   105  	// we have cached events
   106  	if iter.nextPageItemIndex < len(iter.pageItems) {
   107  		index := iter.nextPageItemIndex
   108  		iter.nextPageItemIndex++
   109  		return iter.pageItems[index], nil
   110  	}
   111  
   112  	panic("HistoryEventIterator Next() should return either a history event or a err")
   113  }
   114  
   115  func (iter *PagingIteratorImpl[V]) getNextPage() {
   116  	items, token, err := iter.paginationFn(iter.pageToken)
   117  	if err == nil {
   118  		iter.pageItems = items
   119  		iter.pageToken = token
   120  		iter.pageErr = nil
   121  	} else {
   122  		iter.pageItems = nil
   123  		iter.pageToken = nil
   124  		iter.pageErr = err
   125  	}
   126  	iter.nextPageItemIndex = 0
   127  }