Skip to content

Commit

Permalink
fix: ordering of cursor pagination
Browse files Browse the repository at this point in the history
  • Loading branch information
psteinroe committed Jul 24, 2023
1 parent ba062b6 commit 7abe3e6
Show file tree
Hide file tree
Showing 5 changed files with 140 additions and 5 deletions.
6 changes: 6 additions & 0 deletions .changeset/strange-dragons-guess.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@supabase-cache-helpers/postgrest-fetcher": patch
"@supabase-cache-helpers/postgrest-swr": patch
---

fix: ordering of cursor pagination
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ export const createCursorPaginationFetcher = <
}

const { data } = await query.throwOnError();

// cannot be null because of .throwOnError()
return data as Result[];
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ describe('useCursorInfiniteScrollQuery', () => {
provider = new Map();
});

it('should load correctly', async () => {
it('should load correctly ascending', async () => {
function Page() {
const { data, loadMore, isValidating, error } =
useCursorInfiniteScrollQuery(
Expand Down Expand Up @@ -98,6 +98,64 @@ describe('useCursorInfiniteScrollQuery', () => {
expect(list.childElementCount).toEqual(3);
});

it('should load correctly descending', async () => {
function Page() {
const { data, loadMore, isValidating, error } =
useCursorInfiniteScrollQuery(
client
.from('contact')
.select('id,username')
.ilike('username', `${testRunPrefix}%`)
.order('username', { ascending: false })
.limit(1),
{ path: 'username' },
{ revalidateOnFocus: false }
);

return (
<div>
{loadMore && (
<div data-testid="loadMore" onClick={() => loadMore()} />
)}
<div data-testid="list">
{(data ?? []).map((p) => (
<div key={p.id}>{p.username}</div>
))}
</div>
</div>
);
}

renderWithConfig(<Page />, { provider: () => provider });
await screen.findByText(
`${testRunPrefix}-username-4`,
{},
{ timeout: 10000 }
);
const list = screen.getByTestId('list');
expect(list.childElementCount).toEqual(1);

fireEvent.click(
await screen.findByTestId('loadMore', {}, { timeout: 10000 })
);
await screen.findByText(
`${testRunPrefix}-username-3`,
{},
{ timeout: 10000 }
);

expect(list.childElementCount).toEqual(2);

fireEvent.click(screen.getByTestId('loadMore'));
await screen.findByText(
`${testRunPrefix}-username-2`,
{},
{ timeout: 10000 }
);

expect(list.childElementCount).toEqual(3);
});

it('should stop at lastCursor', async () => {
function Page() {
const { data, loadMore, isValidating, error } =
Expand Down Expand Up @@ -186,7 +244,7 @@ describe('useCursorInfiniteScrollQuery', () => {
);
});

it('should stop if no more data', async () => {
it('should stop if no more data ascending', async () => {
function Page() {
const { data, loadMore, isValidating, error } =
useCursorInfiniteScrollQuery(
Expand Down Expand Up @@ -254,4 +312,73 @@ describe('useCursorInfiniteScrollQuery', () => {

expect(screen.queryByTestId('loadMore')).toBeNull();
});

it('should stop if no more data desc', async () => {
function Page() {
const { data, loadMore, isValidating, error } =
useCursorInfiniteScrollQuery(
client
.from('contact')
.select('id,username')
.ilike('username', `${testRunPrefix}%`)
.order('username', { ascending: false })
.limit(2),
{
path: 'username',
}
);

return (
<div>
{loadMore && (
<div data-testid="loadMore" onClick={() => loadMore()} />
)}
<div data-testid="isValidating">{`isValidating: ${isValidating}`}</div>
<div data-testid="list">
{(data ?? []).map((p) => (
<div key={p.id}>{p.username}</div>
))}
</div>
</div>
);
}

renderWithConfig(<Page />, { provider: () => provider });
const list = screen.getByTestId('list');

await screen.findByText(
`${testRunPrefix}-username-4`,
{},
{ timeout: 10000 }
);
await screen.findByText(
`${testRunPrefix}-username-3`,
{},
{ timeout: 10000 }
);
expect(list.childElementCount).toEqual(2);

fireEvent.click(screen.getByTestId('loadMore'));
await screen.findByText(
`${testRunPrefix}-username-2`,
{},
{ timeout: 10000 }
);
await screen.findByText(
`${testRunPrefix}-username-1`,
{},
{ timeout: 10000 }
);
expect(list.childElementCount).toEqual(4);

await screen.findByText('isValidating: false', {}, { timeout: 10000 });

fireEvent.click(screen.getByTestId('loadMore'));

await screen.findByText('isValidating: false', {}, { timeout: 10000 });

expect(list.childElementCount).toEqual(4);

expect(screen.queryByTestId('loadMore')).toBeNull();
});
});
4 changes: 2 additions & 2 deletions packages/postgrest-swr/src/lib/create-key-getter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,12 +97,12 @@ export const createCursorKeyGetter = <
throw new Error(`No ordering key found for path ${orderingKey}`);
}

const [a, ascending, b] = orderingKey.split('.');
const [a, ascending, b] = orderingValue.split('.');

Check warning on line 100 in packages/postgrest-swr/src/lib/create-key-getter.ts

View workflow job for this annotation

GitHub Actions / ESLint Report Analysis

packages/postgrest-swr/src/lib/create-key-getter.ts#L100

[@typescript-eslint/no-unused-vars] 'a' is assigned a value but never used.

Check warning on line 100 in packages/postgrest-swr/src/lib/create-key-getter.ts

View workflow job for this annotation

GitHub Actions / ESLint Report Analysis

packages/postgrest-swr/src/lib/create-key-getter.ts#L100

[@typescript-eslint/no-unused-vars] 'b' is assigned a value but never used.

Check warning on line 100 in packages/postgrest-swr/src/lib/create-key-getter.ts

View workflow job for this annotation

GitHub Actions / ESLint Report Analysis

packages/postgrest-swr/src/lib/create-key-getter.ts#L100

[@typescript-eslint/no-unused-vars] 'a' is assigned a value but never used.

Check warning on line 100 in packages/postgrest-swr/src/lib/create-key-getter.ts

View workflow job for this annotation

GitHub Actions / ESLint Report Analysis

packages/postgrest-swr/src/lib/create-key-getter.ts#L100

[@typescript-eslint/no-unused-vars] 'b' is assigned a value but never used.

setFilterValue(
query['url'].searchParams,
path,
ascending === 'asc' ? 'lt' : 'gt',
ascending === 'asc' ? 'gt' : 'lt',
lastValue
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ function useCursorInfiniteScrollQuery<
throw new Error(`No ordering key found for path ${orderingKey}`);
}

const [column, ascending, _] = orderingKey.split('.');
const [column, ascending, _] = orderingValue.split('.');

Check warning on line 108 in packages/postgrest-swr/src/query/use-cursor-infinite-scroll-query.ts

View workflow job for this annotation

GitHub Actions / ESLint Report Analysis

packages/postgrest-swr/src/query/use-cursor-infinite-scroll-query.ts#L108

[@typescript-eslint/no-unused-vars] '_' is assigned a value but never used.

Check warning on line 108 in packages/postgrest-swr/src/query/use-cursor-infinite-scroll-query.ts

View workflow job for this annotation

GitHub Actions / ESLint Report Analysis

packages/postgrest-swr/src/query/use-cursor-infinite-scroll-query.ts#L108

[@typescript-eslint/no-unused-vars] '_' is assigned a value but never used.

// cursor value is the gt or lt filter on the order key
const q = new URLSearchParams(decodedKey.queryKey);
Expand All @@ -115,6 +115,7 @@ function useCursorInfiniteScrollQuery<
const filter = filters.find((f) =>
f.startsWith(`${ascending === 'asc' ? 'gt' : 'lt'}.`)
);

if (!filter) {
return {
cursor: undefined,
Expand Down

0 comments on commit 7abe3e6

Please sign in to comment.