also looking at this
feat(paginate): add a spelling that cannot be transposed
#1130
3 files
+208
-5
| @@ -622,6 +622,28 @@ export type WhereExpression<TableColumns> = | ||
| 622 | 622 | | { [K in keyof TableColumns & string]: [key: K, op: WhereOperator, value: WhereValue<TableColumns[K]>] }[keyof TableColumns & string] |
| 623 | 623 | | WhereRaw |
| 624 | 624 | |
| 625 | /** | |
| 626 | * # `PaginateOptions` | |
| 627 | * | |
| 628 | * The unambiguous spelling of a paginate() call. | |
| 629 | * | |
| 630 | * `db.selectFrom(t).paginate(perPage, page)` and `Model.query().paginate(page, | |
| 631 | * perPage)` take the same two numbers in opposite orders, and both parameters | |
| 632 | * are `number` — so transposing them is not a type error, it just returns a | |
| 633 | * different page. Passing this object instead says which is which. | |
| 634 | * | |
| 635 | * Both APIs accept it and both keep their positional forms, so this adds a | |
| 636 | * safe spelling without moving anyone's existing call. See #1092. | |
| 637 | */ | |
| 638 | export interface PaginateOptions { | |
| 639 | /** Rows per page. Defaults to each API's existing default. */ | |
| 640 | perPage?: number | |
| 641 | /** 1-based page number. Defaults to 1. */ | |
| 642 | page?: number | |
| 643 | /** Run the count and the page query inside this transaction — see #1051. */ | |
| 644 | tx?: { unsafe: (sql: string, params?: any[]) => any } | |
| 645 | } | |
| 646 | ||
| 625 | 647 | export type QueryResult = unknown |
| 626 | 648 | |
| 627 | 649 | /** |
| @@ -1930,7 +1952,7 @@ export interface BaseSelectQueryBuilder< | ||
| 1930 | 1952 | * const res2 = await db.selectFrom('users').where({ active: true }).paginate(25) |
| 1931 | 1953 | * ``` |
| 1932 | 1954 | */ |
| 1933 | paginate: (perPage: number, page?: number, opts?: { tx?: { unsafe: (sql: string, params?: unknown[]) => unknown } }) => Promise<{ data: SelectedRow<DB, TTable, TSelected>[], meta: { perPage: number, page: number, total: number, lastPage: number } }> | |
| 1955 | paginate: ((perPage: number, page?: number, opts?: { tx?: { unsafe: (sql: string, params?: unknown[]) => unknown } }) => Promise<{ data: SelectedRow<DB, TTable, TSelected>[], meta: { perPage: number, page: number, total: number, lastPage: number } }>) & ((options: PaginateOptions) => Promise<{ data: SelectedRow<DB, TTable, TSelected>[], meta: { perPage: number, page: number, total: number, lastPage: number } }>) | |
| 1934 | 1956 | /** |
| 1935 | 1957 | * # `simplePaginate` |
| 1936 | 1958 | * |
| @@ -5823,7 +5845,18 @@ export function createQueryBuilder<DB extends AnyDatabaseSchema>(state?: Partial | ||
| 5823 | 5845 | const e = await (this as any).exists() |
| 5824 | 5846 | return !e |
| 5825 | 5847 | }, |
| 5826 | async paginate(perPage: number, page = 1, opts: { tx?: { unsafe: (sql: string, params?: any[]) => any } } = {}) { | |
| 5848 | async paginate(perPage: number | PaginateOptions, page = 1, opts: { tx?: { unsafe: (sql: string, params?: any[]) => any } } = {}) { | |
| 5849 | // Options form: `paginate({ perPage, page })`. The two paginate APIs in | |
| 5850 | // this library take the same two numbers in opposite orders — this one | |
| 5851 | // is (perPage, page), the ORM's is (page, perPage) — and both arguments | |
| 5852 | // are numbers, so getting it backwards is silent: you simply receive a | |
| 5853 | // different page. Naming them cannot be got wrong. See #1092. | |
| 5854 | if (typeof perPage === 'object' && perPage !== null) { | |
| 5855 | const options = perPage | |
| 5856 | page = options.page ?? 1 | |
| 5857 | opts = options.tx ? { tx: options.tx } : {} | |
| 5858 | perPage = options.perPage ?? 10 | |
| 5859 | } | |
| 5827 | 5860 | if (!Number.isFinite(perPage) || perPage <= 0 || !Number.isInteger(perPage)) |
| 5828 | 5861 | throw new TypeError(`[query-builder] paginate(perPage): expected positive integer, got ${perPage}`) |
| 5829 | 5862 | if (!Number.isFinite(page) || page < 1 || !Number.isInteger(page)) |