ReviewOS

also looking at this

stacks/bun-query-builder

feat(paginate): add a spelling that cannot be transposed

#1130
Merged glennmichael123 wants to merge fix/1092-paginate-options into main
3 files +208 -5
packages/bun-query-builder/src/client.tsmodified+35-2
Changes to packages/bun-query-builder/src/client.ts
@@ -622,6 +622,28 @@ export type WhereExpression<TableColumns> =
622622 | { [K in keyof TableColumns & string]: [key: K, op: WhereOperator, value: WhereValue<TableColumns[K]>] }[keyof TableColumns & string]
623623 | WhereRaw
624624
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 */
638export 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
625647export type QueryResult = unknown
626648
627649/**
@@ -1930,7 +1952,7 @@ export interface BaseSelectQueryBuilder<
19301952 * const res2 = await db.selectFrom('users').where({ active: true }).paginate(25)
19311953 * ```
19321954 */
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 } }>)
19341956 /**
19351957 * # `simplePaginate`
19361958 *
@@ -5823,7 +5845,18 @@ export function createQueryBuilder<DB extends AnyDatabaseSchema>(state?: Partial
58235845 const e = await (this as any).exists()
58245846 return !e
58255847 },
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 }
58275860 if (!Number.isFinite(perPage) || perPage <= 0 || !Number.isInteger(perPage))
58285861 throw new TypeError(`[query-builder] paginate(perPage): expected positive integer, got ${perPage}`)
58295862 if (!Number.isFinite(page) || page < 1 || !Number.isInteger(page))