Last active
December 18, 2025 13:06
-
-
Save isDipesh/fdfd5197e89447a9ed6ee48338fe3f5f to your computer and use it in GitHub Desktop.
Drizzle Query Pagination Util for Nitro/Nuxt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import type { H3Event } from 'h3' | |
| import { count } from 'drizzle-orm' | |
| const DEFAULT_PAGE_SIZE = 20 | |
| const MAX_PAGE_SIZE = 200 | |
| type PaginateableQuery<TQuery> = { | |
| limit: (limit: number | undefined) => PaginateableQuery<TQuery> | |
| offset: (offset: number | undefined) => PaginateableQuery<TQuery> | |
| orderBy: (orderBy: string) => PaginateableQuery<TQuery> | |
| } | |
| type Pagination = { | |
| page: number | |
| size: number | |
| count: number | |
| pages: number | |
| } | |
| export async function paginateResults<TQuery>( | |
| query: TQuery, | |
| event: H3Event, | |
| ) { | |
| const queryParams = getQuery(event) | |
| const page = queryParams.page ? parseInt(queryParams.page as string) : 1 | |
| const paginationConfig = useRuntimeConfig().public.pagination | |
| let size = Number(queryParams.size ?? (paginationConfig && typeof paginationConfig === 'object' && 'defaultSize' in paginationConfig && typeof paginationConfig.defaultSize === 'number' ? paginationConfig.defaultSize : DEFAULT_PAGE_SIZE)) | |
| const maxSize = paginationConfig && typeof paginationConfig === 'object' && 'maxSize' in paginationConfig && typeof paginationConfig.maxSize === 'number' ? Number(paginationConfig.maxSize) : MAX_PAGE_SIZE | |
| if (size > maxSize) { | |
| size = maxSize | |
| } | |
| const offset = (page - 1) * size | |
| const results = await (query as PaginateableQuery<TQuery>) | |
| .limit(size) | |
| .offset(offset) | |
| // @ts-expect-error - config is available in runtime but not in type | |
| query.config.fields = { resultCount: count() } | |
| const [{ resultCount }] = await (query as PaginateableQuery<TQuery>).limit(undefined).offset(undefined).orderBy('1') as unknown as { resultCount: number }[] | |
| const pages = Math.ceil(resultCount / size) | |
| if (page > pages) { | |
| throw createError({ | |
| statusCode: 404, | |
| statusMessage: 'Page not found', | |
| }) | |
| } | |
| return { | |
| results: results as unknown as Awaited<Promise<TQuery>>, | |
| pagination: { | |
| page, | |
| size, | |
| count: resultCount, | |
| pages, | |
| } as Pagination, | |
| } | |
| } |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Usage example:
Request:
Response:
{ "results": [ { "id": 6, "name": "Sarah Connor", "email": "[email protected]", "role": "admin" }, { "id": 7, "name": "Kyle Reese", "email": "[email protected]", "role": "user" }, { "id": 8, "name": "Rick Deckard", "email": "[email protected]", "role": "user" }, { "id": 9, "name": "Ellen Ripley", "email": "[email protected]", "role": "manager" }, { "id": 10, "name": "Marty McFly", "email": "[email protected]", "role": "user" } ], "pagination": { "page": 2, "size": 5, "count": 52, "pages": 11 } }Framework-agnostic Drizzle Pagination util:
https://gist.github.com/isDipesh/1b3aa2851bb59b053a1b67f38db806e0