From 005b82c2b545ebb4e0549ba30a497ff64ebecd3d Mon Sep 17 00:00:00 2001 From: "ondrej.frei" Date: Mon, 23 Sep 2024 20:28:05 +0200 Subject: [PATCH] Introduce traversePaginatedSourceByHasMore() --- .../app/api-common/src/paginationUtils.ts | 19 ++++++++ .../api-common/test/paginationUtils.spec.ts | 44 +++++++++++++++++++ 2 files changed, 63 insertions(+) diff --git a/packages/app/api-common/src/paginationUtils.ts b/packages/app/api-common/src/paginationUtils.ts index 34ebfe88..46d7522f 100644 --- a/packages/app/api-common/src/paginationUtils.ts +++ b/packages/app/api-common/src/paginationUtils.ts @@ -201,3 +201,22 @@ export async function getPaginatedEntriesByHasMore, +>( + pagination: OptionalPaginationParams, + apiCall: (params: OptionalPaginationParams) => Promise>, + processPage: (pageData: PaginatedResponse['data']) => Promise, +): Promise { + let hasMore: boolean | undefined + let currentCursor: string | undefined = pagination.after + + do { + const pageResult = await apiCall({ ...pagination, after: currentCursor }) + hasMore = pageResult.meta.hasMore + currentCursor = pageResult.meta.cursor + + await processPage(pageResult.data) + } while (hasMore) +} diff --git a/packages/app/api-common/test/paginationUtils.spec.ts b/packages/app/api-common/test/paginationUtils.spec.ts index 5a4e4aea..e3ee2ac0 100644 --- a/packages/app/api-common/test/paginationUtils.spec.ts +++ b/packages/app/api-common/test/paginationUtils.spec.ts @@ -8,6 +8,7 @@ import { getPaginatedEntries, getPaginatedEntriesByHasMore, } from '../src' +import { traversePaginatedSourceByHasMore } from '../src' describe('paginationUtils', () => { describe('createPaginatedResponse', () => { @@ -276,6 +277,49 @@ describe('paginationUtils', () => { expect(result).toEqual([{ id: 'red' }]) }) }) + describe('traversePaginatedSourceByHasMore', () => { + it.only('should perform callback per each page', async () => { + // Given + const spy = vi + .spyOn(market, 'getApples') + .mockResolvedValueOnce({ + data: [{ id: 'red' }], + meta: { + count: 1, + cursor: 'red', + hasMore: true, + }, + }) + .mockResolvedValueOnce({ + data: [{ id: 'blue' }], + meta: { + count: 1, + cursor: 'blue', + hasMore: false, + }, + }) + + const processPage = vi.fn() + + // When + await traversePaginatedSourceByHasMore( + { limit: 1 }, + (params) => { + return market.getApples(params) + }, + processPage, + ) + + // Then + expect(spy).toHaveBeenCalledTimes(2) + expect(spy).toHaveBeenNthCalledWith(1, { limit: 1 }) + expect(spy).toHaveBeenNthCalledWith(2, { after: 'red', limit: 1 }) + + expect(processPage).toHaveBeenCalledTimes(2) + expect(processPage).toHaveBeenNthCalledWith(1, [{ id: 'red' }]) + expect(processPage).toHaveBeenNthCalledWith(2, [{ id: 'blue' }]) + }) + }) }) type Entity = {