Skip to content

Paging

Enumerable query proxies expose paging helpers. The backend must implement paging: ordinary automatic pipeline paging uses IQueryable<T>, while observable providers can apply paging themselves (for example MongoDB Observe() uses the query context’s Skip/Limit).

When the backend returns IQueryable<T>, the query pipeline applies .Skip() and .Take() on the server so only the requested page is fetched. Generated proxies expose useWithPaging and useSuspenseWithPaging for this flow.

For backend implementation details, see Controller-based Paging and Model-bound Paging.

Use useWithPaging instead of use, passing a page size:

export const AccountList = () => {
const [result, perform, setSorting, setPage, setPageSize] = AllAccounts.useWithPaging(25);
return (
<>
<DataTable value={result.data}>
<Column field="name" header="Name" />
<Column field="balance" header="Balance" />
</DataTable>
<p>
Page {result.paging.page + 1} of {result.paging.totalPages}
({result.paging.totalItems} total items)
</p>
<button
disabled={result.paging.page === 0}
onClick={() => setPage(result.paging.page - 1)}>
Previous
</button>
<button
disabled={result.paging.page >= result.paging.totalPages - 1}
onClick={() => setPage(result.paging.page + 1)}>
Next
</button>
</>
);
};

For an ordinary query, useWithPaging returns an extended tuple:

IndexNameTypeDescription
0resultQueryResultWithState<T>Query result including paging metadata
1perform() => Promise<void>Re-execute the query
2setSorting(sorting: Sorting) => Promise<void>Change sort field and direction
3setPage(page: number) => Promise<void>Navigate to a specific page (zero-based)
4setPageSize(pageSize: number) => Promise<void>Change number of items per page

For an observable enumerable query the tuple is [result, setSorting, setPage, setPageSize]; there is no perform delegate. Single-result proxies do not generate paging helpers. Suspense variants preserve these tuple shapes.

Initial paging and sorting are sent when an observable subscription opens. In the current non-Suspense hooks with the default retained instance cache, subsequent setPage, setPageSize, and setSorting calls update local settings but reuse the established subscription instead of opening one with new arguments. Do not rely on those setters to navigate or reorder an already subscribed result.

This limitation is separate from backend paging support and does not describe ordinary one-shot queries. Suspense uses separate resource caches; do not infer its behavior from this non-Suspense path. See query instance caching and verify the chosen hook/provider combination before adding live paging controls.

Paging information is available on result.paging:

PropertyTypeDescription
pagenumberCurrent zero-based page number
sizenumberItems per page
totalItemsnumberTotal items across all pages
totalPagesnumberTotal number of pages
HookDescription
MyQuery.useWithPaging(pageSize)Standard query with paging
MyQuery.useSuspenseWithPaging(pageSize)Suspense-compatible query with paging
MyObservableQuery.useWithPaging(pageSize)Initial observable paging; see the cached-subscription limitation above

Parameterized proxies accept (pageSize, args?, sorting?); parameterless enumerable proxies accept (pageSize, sorting?). Match the generated signature rather than inserting an arguments placeholder for a parameterless query.

Sorting is independent of paging. The following ordinary-query fragment shows initial sorting and a dynamic change; cached non-Suspense observables have the limitation described above.

import { Sorting, SortDirection } from '@cratis/arc/queries';
// Initial sorting
const [result] = AllAccounts.use(new Sorting('name', SortDirection.ascending));
// Change sorting dynamically
const [paged, perform, setSorting] = AllAccounts.useWithPaging(25);
await setSorting(new Sorting('balance', SortDirection.descending));

Ordinary automatic query-pipeline paging requires IQueryable<T>. A materialized IEnumerable<T> or List<T> does not gain automatic server slicing merely because a paging hook exists. An application/provider may explicitly consume paging context, including for observable ISubject results. Verify both returned rows and paging metadata against that provider.