Skip to content

Commit 6bb88cf

Browse files
committed
only enable pagination if limit/offset match pagination size
1 parent 68ad1f6 commit 6bb88cf

File tree

3 files changed

+56
-4
lines changed

3 files changed

+56
-4
lines changed

packages/explorer/src/app/(explorer)/[chainName]/worlds/[worldAddress]/explore/TablesViewer.tsx

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ import { TData, TDataRow, useTableDataQuery } from "../../../../queries/useTable
3333
import { indexerForChainId } from "../../../../utils/indexerForChainId";
3434
import { EditableTableCell } from "./EditableTableCell";
3535
import { ExportButton } from "./ExportButton";
36+
import { PAGE_SIZE_OPTIONS } from "./consts";
37+
import { getLimitOffset } from "./utils/getLimitOffset";
3638
import { typeSortingFn } from "./utils/typeSortingFn";
3739

3840
const initialSortingState: SortingState = [];
@@ -153,6 +155,16 @@ export function TablesViewer({ table, isLiveQuery }: Props) {
153155
},
154156
});
155157

158+
// Pagination is only enabled if the query has a LIMIT and OFFSET that are divisible by the page size
159+
const isPaginationEnabled = useMemo(() => {
160+
if (!query) return false;
161+
162+
const { limit, offset } = getLimitOffset(query);
163+
if (limit == null || offset == null) return false;
164+
165+
return PAGE_SIZE_OPTIONS.includes(limit) && offset % pagination.pageSize === 0;
166+
}, [pagination.pageSize, query]);
167+
156168
return (
157169
<div
158170
className={cn("space-y-4", {
@@ -237,12 +249,13 @@ export function TablesViewer({ table, isLiveQuery }: Props) {
237249
<Select
238250
value={pagination.pageSize.toString()}
239251
onValueChange={(value) => reactTable.setPageSize(Number(value))}
252+
disabled={!isPaginationEnabled}
240253
>
241254
<SelectTrigger className="h-8 w-[70px]">
242255
<SelectValue>{pagination.pageSize}</SelectValue>
243256
</SelectTrigger>
244257
<SelectContent>
245-
{[5, 10, 20, 30, 40, 50, 100].map((pageSize) => (
258+
{PAGE_SIZE_OPTIONS.map((pageSize) => (
246259
<SelectItem key={pageSize} value={pageSize.toString()}>
247260
{pageSize}
248261
</SelectItem>
@@ -257,23 +270,28 @@ export function TablesViewer({ table, isLiveQuery }: Props) {
257270
variant="outline"
258271
size="sm"
259272
onClick={() => reactTable.setPageIndex(0)}
260-
disabled={!reactTable.getCanPreviousPage()}
273+
disabled={!isPaginationEnabled || !reactTable.getCanPreviousPage()}
261274
>
262275
<ChevronsLeftIcon className="mr-1 h-4 w-4" />
263276
</Button>
264277
<Button
265278
variant="outline"
266279
size="sm"
267280
onClick={() => reactTable.previousPage()}
268-
disabled={!reactTable.getCanPreviousPage()}
281+
disabled={!isPaginationEnabled || !reactTable.getCanPreviousPage()}
269282
>
270283
<ChevronLeftIcon className="mr-1 h-4 w-4" /> Prev
271284
</Button>
272285
<Button
273286
variant="outline"
274287
size="sm"
275288
onClick={() => reactTable.nextPage()}
276-
disabled={!reactTable.getCanNextPage() || !tableData || tableData.rows.length < pagination.pageSize}
289+
disabled={
290+
!isPaginationEnabled ||
291+
!reactTable.getCanNextPage() ||
292+
!tableData ||
293+
tableData.rows.length < pagination.pageSize
294+
}
277295
>
278296
Next <ChevronRightIcon className="ml-1 h-4 w-4" />
279297
</Button>

packages/explorer/src/app/(explorer)/[chainName]/worlds/[worldAddress]/explore/consts.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,3 +94,5 @@ export const suggestedSQLKeywords = [
9494
"EXCEPT",
9595
] as const;
9696
export type SuggestedSQLKeyword = (typeof suggestedSQLKeywords)[number];
97+
98+
export const PAGE_SIZE_OPTIONS = [5, 10, 20, 30, 40, 50, 100];
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { Parser } from "node-sql-parser";
2+
3+
const sqlParser = new Parser();
4+
const opt = {
5+
database: "Postgresql",
6+
};
7+
8+
export function getLimitOffset(query: string) {
9+
const decodedQuery = decodeURIComponent(query);
10+
let ast = sqlParser.astify(decodedQuery, opt);
11+
if (Array.isArray(ast) && ast.length > 0) {
12+
const astFirst = ast[0];
13+
if (astFirst) {
14+
ast = astFirst;
15+
}
16+
}
17+
18+
let limit = null;
19+
let offset = null;
20+
21+
if ("limit" in ast) {
22+
// If limit has a separator "offset", it contains both limit and offset values. Otherwise, only limit is set.
23+
if (ast.limit?.seperator === "offset") {
24+
limit = ast.limit?.value?.[0]?.value;
25+
offset = ast.limit?.value?.[1]?.value;
26+
} else {
27+
limit = ast.limit?.value?.[0]?.value;
28+
}
29+
}
30+
31+
return { limit, offset };
32+
}

0 commit comments

Comments
 (0)