/** * Page-based pagination: reading `page` and `limit` from a query string, and * cutting fetched rows into a page. * * @module */ import { PAGINATION_DEFAULT_LIMIT, PAGINATION_MAX_LIMIT } from "../config.ts"; /** * Reads the `page` and `limit` query parameters. `page` is at least 1 and * defaults to 1; `limit` is clamped to [1, {@link PAGINATION_MAX_LIMIT}] and * defaults to `defaultLimit`. */ export function parsePagination( params: URLSearchParams, defaultLimit = PAGINATION_DEFAULT_LIMIT, ): { page: number; limit: number } { const page = Math.max( 1, parseInt(params.get("page") ?? "1") || 1, ); const limit = Math.min( Math.max( 1, parseInt(params.get("limit") ?? String(defaultLimit)) || defaultLimit, ), PAGINATION_MAX_LIMIT, ); return { page, limit }; } /** One page of a list, and whether another follows. */ export interface Page { /** The page's items, in order. */ items: T[]; /** Whether another page follows this one. */ hasMore: boolean; } /** * Turns rows fetched with `LIMIT limit + 1` into a page: the extra row, if it * came back, is dropped and says there's a next page. No COUNT(*) over the * whole list just to know that. */ export function pageOf(rows: T[], limit: number): Page { return rows.length > limit ? { items: rows.slice(0, limit), hasMore: true } : { items: rows, hasMore: false }; }