(
method: string,
options?: WebAPICallOptions,
shouldStop?: PaginatePredicate,
reduce?: PageReducer<A>,
)
| 195 | reduce?: PageReducer<A>, |
| 196 | ): Promise<A>; |
| 197 | public paginate<R extends PageReducer, A extends PageAccumulator<R>>( |
| 198 | method: string, |
| 199 | options?: WebAPICallOptions, |
| 200 | shouldStop?: PaginatePredicate, |
| 201 | reduce?: PageReducer<A>, |
| 202 | ): (Promise<A> | AsyncIterator<WebAPICallResult>) { |
| 203 | |
| 204 | if (!methods.cursorPaginationEnabledMethods.has(method)) { |
| 205 | this.logger.warn(`paginate() called with method ${method}, which is not known to be cursor pagination enabled.`); |
| 206 | } |
| 207 | |
| 208 | const pageSize = (() => { |
| 209 | if (options !== undefined && typeof options.limit === 'number') { |
| 210 | const limit = options.limit; |
| 211 | delete options.limit; |
| 212 | return limit; |
| 213 | } |
| 214 | return defaultPageSize; |
| 215 | })(); |
| 216 | |
| 217 | async function* generatePages(this: WebClient): AsyncIterableIterator<WebAPICallResult> { |
| 218 | // when result is undefined, that signals that the first of potentially many calls has not yet been made |
| 219 | let result: WebAPICallResult | undefined = undefined; |
| 220 | // paginationOptions stores pagination options not already stored in the options argument |
| 221 | let paginationOptions: methods.CursorPaginationEnabled | undefined = { |
| 222 | limit: pageSize, |
| 223 | }; |
| 224 | if (options !== undefined && options.cursor !== undefined) { |
| 225 | paginationOptions.cursor = options.cursor as string; |
| 226 | } |
| 227 | |
| 228 | // NOTE: test for the situation where you're resuming a pagination using and existing cursor |
| 229 | |
| 230 | while (result === undefined || paginationOptions !== undefined) { |
| 231 | result = await this.apiCall(method, Object.assign(options !== undefined ? options : {}, paginationOptions)); |
| 232 | yield result; |
| 233 | paginationOptions = paginationOptionsForNextPage(result, pageSize); |
| 234 | } |
| 235 | } |
| 236 | |
| 237 | if (shouldStop === undefined) { |
| 238 | return generatePages.call(this); |
| 239 | } |
| 240 | |
| 241 | const pageReducer: PageReducer<A> = (reduce !== undefined) ? reduce : noopPageReducer; |
| 242 | let index = 0; |
| 243 | |
| 244 | return (async () => { |
| 245 | // Unroll the first iteration of the iterator |
| 246 | // This is done primarily because in order to satisfy the type system, we need a variable that is typed as A |
| 247 | // (shown as accumulator before), but before the first iteration all we have is a variable typed A | undefined. |
| 248 | // Unrolling the first iteration allows us to deal with undefined as a special case. |
| 249 | |
| 250 | const pageIterator: AsyncIterableIterator<WebAPICallResult> = generatePages.call(this); |
| 251 | const firstIteratorResult = await pageIterator.next(undefined); |
| 252 | // Assumption: there will always be at least one result in a paginated API request |
| 253 | // if (firstIteratorResult.done) { return; } |
| 254 | const firstPage = firstIteratorResult.value; |
no test coverage detected