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 }