diff --git a/.changeset/strange-dragons-guess.md b/.changeset/strange-dragons-guess.md
new file mode 100644
index 00000000..06eb01db
--- /dev/null
+++ b/.changeset/strange-dragons-guess.md
@@ -0,0 +1,6 @@
+---
+"@supabase-cache-helpers/postgrest-fetcher": patch
+"@supabase-cache-helpers/postgrest-swr": patch
+---
+
+fix: ordering of cursor pagination
diff --git a/packages/postgrest-fetcher/src/cursor-pagination-fetcher.ts b/packages/postgrest-fetcher/src/cursor-pagination-fetcher.ts
index f2959403..40f83363 100644
--- a/packages/postgrest-fetcher/src/cursor-pagination-fetcher.ts
+++ b/packages/postgrest-fetcher/src/cursor-pagination-fetcher.ts
@@ -41,6 +41,7 @@ export const createCursorPaginationFetcher = <
}
const { data } = await query.throwOnError();
+
// cannot be null because of .throwOnError()
return data as Result[];
};
diff --git a/packages/postgrest-swr/__tests__/query/use-cursor-infinite-scroll-query.spec.tsx b/packages/postgrest-swr/__tests__/query/use-cursor-infinite-scroll-query.spec.tsx
index 10de1e8e..be94269f 100644
--- a/packages/postgrest-swr/__tests__/query/use-cursor-infinite-scroll-query.spec.tsx
+++ b/packages/postgrest-swr/__tests__/query/use-cursor-infinite-scroll-query.spec.tsx
@@ -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(
@@ -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 (
+
+ {loadMore && (
+
loadMore()} />
+ )}
+
+ {(data ?? []).map((p) => (
+
{p.username}
+ ))}
+
+
+ );
+ }
+
+ renderWithConfig(
, { 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 } =
@@ -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(
@@ -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 (
+
+ {loadMore && (
+
loadMore()} />
+ )}
+
{`isValidating: ${isValidating}`}
+
+ {(data ?? []).map((p) => (
+
{p.username}
+ ))}
+
+
+ );
+ }
+
+ renderWithConfig(
, { 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();
+ });
});
diff --git a/packages/postgrest-swr/src/lib/create-key-getter.ts b/packages/postgrest-swr/src/lib/create-key-getter.ts
index 0843150e..19f39602 100644
--- a/packages/postgrest-swr/src/lib/create-key-getter.ts
+++ b/packages/postgrest-swr/src/lib/create-key-getter.ts
@@ -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('.');
setFilterValue(
query['url'].searchParams,
path,
- ascending === 'asc' ? 'lt' : 'gt',
+ ascending === 'asc' ? 'gt' : 'lt',
lastValue
);
diff --git a/packages/postgrest-swr/src/query/use-cursor-infinite-scroll-query.ts b/packages/postgrest-swr/src/query/use-cursor-infinite-scroll-query.ts
index 8f85e108..27a51fa6 100644
--- a/packages/postgrest-swr/src/query/use-cursor-infinite-scroll-query.ts
+++ b/packages/postgrest-swr/src/query/use-cursor-infinite-scroll-query.ts
@@ -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('.');
// cursor value is the gt or lt filter on the order key
const q = new URLSearchParams(decodedKey.queryKey);
@@ -115,6 +115,7 @@ function useCursorInfiniteScrollQuery<
const filter = filters.find((f) =>
f.startsWith(`${ascending === 'asc' ? 'gt' : 'lt'}.`)
);
+
if (!filter) {
return {
cursor: undefined,