53 lines
1.4 KiB
TypeScript
53 lines
1.4 KiB
TypeScript
/**
|
|
* Reads the page a list route's query string asks for, and cuts the rows a
|
|
* service fetched into that page. The routes send the page as
|
|
* `PaginatedData`.
|
|
*
|
|
* @module
|
|
*/
|
|
|
|
import { PAGINATION_DEFAULT_LIMIT, PAGINATION_MAX_LIMIT } from "../config.ts";
|
|
|
|
/**
|
|
* Reads the `page` and `limit` query parameters of a list route. It never
|
|
* fails: a missing or invalid `page` reads as 1, and `limit` is kept between 1
|
|
* and {@link PAGINATION_MAX_LIMIT}.
|
|
*/
|
|
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 };
|
|
}
|
|
|
|
/**
|
|
* Returned to the routes by the services' list functions, and sent as
|
|
* `PaginatedData`.
|
|
*/
|
|
export interface Page<T> {
|
|
items: T[];
|
|
hasMore: boolean;
|
|
}
|
|
|
|
/**
|
|
* Turns rows fetched with `LIMIT limit + 1` into a page. The extra row, when it
|
|
* comes back, is dropped and tells that another page follows, which spares a
|
|
* COUNT(*) over the whole list.
|
|
*/
|
|
export function pageOf<T>(rows: T[], limit: number): Page<T> {
|
|
return rows.length > limit
|
|
? { items: rows.slice(0, limit), hasMore: true }
|
|
: { items: rows, hasMore: false };
|
|
}
|