@geekmidas/db 1.0.0 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/kysely/pagination.cjs +15 -41
  3. package/dist/kysely/pagination.cjs.map +1 -1
  4. package/dist/kysely/pagination.d.cts +12 -34
  5. package/dist/kysely/pagination.d.cts.map +1 -1
  6. package/dist/kysely/pagination.d.mts +12 -34
  7. package/dist/kysely/pagination.d.mts.map +1 -1
  8. package/dist/kysely/pagination.mjs +11 -36
  9. package/dist/kysely/pagination.mjs.map +1 -1
  10. package/dist/{kysely-DUdsB0BP.d.mts → kysely-Dm1w5gAY.d.mts} +1 -1
  11. package/dist/{kysely-DUdsB0BP.d.mts.map → kysely-Dm1w5gAY.d.mts.map} +1 -1
  12. package/dist/kysely.d.mts +1 -1
  13. package/dist/objection/pagination.cjs +50 -0
  14. package/dist/objection/pagination.cjs.map +1 -0
  15. package/dist/objection/pagination.d.cts +51 -0
  16. package/dist/objection/pagination.d.cts.map +1 -0
  17. package/dist/objection/pagination.d.mts +51 -0
  18. package/dist/objection/pagination.d.mts.map +1 -0
  19. package/dist/objection/pagination.mjs +47 -0
  20. package/dist/objection/pagination.mjs.map +1 -0
  21. package/dist/pagination-BAFX7C1I.d.cts +32 -0
  22. package/dist/pagination-BAFX7C1I.d.cts.map +1 -0
  23. package/dist/pagination-BDLa7Yb_.mjs +37 -0
  24. package/dist/pagination-BDLa7Yb_.mjs.map +1 -0
  25. package/dist/pagination-Bdoa4PVj.cjs +55 -0
  26. package/dist/pagination-Bdoa4PVj.cjs.map +1 -0
  27. package/dist/pagination-BziGl-B8.d.mts +32 -0
  28. package/dist/pagination-BziGl-B8.d.mts.map +1 -0
  29. package/dist/pagination.cjs +5 -0
  30. package/dist/pagination.d.cts +2 -0
  31. package/dist/pagination.d.mts +2 -0
  32. package/dist/pagination.mjs +3 -0
  33. package/dist/rls.d.mts +1 -1
  34. package/package.json +45 -10
  35. package/src/__tests__/rls.spec.ts +272 -0
  36. package/src/kysely/pagination.ts +20 -57
  37. package/src/objection/__tests__/pagination.integration.spec.ts +291 -0
  38. package/src/objection/pagination.ts +98 -0
  39. package/src/pagination.ts +49 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # @geekmidas/db
2
2
 
3
+ ## 1.0.2
4
+
5
+ ### Patch Changes
6
+
7
+ - 🐛 [`d70c6c0`](https://github.com/geekmidas/toolbox/commit/d70c6c0aeb8a79da2473ac77dbd8255a4a2f5651) Thanks [@geekmidas](https://github.com/geekmidas)! - Fix `package.json` exports so TypeScript declarations resolve correctly under NodeNext/Bundler module resolution. Each subpath export now nests `types` inside its `import`/`require` condition, pointing at the `.d.mts` and `.d.cts` files that `tsdown` actually emits (previously the exports referenced non-existent `.d.ts` files, causing type-resolution failures for consumers). Both ESM (`.mjs`) and CJS (`.cjs`) runtime entry points are preserved. Additionally, `@geekmidas/ui` had `import` paths pointing at `.js` files that were never emitted — those are corrected to `.mjs`.
8
+
9
+ ## 1.0.1
10
+
11
+ ### Patch Changes
12
+
13
+ - ✨ [`ac041cc`](https://github.com/geekmidas/toolbox/commit/ac041cc459e87107ffb4e508e85c04c3079bf040) Thanks [@geekmidas](https://github.com/geekmidas)! - Add objection pagination and fix secret loading for server apps
14
+
3
15
  ## 1.0.0
4
16
 
5
17
  ### Major Changes
@@ -1,14 +1,7 @@
1
+ const require_pagination = require('../pagination-Bdoa4PVj.cjs');
1
2
 
2
3
  //#region src/kysely/pagination.ts
3
4
  /**
4
- * Sort direction for cursor-based pagination.
5
- */
6
- let Direction = /* @__PURE__ */ function(Direction$1) {
7
- Direction$1["Asc"] = "asc";
8
- Direction$1["Desc"] = "desc";
9
- return Direction$1;
10
- }({});
11
- /**
12
5
  * Generic paginated search function that handles:
13
6
  * - Total count calculation
14
7
  * - Cursor-based pagination
@@ -17,22 +10,26 @@ let Direction = /* @__PURE__ */ function(Direction$1) {
17
10
  *
18
11
  * @example
19
12
  * ```typescript
13
+ * // With mapRow
20
14
  * const result = await paginatedSearch({
21
15
  * query: db.selectFrom('users').selectAll(),
22
- * cursor: previousCursor,
23
16
  * limit: 20,
24
17
  * mapRow: (row) => ({ id: row.id, name: row.name }),
25
- * cursorField: 'id',
26
- * cursorDirection: Direction.Asc,
18
+ * });
19
+ *
20
+ * // Without mapRow — items are the raw row type
21
+ * const result = await paginatedSearch({
22
+ * query: db.selectFrom('users').selectAll(),
23
+ * limit: 20,
27
24
  * });
28
25
  * ```
29
26
  */
30
- async function paginatedSearch({ query, cursor, limit = 20, mapRow, cursorField = "id", cursorDirection = Direction.Asc }) {
27
+ async function paginatedSearch({ query, cursor, limit = 20, mapRow, cursorField = "id", cursorDirection = require_pagination.Direction.Asc }) {
31
28
  const countResult = await query.clearSelect().clearOrderBy().select((eb) => eb.fn.countAll().as("count")).executeTakeFirstOrThrow();
32
29
  const count = countResult.count;
33
30
  let paginatedQuery = query;
34
31
  if (cursor) {
35
- const operator = cursorDirection === Direction.Asc ? ">" : "<";
32
+ const operator = cursorDirection === require_pagination.Direction.Asc ? ">" : "<";
36
33
  paginatedQuery = paginatedQuery.where(cursorField, operator, cursor);
37
34
  }
38
35
  const data = await paginatedQuery.orderBy(cursorField, cursorDirection).limit(limit + 1).execute();
@@ -40,7 +37,8 @@ async function paginatedSearch({ query, cursor, limit = 20, mapRow, cursorField
40
37
  const rows = hasMore ? data.slice(0, limit) : data;
41
38
  const lastRow = rows[rows.length - 1];
42
39
  const nextCursor = hasMore && lastRow ? String(lastRow[cursorField]) : void 0;
43
- const items = await Promise.all(rows.map(mapRow));
40
+ const mapper = mapRow ?? ((row) => row);
41
+ const items = await Promise.all(rows.map(mapper));
44
42
  return {
45
43
  items,
46
44
  pagination: {
@@ -50,34 +48,10 @@ async function paginatedSearch({ query, cursor, limit = 20, mapRow, cursorField
50
48
  }
51
49
  };
52
50
  }
53
- /**
54
- * Encode a cursor value for safe URL transmission.
55
- * Supports various types: string, number, Date, etc.
56
- */
57
- function encodeCursor(value) {
58
- const payload = {
59
- v: value instanceof Date ? value.toISOString() : value,
60
- t: value instanceof Date ? "date" : typeof value
61
- };
62
- return Buffer.from(JSON.stringify(payload)).toString("base64url");
63
- }
64
- /**
65
- * Decode a cursor string back to its original value.
66
- */
67
- function decodeCursor(cursor) {
68
- try {
69
- const json = Buffer.from(cursor, "base64url").toString("utf-8");
70
- const payload = JSON.parse(json);
71
- if (payload.t === "date") return new Date(payload.v);
72
- return payload.v;
73
- } catch {
74
- throw new Error("Invalid cursor format");
75
- }
76
- }
77
51
 
78
52
  //#endregion
79
- exports.Direction = Direction;
80
- exports.decodeCursor = decodeCursor;
81
- exports.encodeCursor = encodeCursor;
53
+ exports.Direction = require_pagination.Direction;
54
+ exports.decodeCursor = require_pagination.decodeCursor;
55
+ exports.encodeCursor = require_pagination.encodeCursor;
82
56
  exports.paginatedSearch = paginatedSearch;
83
57
  //# sourceMappingURL=pagination.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"pagination.cjs","names":["value: unknown","cursor: string"],"sources":["../../src/kysely/pagination.ts"],"sourcesContent":["import type { SelectQueryBuilder } from 'kysely';\n\n/**\n * Sort direction for cursor-based pagination.\n */\nexport enum Direction {\n\tAsc = 'asc',\n\tDesc = 'desc',\n}\n\n/**\n * Result of a paginated query.\n */\nexport interface PaginationResult<TItem> {\n\titems: TItem[];\n\tpagination: {\n\t\ttotal: number;\n\t\thasMore: boolean;\n\t\tcursor?: string;\n\t};\n}\n\n/**\n * Options for paginated search.\n */\nexport interface PaginatedSearchOptions<\n\tTRow,\n\tTMapRow extends (row: TRow) => unknown,\n> {\n\t/** The base Kysely query to paginate */\n\tquery: SelectQueryBuilder<any, any, TRow>;\n\t/** Cursor value for pagination (value of cursorField from previous page) */\n\tcursor?: string;\n\t/** Maximum number of items per page (default: 20) */\n\tlimit?: number;\n\t/** Function to transform each row to the output format */\n\tmapRow: TMapRow;\n\t/** Field to use for cursor pagination (default: 'id') */\n\tcursorField?: string;\n\t/** Sort direction for cursor field (default: Direction.Asc) */\n\tcursorDirection?: Direction;\n}\n\n/**\n * Generic paginated search function that handles:\n * - Total count calculation\n * - Cursor-based pagination\n * - Fetching one extra row to determine hasMore\n * - Mapping rows to output format\n *\n * @example\n * ```typescript\n * const result = await paginatedSearch({\n * query: db.selectFrom('users').selectAll(),\n * cursor: previousCursor,\n * limit: 20,\n * mapRow: (row) => ({ id: row.id, name: row.name }),\n * cursorField: 'id',\n * cursorDirection: Direction.Asc,\n * });\n * ```\n */\nexport async function paginatedSearch<\n\tTRow extends Record<string, unknown>,\n\tTMapRow extends (row: TRow) => unknown,\n>({\n\tquery,\n\tcursor,\n\tlimit = 20,\n\tmapRow,\n\tcursorField = 'id',\n\tcursorDirection = Direction.Asc,\n}: PaginatedSearchOptions<TRow, TMapRow>): Promise<\n\tPaginationResult<Awaited<ReturnType<TMapRow>>>\n> {\n\t// Get total count (without cursor)\n\tconst countResult = await query\n\t\t.clearSelect()\n\t\t.clearOrderBy()\n\t\t.select((eb) => eb.fn.countAll().as('count'))\n\t\t.executeTakeFirstOrThrow();\n\n\tconst count = countResult.count;\n\n\t// Apply cursor if provided\n\tlet paginatedQuery = query;\n\tif (cursor) {\n\t\tconst operator = cursorDirection === Direction.Asc ? '>' : '<';\n\t\tpaginatedQuery = paginatedQuery.where(\n\t\t\tcursorField as any,\n\t\t\toperator,\n\t\t\tcursor,\n\t\t) as typeof query;\n\t}\n\n\t// Fetch one extra to determine if there are more results\n\tconst data = await paginatedQuery\n\t\t.orderBy(cursorField as any, cursorDirection)\n\t\t.limit(limit + 1)\n\t\t.execute();\n\n\tconst hasMore = data.length > limit;\n\tconst rows = hasMore ? data.slice(0, limit) : data;\n\tconst lastRow = rows[rows.length - 1];\n\tconst nextCursor =\n\t\thasMore && lastRow ? String(lastRow[cursorField]) : undefined;\n\n\tconst items = (await Promise.all(rows.map(mapRow))) as Awaited<\n\t\tReturnType<TMapRow>\n\t>[];\n\n\treturn {\n\t\titems,\n\t\tpagination: {\n\t\t\ttotal: Number(count),\n\t\t\thasMore,\n\t\t\tcursor: nextCursor,\n\t\t},\n\t};\n}\n\n/**\n * Encode a cursor value for safe URL transmission.\n * Supports various types: string, number, Date, etc.\n */\nexport function encodeCursor(value: unknown): string {\n\tconst payload = {\n\t\tv: value instanceof Date ? value.toISOString() : value,\n\t\tt: value instanceof Date ? 'date' : typeof value,\n\t};\n\treturn Buffer.from(JSON.stringify(payload)).toString('base64url');\n}\n\n/**\n * Decode a cursor string back to its original value.\n */\nexport function decodeCursor(cursor: string): unknown {\n\ttry {\n\t\tconst json = Buffer.from(cursor, 'base64url').toString('utf-8');\n\t\tconst payload = JSON.parse(json);\n\n\t\tif (payload.t === 'date') {\n\t\t\treturn new Date(payload.v);\n\t\t}\n\n\t\treturn payload.v;\n\t} catch {\n\t\tthrow new Error('Invalid cursor format');\n\t}\n}\n"],"mappings":";;;;;AAKA,IAAY,kDAAL;AACN;AACA;;AACA;;;;;;;;;;;;;;;;;;;;AAsDD,eAAsB,gBAGpB,EACD,OACA,QACA,QAAQ,IACR,QACA,cAAc,MACd,kBAAkB,UAAU,KACW,EAEtC;CAED,MAAM,cAAc,MAAM,MACxB,aAAa,CACb,cAAc,CACd,OAAO,CAAC,OAAO,GAAG,GAAG,UAAU,CAAC,GAAG,QAAQ,CAAC,CAC5C,yBAAyB;CAE3B,MAAM,QAAQ,YAAY;CAG1B,IAAI,iBAAiB;AACrB,KAAI,QAAQ;EACX,MAAM,WAAW,oBAAoB,UAAU,MAAM,MAAM;AAC3D,mBAAiB,eAAe,MAC/B,aACA,UACA,OACA;CACD;CAGD,MAAM,OAAO,MAAM,eACjB,QAAQ,aAAoB,gBAAgB,CAC5C,MAAM,QAAQ,EAAE,CAChB,SAAS;CAEX,MAAM,UAAU,KAAK,SAAS;CAC9B,MAAM,OAAO,UAAU,KAAK,MAAM,GAAG,MAAM,GAAG;CAC9C,MAAM,UAAU,KAAK,KAAK,SAAS;CACnC,MAAM,aACL,WAAW,UAAU,OAAO,QAAQ,aAAa;CAElD,MAAM,QAAS,MAAM,QAAQ,IAAI,KAAK,IAAI,OAAO,CAAC;AAIlD,QAAO;EACN;EACA,YAAY;GACX,OAAO,OAAO,MAAM;GACpB;GACA,QAAQ;EACR;CACD;AACD;;;;;AAMD,SAAgB,aAAaA,OAAwB;CACpD,MAAM,UAAU;EACf,GAAG,iBAAiB,OAAO,MAAM,aAAa,GAAG;EACjD,GAAG,iBAAiB,OAAO,gBAAgB;CAC3C;AACD,QAAO,OAAO,KAAK,KAAK,UAAU,QAAQ,CAAC,CAAC,SAAS,YAAY;AACjE;;;;AAKD,SAAgB,aAAaC,QAAyB;AACrD,KAAI;EACH,MAAM,OAAO,OAAO,KAAK,QAAQ,YAAY,CAAC,SAAS,QAAQ;EAC/D,MAAM,UAAU,KAAK,MAAM,KAAK;AAEhC,MAAI,QAAQ,MAAM,OACjB,QAAO,IAAI,KAAK,QAAQ;AAGzB,SAAO,QAAQ;CACf,QAAO;AACP,QAAM,IAAI,MAAM;CAChB;AACD"}
1
+ {"version":3,"file":"pagination.cjs","names":["Direction","row: TRow"],"sources":["../../src/kysely/pagination.ts"],"sourcesContent":["import type { SelectQueryBuilder } from 'kysely';\nimport {\n\tDirection,\n\tdecodeCursor,\n\tencodeCursor,\n\ttype PaginationResult,\n} from '../pagination';\n\nexport { Direction, decodeCursor, encodeCursor, type PaginationResult };\n\n/**\n * Options for paginated search.\n */\nexport interface PaginatedSearchOptions<\n\tTRow,\n\tTMapRow extends (row: TRow) => unknown = (row: TRow) => TRow,\n> {\n\t/** The base Kysely query to paginate */\n\tquery: SelectQueryBuilder<any, any, TRow>;\n\t/** Cursor value for pagination (value of cursorField from previous page) */\n\tcursor?: string;\n\t/** Maximum number of items per page (default: 20) */\n\tlimit?: number;\n\t/** Function to transform each row to the output format (default: identity) */\n\tmapRow?: TMapRow;\n\t/** Field to use for cursor pagination (default: 'id') */\n\tcursorField?: string;\n\t/** Sort direction for cursor field (default: Direction.Asc) */\n\tcursorDirection?: Direction;\n}\n\n/**\n * Generic paginated search function that handles:\n * - Total count calculation\n * - Cursor-based pagination\n * - Fetching one extra row to determine hasMore\n * - Mapping rows to output format\n *\n * @example\n * ```typescript\n * // With mapRow\n * const result = await paginatedSearch({\n * query: db.selectFrom('users').selectAll(),\n * limit: 20,\n * mapRow: (row) => ({ id: row.id, name: row.name }),\n * });\n *\n * // Without mapRow — items are the raw row type\n * const result = await paginatedSearch({\n * query: db.selectFrom('users').selectAll(),\n * limit: 20,\n * });\n * ```\n */\nexport async function paginatedSearch<\n\tTRow extends Record<string, unknown>,\n\tTMapRow extends (row: TRow) => unknown = (row: TRow) => TRow,\n>({\n\tquery,\n\tcursor,\n\tlimit = 20,\n\tmapRow,\n\tcursorField = 'id',\n\tcursorDirection = Direction.Asc,\n}: PaginatedSearchOptions<TRow, TMapRow>): Promise<\n\tPaginationResult<Awaited<ReturnType<TMapRow>>>\n> {\n\t// Get total count (without cursor)\n\tconst countResult = await query\n\t\t.clearSelect()\n\t\t.clearOrderBy()\n\t\t.select((eb) => eb.fn.countAll().as('count'))\n\t\t.executeTakeFirstOrThrow();\n\n\tconst count = countResult.count;\n\n\t// Apply cursor if provided\n\tlet paginatedQuery = query;\n\tif (cursor) {\n\t\tconst operator = cursorDirection === Direction.Asc ? '>' : '<';\n\t\tpaginatedQuery = paginatedQuery.where(\n\t\t\tcursorField as any,\n\t\t\toperator,\n\t\t\tcursor,\n\t\t) as typeof query;\n\t}\n\n\t// Fetch one extra to determine if there are more results\n\tconst data = await paginatedQuery\n\t\t.orderBy(cursorField as any, cursorDirection)\n\t\t.limit(limit + 1)\n\t\t.execute();\n\n\tconst hasMore = data.length > limit;\n\tconst rows = hasMore ? data.slice(0, limit) : data;\n\tconst lastRow = rows[rows.length - 1];\n\tconst nextCursor =\n\t\thasMore && lastRow ? String(lastRow[cursorField]) : undefined;\n\n\tconst mapper = mapRow ?? ((row: TRow) => row);\n\tconst items = (await Promise.all(rows.map(mapper))) as Awaited<\n\t\tReturnType<TMapRow>\n\t>[];\n\n\treturn {\n\t\titems,\n\t\tpagination: {\n\t\t\ttotal: Number(count),\n\t\t\thasMore,\n\t\t\tcursor: nextCursor,\n\t\t},\n\t};\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAsDA,eAAsB,gBAGpB,EACD,OACA,QACA,QAAQ,IACR,QACA,cAAc,MACd,kBAAkBA,6BAAU,KACW,EAEtC;CAED,MAAM,cAAc,MAAM,MACxB,aAAa,CACb,cAAc,CACd,OAAO,CAAC,OAAO,GAAG,GAAG,UAAU,CAAC,GAAG,QAAQ,CAAC,CAC5C,yBAAyB;CAE3B,MAAM,QAAQ,YAAY;CAG1B,IAAI,iBAAiB;AACrB,KAAI,QAAQ;EACX,MAAM,WAAW,oBAAoBA,6BAAU,MAAM,MAAM;AAC3D,mBAAiB,eAAe,MAC/B,aACA,UACA,OACA;CACD;CAGD,MAAM,OAAO,MAAM,eACjB,QAAQ,aAAoB,gBAAgB,CAC5C,MAAM,QAAQ,EAAE,CAChB,SAAS;CAEX,MAAM,UAAU,KAAK,SAAS;CAC9B,MAAM,OAAO,UAAU,KAAK,MAAM,GAAG,MAAM,GAAG;CAC9C,MAAM,UAAU,KAAK,KAAK,SAAS;CACnC,MAAM,aACL,WAAW,UAAU,OAAO,QAAQ,aAAa;CAElD,MAAM,SAAS,WAAW,CAACC,QAAc;CACzC,MAAM,QAAS,MAAM,QAAQ,IAAI,KAAK,IAAI,OAAO,CAAC;AAIlD,QAAO;EACN;EACA,YAAY;GACX,OAAO,OAAO,MAAM;GACpB;GACA,QAAQ;EACR;CACD;AACD"}
@@ -1,37 +1,20 @@
1
+ import { Direction, PaginationResult, decodeCursor, encodeCursor } from "../pagination-BAFX7C1I.cjs";
1
2
  import { SelectQueryBuilder } from "kysely";
2
3
 
3
4
  //#region src/kysely/pagination.d.ts
4
5
 
5
- /**
6
- * Sort direction for cursor-based pagination.
7
- */
8
- declare enum Direction {
9
- Asc = "asc",
10
- Desc = "desc",
11
- }
12
- /**
13
- * Result of a paginated query.
14
- */
15
- interface PaginationResult<TItem> {
16
- items: TItem[];
17
- pagination: {
18
- total: number;
19
- hasMore: boolean;
20
- cursor?: string;
21
- };
22
- }
23
6
  /**
24
7
  * Options for paginated search.
25
8
  */
26
- interface PaginatedSearchOptions<TRow, TMapRow extends (row: TRow) => unknown> {
9
+ interface PaginatedSearchOptions<TRow, TMapRow extends (row: TRow) => unknown = (row: TRow) => TRow> {
27
10
  /** The base Kysely query to paginate */
28
11
  query: SelectQueryBuilder<any, any, TRow>;
29
12
  /** Cursor value for pagination (value of cursorField from previous page) */
30
13
  cursor?: string;
31
14
  /** Maximum number of items per page (default: 20) */
32
15
  limit?: number;
33
- /** Function to transform each row to the output format */
34
- mapRow: TMapRow;
16
+ /** Function to transform each row to the output format (default: identity) */
17
+ mapRow?: TMapRow;
35
18
  /** Field to use for cursor pagination (default: 'id') */
36
19
  cursorField?: string;
37
20
  /** Sort direction for cursor field (default: Direction.Asc) */
@@ -46,17 +29,21 @@ interface PaginatedSearchOptions<TRow, TMapRow extends (row: TRow) => unknown> {
46
29
  *
47
30
  * @example
48
31
  * ```typescript
32
+ * // With mapRow
49
33
  * const result = await paginatedSearch({
50
34
  * query: db.selectFrom('users').selectAll(),
51
- * cursor: previousCursor,
52
35
  * limit: 20,
53
36
  * mapRow: (row) => ({ id: row.id, name: row.name }),
54
- * cursorField: 'id',
55
- * cursorDirection: Direction.Asc,
37
+ * });
38
+ *
39
+ * // Without mapRow — items are the raw row type
40
+ * const result = await paginatedSearch({
41
+ * query: db.selectFrom('users').selectAll(),
42
+ * limit: 20,
56
43
  * });
57
44
  * ```
58
45
  */
59
- declare function paginatedSearch<TRow extends Record<string, unknown>, TMapRow extends (row: TRow) => unknown>({
46
+ declare function paginatedSearch<TRow extends Record<string, unknown>, TMapRow extends (row: TRow) => unknown = (row: TRow) => TRow>({
60
47
  query,
61
48
  cursor,
62
49
  limit,
@@ -64,15 +51,6 @@ declare function paginatedSearch<TRow extends Record<string, unknown>, TMapRow e
64
51
  cursorField,
65
52
  cursorDirection
66
53
  }: PaginatedSearchOptions<TRow, TMapRow>): Promise<PaginationResult<Awaited<ReturnType<TMapRow>>>>;
67
- /**
68
- * Encode a cursor value for safe URL transmission.
69
- * Supports various types: string, number, Date, etc.
70
- */
71
- declare function encodeCursor(value: unknown): string;
72
- /**
73
- * Decode a cursor string back to its original value.
74
- */
75
- declare function decodeCursor(cursor: string): unknown;
76
54
  //# sourceMappingURL=pagination.d.ts.map
77
55
  //#endregion
78
56
  export { Direction, PaginatedSearchOptions, PaginationResult, decodeCursor, encodeCursor, paginatedSearch };
@@ -1 +1 @@
1
- {"version":3,"file":"pagination.d.cts","names":[],"sources":["../../src/kysely/pagination.ts"],"sourcesContent":[],"mappings":";;;;;;AAKA;AAQiB,aARL,SAAA;EAoBK,GAAA,GAAA,KAAA;EAAsB,IAAA,GAAA,MAAA;;;;;AAepB,UA3BF,gBA2BE,CAAA,KAAA,CAAA,CAAA;EAAS,KAAA,EA1BpB,KA0BoB,EAAA;EAsBN,UAAA,EAAA;IAAe,KAAA,EAAA,MAAA;IACvB,OAAA,EAAA,OAAA;IACS,MAAA,CAAA,EAAA,MAAA;EAAI,CAAA;;;;;AAO1B,UA9CgB,sBA8ChB,CAAA,IAAA,EAAA,gBAAA,CAAA,GAAA,EA5CsB,IA4CtB,EAAA,GAAA,OAAA,CAAA,CAAA;EAA+B;EACF,KAAE,EA1CxB,kBA0CwB,CAAA,GAAA,EAAA,GAAA,EA1CK,IA0CL,CAAA;EAAO;EAAd,MACY,CAAA,EAAA,MAAA;EAAO;EAAR,KAAlB,CAAA,EAAA,MAAA;EAAO;EAAR,MAD0B,EApClC,OAoCkC;EAAO;EAqDlC,WAAA,CAAA,EAAA,MAAY;EAWZ;oBAhGG;;;;;;;;;;;;;;;;;;;;;iBAsBG,6BACR,+CACS;;;;;;;GAQpB,uBAAuB,MAAM,WAAW,QAC1C,iBAAiB,QAAQ,WAAW;;;;;iBAoDrB,YAAA;;;;iBAWA,YAAA"}
1
+ {"version":3,"file":"pagination.d.cts","names":[],"sources":["../../src/kysely/pagination.ts"],"sourcesContent":[],"mappings":";;;;;;AAaA;;AAEuB,UAFN,sBAEM,CAAA,IAAA,EAAA,gBAAA,CAAA,GAAA,EAAA,IAAA,EAAA,GAAA,OAAA,GAAA,CAAA,GAAA,EAAyB,IAAzB,EAAA,GAAkC,IAAlC,CAAA,CAAA;EAAI;EAAyB,KAAK,EAGjD,kBAHiD,CAAA,GAAA,EAAA,GAAA,EAGpB,IAHoB,CAAA;EAAI;EAGpB,MAAjC,CAAA,EAAA,MAAA;EAAkB;EAMT,KAIE,CAAA,EAAA,MAAA;EAAS;EA0BN,MAAA,CAAA,EA9BZ,OA8BY;EAAe;EAAA,WACvB,CAAA,EAAA,MAAA;EAAM;EACO,eAAqB,CAAA,EA5B7B,SA4B6B;;;;;;;;;;;;;;;;AAQE;;;;;;;;;iBAV5B,6BACR,+CACS,yBAAyB,SAAS;;;;;;;GAQtD,uBAAuB,MAAM,WAAW,QAC1C,iBAAiB,QAAQ,WAAW"}
@@ -1,37 +1,20 @@
1
+ import { Direction, PaginationResult, decodeCursor, encodeCursor } from "../pagination-BziGl-B8.mjs";
1
2
  import { SelectQueryBuilder } from "kysely";
2
3
 
3
4
  //#region src/kysely/pagination.d.ts
4
5
 
5
- /**
6
- * Sort direction for cursor-based pagination.
7
- */
8
- declare enum Direction {
9
- Asc = "asc",
10
- Desc = "desc",
11
- }
12
- /**
13
- * Result of a paginated query.
14
- */
15
- interface PaginationResult<TItem> {
16
- items: TItem[];
17
- pagination: {
18
- total: number;
19
- hasMore: boolean;
20
- cursor?: string;
21
- };
22
- }
23
6
  /**
24
7
  * Options for paginated search.
25
8
  */
26
- interface PaginatedSearchOptions<TRow, TMapRow extends (row: TRow) => unknown> {
9
+ interface PaginatedSearchOptions<TRow, TMapRow extends (row: TRow) => unknown = (row: TRow) => TRow> {
27
10
  /** The base Kysely query to paginate */
28
11
  query: SelectQueryBuilder<any, any, TRow>;
29
12
  /** Cursor value for pagination (value of cursorField from previous page) */
30
13
  cursor?: string;
31
14
  /** Maximum number of items per page (default: 20) */
32
15
  limit?: number;
33
- /** Function to transform each row to the output format */
34
- mapRow: TMapRow;
16
+ /** Function to transform each row to the output format (default: identity) */
17
+ mapRow?: TMapRow;
35
18
  /** Field to use for cursor pagination (default: 'id') */
36
19
  cursorField?: string;
37
20
  /** Sort direction for cursor field (default: Direction.Asc) */
@@ -46,17 +29,21 @@ interface PaginatedSearchOptions<TRow, TMapRow extends (row: TRow) => unknown> {
46
29
  *
47
30
  * @example
48
31
  * ```typescript
32
+ * // With mapRow
49
33
  * const result = await paginatedSearch({
50
34
  * query: db.selectFrom('users').selectAll(),
51
- * cursor: previousCursor,
52
35
  * limit: 20,
53
36
  * mapRow: (row) => ({ id: row.id, name: row.name }),
54
- * cursorField: 'id',
55
- * cursorDirection: Direction.Asc,
37
+ * });
38
+ *
39
+ * // Without mapRow — items are the raw row type
40
+ * const result = await paginatedSearch({
41
+ * query: db.selectFrom('users').selectAll(),
42
+ * limit: 20,
56
43
  * });
57
44
  * ```
58
45
  */
59
- declare function paginatedSearch<TRow extends Record<string, unknown>, TMapRow extends (row: TRow) => unknown>({
46
+ declare function paginatedSearch<TRow extends Record<string, unknown>, TMapRow extends (row: TRow) => unknown = (row: TRow) => TRow>({
60
47
  query,
61
48
  cursor,
62
49
  limit,
@@ -64,15 +51,6 @@ declare function paginatedSearch<TRow extends Record<string, unknown>, TMapRow e
64
51
  cursorField,
65
52
  cursorDirection
66
53
  }: PaginatedSearchOptions<TRow, TMapRow>): Promise<PaginationResult<Awaited<ReturnType<TMapRow>>>>;
67
- /**
68
- * Encode a cursor value for safe URL transmission.
69
- * Supports various types: string, number, Date, etc.
70
- */
71
- declare function encodeCursor(value: unknown): string;
72
- /**
73
- * Decode a cursor string back to its original value.
74
- */
75
- declare function decodeCursor(cursor: string): unknown;
76
54
  //# sourceMappingURL=pagination.d.ts.map
77
55
  //#endregion
78
56
  export { Direction, PaginatedSearchOptions, PaginationResult, decodeCursor, encodeCursor, paginatedSearch };
@@ -1 +1 @@
1
- {"version":3,"file":"pagination.d.mts","names":[],"sources":["../../src/kysely/pagination.ts"],"sourcesContent":[],"mappings":";;;;;;AAKA;AAQiB,aARL,SAAA;EAoBK,GAAA,GAAA,KAAA;EAAsB,IAAA,GAAA,MAAA;;;;;AAepB,UA3BF,gBA2BE,CAAA,KAAA,CAAA,CAAA;EAAS,KAAA,EA1BpB,KA0BoB,EAAA;EAsBN,UAAA,EAAA;IAAe,KAAA,EAAA,MAAA;IACvB,OAAA,EAAA,OAAA;IACS,MAAA,CAAA,EAAA,MAAA;EAAI,CAAA;;;;;AAO1B,UA9CgB,sBA8ChB,CAAA,IAAA,EAAA,gBAAA,CAAA,GAAA,EA5CsB,IA4CtB,EAAA,GAAA,OAAA,CAAA,CAAA;EAA+B;EACF,KAAE,EA1CxB,kBA0CwB,CAAA,GAAA,EAAA,GAAA,EA1CK,IA0CL,CAAA;EAAO;EAAd,MACY,CAAA,EAAA,MAAA;EAAO;EAAR,KAAlB,CAAA,EAAA,MAAA;EAAO;EAAR,MAD0B,EApClC,OAoCkC;EAAO;EAqDlC,WAAA,CAAA,EAAA,MAAY;EAWZ;oBAhGG;;;;;;;;;;;;;;;;;;;;;iBAsBG,6BACR,+CACS;;;;;;;GAQpB,uBAAuB,MAAM,WAAW,QAC1C,iBAAiB,QAAQ,WAAW;;;;;iBAoDrB,YAAA;;;;iBAWA,YAAA"}
1
+ {"version":3,"file":"pagination.d.mts","names":[],"sources":["../../src/kysely/pagination.ts"],"sourcesContent":[],"mappings":";;;;;;AAaA;;AAEuB,UAFN,sBAEM,CAAA,IAAA,EAAA,gBAAA,CAAA,GAAA,EAAA,IAAA,EAAA,GAAA,OAAA,GAAA,CAAA,GAAA,EAAyB,IAAzB,EAAA,GAAkC,IAAlC,CAAA,CAAA;EAAI;EAAyB,KAAK,EAGjD,kBAHiD,CAAA,GAAA,EAAA,GAAA,EAGpB,IAHoB,CAAA;EAAI;EAGpB,MAAjC,CAAA,EAAA,MAAA;EAAkB;EAMT,KAIE,CAAA,EAAA,MAAA;EAAS;EA0BN,MAAA,CAAA,EA9BZ,OA8BY;EAAe;EAAA,WACvB,CAAA,EAAA,MAAA;EAAM;EACO,eAAqB,CAAA,EA5B7B,SA4B6B;;;;;;;;;;;;;;;;AAQE;;;;;;;;;iBAV5B,6BACR,+CACS,yBAAyB,SAAS;;;;;;;GAQtD,uBAAuB,MAAM,WAAW,QAC1C,iBAAiB,QAAQ,WAAW"}
@@ -1,13 +1,7 @@
1
+ import { Direction, decodeCursor, encodeCursor } from "../pagination-BDLa7Yb_.mjs";
2
+
1
3
  //#region src/kysely/pagination.ts
2
4
  /**
3
- * Sort direction for cursor-based pagination.
4
- */
5
- let Direction = /* @__PURE__ */ function(Direction$1) {
6
- Direction$1["Asc"] = "asc";
7
- Direction$1["Desc"] = "desc";
8
- return Direction$1;
9
- }({});
10
- /**
11
5
  * Generic paginated search function that handles:
12
6
  * - Total count calculation
13
7
  * - Cursor-based pagination
@@ -16,13 +10,17 @@ let Direction = /* @__PURE__ */ function(Direction$1) {
16
10
  *
17
11
  * @example
18
12
  * ```typescript
13
+ * // With mapRow
19
14
  * const result = await paginatedSearch({
20
15
  * query: db.selectFrom('users').selectAll(),
21
- * cursor: previousCursor,
22
16
  * limit: 20,
23
17
  * mapRow: (row) => ({ id: row.id, name: row.name }),
24
- * cursorField: 'id',
25
- * cursorDirection: Direction.Asc,
18
+ * });
19
+ *
20
+ * // Without mapRow — items are the raw row type
21
+ * const result = await paginatedSearch({
22
+ * query: db.selectFrom('users').selectAll(),
23
+ * limit: 20,
26
24
  * });
27
25
  * ```
28
26
  */
@@ -39,7 +37,8 @@ async function paginatedSearch({ query, cursor, limit = 20, mapRow, cursorField
39
37
  const rows = hasMore ? data.slice(0, limit) : data;
40
38
  const lastRow = rows[rows.length - 1];
41
39
  const nextCursor = hasMore && lastRow ? String(lastRow[cursorField]) : void 0;
42
- const items = await Promise.all(rows.map(mapRow));
40
+ const mapper = mapRow ?? ((row) => row);
41
+ const items = await Promise.all(rows.map(mapper));
43
42
  return {
44
43
  items,
45
44
  pagination: {
@@ -49,30 +48,6 @@ async function paginatedSearch({ query, cursor, limit = 20, mapRow, cursorField
49
48
  }
50
49
  };
51
50
  }
52
- /**
53
- * Encode a cursor value for safe URL transmission.
54
- * Supports various types: string, number, Date, etc.
55
- */
56
- function encodeCursor(value) {
57
- const payload = {
58
- v: value instanceof Date ? value.toISOString() : value,
59
- t: value instanceof Date ? "date" : typeof value
60
- };
61
- return Buffer.from(JSON.stringify(payload)).toString("base64url");
62
- }
63
- /**
64
- * Decode a cursor string back to its original value.
65
- */
66
- function decodeCursor(cursor) {
67
- try {
68
- const json = Buffer.from(cursor, "base64url").toString("utf-8");
69
- const payload = JSON.parse(json);
70
- if (payload.t === "date") return new Date(payload.v);
71
- return payload.v;
72
- } catch {
73
- throw new Error("Invalid cursor format");
74
- }
75
- }
76
51
 
77
52
  //#endregion
78
53
  export { Direction, decodeCursor, encodeCursor, paginatedSearch };
@@ -1 +1 @@
1
- {"version":3,"file":"pagination.mjs","names":["value: unknown","cursor: string"],"sources":["../../src/kysely/pagination.ts"],"sourcesContent":["import type { SelectQueryBuilder } from 'kysely';\n\n/**\n * Sort direction for cursor-based pagination.\n */\nexport enum Direction {\n\tAsc = 'asc',\n\tDesc = 'desc',\n}\n\n/**\n * Result of a paginated query.\n */\nexport interface PaginationResult<TItem> {\n\titems: TItem[];\n\tpagination: {\n\t\ttotal: number;\n\t\thasMore: boolean;\n\t\tcursor?: string;\n\t};\n}\n\n/**\n * Options for paginated search.\n */\nexport interface PaginatedSearchOptions<\n\tTRow,\n\tTMapRow extends (row: TRow) => unknown,\n> {\n\t/** The base Kysely query to paginate */\n\tquery: SelectQueryBuilder<any, any, TRow>;\n\t/** Cursor value for pagination (value of cursorField from previous page) */\n\tcursor?: string;\n\t/** Maximum number of items per page (default: 20) */\n\tlimit?: number;\n\t/** Function to transform each row to the output format */\n\tmapRow: TMapRow;\n\t/** Field to use for cursor pagination (default: 'id') */\n\tcursorField?: string;\n\t/** Sort direction for cursor field (default: Direction.Asc) */\n\tcursorDirection?: Direction;\n}\n\n/**\n * Generic paginated search function that handles:\n * - Total count calculation\n * - Cursor-based pagination\n * - Fetching one extra row to determine hasMore\n * - Mapping rows to output format\n *\n * @example\n * ```typescript\n * const result = await paginatedSearch({\n * query: db.selectFrom('users').selectAll(),\n * cursor: previousCursor,\n * limit: 20,\n * mapRow: (row) => ({ id: row.id, name: row.name }),\n * cursorField: 'id',\n * cursorDirection: Direction.Asc,\n * });\n * ```\n */\nexport async function paginatedSearch<\n\tTRow extends Record<string, unknown>,\n\tTMapRow extends (row: TRow) => unknown,\n>({\n\tquery,\n\tcursor,\n\tlimit = 20,\n\tmapRow,\n\tcursorField = 'id',\n\tcursorDirection = Direction.Asc,\n}: PaginatedSearchOptions<TRow, TMapRow>): Promise<\n\tPaginationResult<Awaited<ReturnType<TMapRow>>>\n> {\n\t// Get total count (without cursor)\n\tconst countResult = await query\n\t\t.clearSelect()\n\t\t.clearOrderBy()\n\t\t.select((eb) => eb.fn.countAll().as('count'))\n\t\t.executeTakeFirstOrThrow();\n\n\tconst count = countResult.count;\n\n\t// Apply cursor if provided\n\tlet paginatedQuery = query;\n\tif (cursor) {\n\t\tconst operator = cursorDirection === Direction.Asc ? '>' : '<';\n\t\tpaginatedQuery = paginatedQuery.where(\n\t\t\tcursorField as any,\n\t\t\toperator,\n\t\t\tcursor,\n\t\t) as typeof query;\n\t}\n\n\t// Fetch one extra to determine if there are more results\n\tconst data = await paginatedQuery\n\t\t.orderBy(cursorField as any, cursorDirection)\n\t\t.limit(limit + 1)\n\t\t.execute();\n\n\tconst hasMore = data.length > limit;\n\tconst rows = hasMore ? data.slice(0, limit) : data;\n\tconst lastRow = rows[rows.length - 1];\n\tconst nextCursor =\n\t\thasMore && lastRow ? String(lastRow[cursorField]) : undefined;\n\n\tconst items = (await Promise.all(rows.map(mapRow))) as Awaited<\n\t\tReturnType<TMapRow>\n\t>[];\n\n\treturn {\n\t\titems,\n\t\tpagination: {\n\t\t\ttotal: Number(count),\n\t\t\thasMore,\n\t\t\tcursor: nextCursor,\n\t\t},\n\t};\n}\n\n/**\n * Encode a cursor value for safe URL transmission.\n * Supports various types: string, number, Date, etc.\n */\nexport function encodeCursor(value: unknown): string {\n\tconst payload = {\n\t\tv: value instanceof Date ? value.toISOString() : value,\n\t\tt: value instanceof Date ? 'date' : typeof value,\n\t};\n\treturn Buffer.from(JSON.stringify(payload)).toString('base64url');\n}\n\n/**\n * Decode a cursor string back to its original value.\n */\nexport function decodeCursor(cursor: string): unknown {\n\ttry {\n\t\tconst json = Buffer.from(cursor, 'base64url').toString('utf-8');\n\t\tconst payload = JSON.parse(json);\n\n\t\tif (payload.t === 'date') {\n\t\t\treturn new Date(payload.v);\n\t\t}\n\n\t\treturn payload.v;\n\t} catch {\n\t\tthrow new Error('Invalid cursor format');\n\t}\n}\n"],"mappings":";;;;AAKA,IAAY,kDAAL;AACN;AACA;;AACA;;;;;;;;;;;;;;;;;;;;AAsDD,eAAsB,gBAGpB,EACD,OACA,QACA,QAAQ,IACR,QACA,cAAc,MACd,kBAAkB,UAAU,KACW,EAEtC;CAED,MAAM,cAAc,MAAM,MACxB,aAAa,CACb,cAAc,CACd,OAAO,CAAC,OAAO,GAAG,GAAG,UAAU,CAAC,GAAG,QAAQ,CAAC,CAC5C,yBAAyB;CAE3B,MAAM,QAAQ,YAAY;CAG1B,IAAI,iBAAiB;AACrB,KAAI,QAAQ;EACX,MAAM,WAAW,oBAAoB,UAAU,MAAM,MAAM;AAC3D,mBAAiB,eAAe,MAC/B,aACA,UACA,OACA;CACD;CAGD,MAAM,OAAO,MAAM,eACjB,QAAQ,aAAoB,gBAAgB,CAC5C,MAAM,QAAQ,EAAE,CAChB,SAAS;CAEX,MAAM,UAAU,KAAK,SAAS;CAC9B,MAAM,OAAO,UAAU,KAAK,MAAM,GAAG,MAAM,GAAG;CAC9C,MAAM,UAAU,KAAK,KAAK,SAAS;CACnC,MAAM,aACL,WAAW,UAAU,OAAO,QAAQ,aAAa;CAElD,MAAM,QAAS,MAAM,QAAQ,IAAI,KAAK,IAAI,OAAO,CAAC;AAIlD,QAAO;EACN;EACA,YAAY;GACX,OAAO,OAAO,MAAM;GACpB;GACA,QAAQ;EACR;CACD;AACD;;;;;AAMD,SAAgB,aAAaA,OAAwB;CACpD,MAAM,UAAU;EACf,GAAG,iBAAiB,OAAO,MAAM,aAAa,GAAG;EACjD,GAAG,iBAAiB,OAAO,gBAAgB;CAC3C;AACD,QAAO,OAAO,KAAK,KAAK,UAAU,QAAQ,CAAC,CAAC,SAAS,YAAY;AACjE;;;;AAKD,SAAgB,aAAaC,QAAyB;AACrD,KAAI;EACH,MAAM,OAAO,OAAO,KAAK,QAAQ,YAAY,CAAC,SAAS,QAAQ;EAC/D,MAAM,UAAU,KAAK,MAAM,KAAK;AAEhC,MAAI,QAAQ,MAAM,OACjB,QAAO,IAAI,KAAK,QAAQ;AAGzB,SAAO,QAAQ;CACf,QAAO;AACP,QAAM,IAAI,MAAM;CAChB;AACD"}
1
+ {"version":3,"file":"pagination.mjs","names":["row: TRow"],"sources":["../../src/kysely/pagination.ts"],"sourcesContent":["import type { SelectQueryBuilder } from 'kysely';\nimport {\n\tDirection,\n\tdecodeCursor,\n\tencodeCursor,\n\ttype PaginationResult,\n} from '../pagination';\n\nexport { Direction, decodeCursor, encodeCursor, type PaginationResult };\n\n/**\n * Options for paginated search.\n */\nexport interface PaginatedSearchOptions<\n\tTRow,\n\tTMapRow extends (row: TRow) => unknown = (row: TRow) => TRow,\n> {\n\t/** The base Kysely query to paginate */\n\tquery: SelectQueryBuilder<any, any, TRow>;\n\t/** Cursor value for pagination (value of cursorField from previous page) */\n\tcursor?: string;\n\t/** Maximum number of items per page (default: 20) */\n\tlimit?: number;\n\t/** Function to transform each row to the output format (default: identity) */\n\tmapRow?: TMapRow;\n\t/** Field to use for cursor pagination (default: 'id') */\n\tcursorField?: string;\n\t/** Sort direction for cursor field (default: Direction.Asc) */\n\tcursorDirection?: Direction;\n}\n\n/**\n * Generic paginated search function that handles:\n * - Total count calculation\n * - Cursor-based pagination\n * - Fetching one extra row to determine hasMore\n * - Mapping rows to output format\n *\n * @example\n * ```typescript\n * // With mapRow\n * const result = await paginatedSearch({\n * query: db.selectFrom('users').selectAll(),\n * limit: 20,\n * mapRow: (row) => ({ id: row.id, name: row.name }),\n * });\n *\n * // Without mapRow — items are the raw row type\n * const result = await paginatedSearch({\n * query: db.selectFrom('users').selectAll(),\n * limit: 20,\n * });\n * ```\n */\nexport async function paginatedSearch<\n\tTRow extends Record<string, unknown>,\n\tTMapRow extends (row: TRow) => unknown = (row: TRow) => TRow,\n>({\n\tquery,\n\tcursor,\n\tlimit = 20,\n\tmapRow,\n\tcursorField = 'id',\n\tcursorDirection = Direction.Asc,\n}: PaginatedSearchOptions<TRow, TMapRow>): Promise<\n\tPaginationResult<Awaited<ReturnType<TMapRow>>>\n> {\n\t// Get total count (without cursor)\n\tconst countResult = await query\n\t\t.clearSelect()\n\t\t.clearOrderBy()\n\t\t.select((eb) => eb.fn.countAll().as('count'))\n\t\t.executeTakeFirstOrThrow();\n\n\tconst count = countResult.count;\n\n\t// Apply cursor if provided\n\tlet paginatedQuery = query;\n\tif (cursor) {\n\t\tconst operator = cursorDirection === Direction.Asc ? '>' : '<';\n\t\tpaginatedQuery = paginatedQuery.where(\n\t\t\tcursorField as any,\n\t\t\toperator,\n\t\t\tcursor,\n\t\t) as typeof query;\n\t}\n\n\t// Fetch one extra to determine if there are more results\n\tconst data = await paginatedQuery\n\t\t.orderBy(cursorField as any, cursorDirection)\n\t\t.limit(limit + 1)\n\t\t.execute();\n\n\tconst hasMore = data.length > limit;\n\tconst rows = hasMore ? data.slice(0, limit) : data;\n\tconst lastRow = rows[rows.length - 1];\n\tconst nextCursor =\n\t\thasMore && lastRow ? String(lastRow[cursorField]) : undefined;\n\n\tconst mapper = mapRow ?? ((row: TRow) => row);\n\tconst items = (await Promise.all(rows.map(mapper))) as Awaited<\n\t\tReturnType<TMapRow>\n\t>[];\n\n\treturn {\n\t\titems,\n\t\tpagination: {\n\t\t\ttotal: Number(count),\n\t\t\thasMore,\n\t\t\tcursor: nextCursor,\n\t\t},\n\t};\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAsDA,eAAsB,gBAGpB,EACD,OACA,QACA,QAAQ,IACR,QACA,cAAc,MACd,kBAAkB,UAAU,KACW,EAEtC;CAED,MAAM,cAAc,MAAM,MACxB,aAAa,CACb,cAAc,CACd,OAAO,CAAC,OAAO,GAAG,GAAG,UAAU,CAAC,GAAG,QAAQ,CAAC,CAC5C,yBAAyB;CAE3B,MAAM,QAAQ,YAAY;CAG1B,IAAI,iBAAiB;AACrB,KAAI,QAAQ;EACX,MAAM,WAAW,oBAAoB,UAAU,MAAM,MAAM;AAC3D,mBAAiB,eAAe,MAC/B,aACA,UACA,OACA;CACD;CAGD,MAAM,OAAO,MAAM,eACjB,QAAQ,aAAoB,gBAAgB,CAC5C,MAAM,QAAQ,EAAE,CAChB,SAAS;CAEX,MAAM,UAAU,KAAK,SAAS;CAC9B,MAAM,OAAO,UAAU,KAAK,MAAM,GAAG,MAAM,GAAG;CAC9C,MAAM,UAAU,KAAK,KAAK,SAAS;CACnC,MAAM,aACL,WAAW,UAAU,OAAO,QAAQ,aAAa;CAElD,MAAM,SAAS,WAAW,CAACA,QAAc;CACzC,MAAM,QAAS,MAAM,QAAQ,IAAI,KAAK,IAAI,OAAO,CAAC;AAIlD,QAAO;EACN;EACA,YAAY;GACX,OAAO,OAAO,MAAM;GACpB;GACA,QAAQ;EACR;CACD;AACD"}
@@ -10,4 +10,4 @@ type DatabaseConnection<T> = ControlledTransaction<T> | Kysely<T> | Transaction<
10
10
 
11
11
  //#endregion
12
12
  export { DatabaseConnection, TransactionSettings, withTransaction };
13
- //# sourceMappingURL=kysely-DUdsB0BP.d.mts.map
13
+ //# sourceMappingURL=kysely-Dm1w5gAY.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"kysely-DUdsB0BP.d.mts","names":[],"sources":["../src/kysely.ts"],"sourcesContent":[],"mappings":";;;UAOiB,mBAAA;mBACC;AADlB;AAIgB,iBAAA,eAAe,CAAA,EAAA,EAAA,CAAA,CAAA,CAAA,EAAA,EAC1B,kBAD0B,CACP,EADO,CAAA,EAAA,EAAA,EAAA,CAAA,GAAA,EAEpB,WAFoB,CAER,EAFQ,CAAA,EAAA,GAEA,OAFA,CAEQ,CAFR,CAAA,EAAA,QAAA,CAAA,EAGnB,mBAHmB,CAAA,EAI5B,OAJ4B,CAIpB,CAJoB,CAAA;AAAA,KAkBnB,kBAlBmB,CAAA,CAAA,CAAA,GAmB5B,qBAnB4B,CAmBN,CAnBM,CAAA,GAoB5B,MApB4B,CAoBrB,CApBqB,CAAA,GAqB5B,WArB4B,CAqBhB,CArBgB,CAAA"}
1
+ {"version":3,"file":"kysely-Dm1w5gAY.d.mts","names":[],"sources":["../src/kysely.ts"],"sourcesContent":[],"mappings":";;;UAOiB,mBAAA;mBACC;AADlB;AAIgB,iBAAA,eAAe,CAAA,EAAA,EAAA,CAAA,CAAA,CAAA,EAAA,EAC1B,kBAD0B,CACP,EADO,CAAA,EAAA,EAAA,EAAA,CAAA,GAAA,EAEpB,WAFoB,CAER,EAFQ,CAAA,EAAA,GAEA,OAFA,CAEQ,CAFR,CAAA,EAAA,QAAA,CAAA,EAGnB,mBAHmB,CAAA,EAI5B,OAJ4B,CAIpB,CAJoB,CAAA;AAAA,KAkBnB,kBAlBmB,CAAA,CAAA,CAAA,GAmB5B,qBAnB4B,CAmBN,CAnBM,CAAA,GAoB5B,MApB4B,CAoBrB,CApBqB,CAAA,GAqB5B,WArB4B,CAqBhB,CArBgB,CAAA"}
package/dist/kysely.d.mts CHANGED
@@ -1,2 +1,2 @@
1
- import { DatabaseConnection, TransactionSettings, withTransaction } from "./kysely-DUdsB0BP.mjs";
1
+ import { DatabaseConnection, TransactionSettings, withTransaction } from "./kysely-Dm1w5gAY.mjs";
2
2
  export { DatabaseConnection, TransactionSettings, withTransaction };
@@ -0,0 +1,50 @@
1
+ const require_pagination = require('../pagination-Bdoa4PVj.cjs');
2
+
3
+ //#region src/objection/pagination.ts
4
+ /**
5
+ * Cursor-based paginated search for Objection.js models.
6
+ *
7
+ * Accepts a pre-built QueryBuilder so callers can apply filters,
8
+ * eager loading, and scopes before pagination is layered on top.
9
+ *
10
+ * @example
11
+ * ```typescript
12
+ * const result = await paginatedSearch({
13
+ * query: User.query(trx).where('orgId', orgId).withGraphFetched('roles'),
14
+ * cursor: previousCursor,
15
+ * limit: 20,
16
+ * cursorField: 'createdAt',
17
+ * cursorDirection: Direction.Desc,
18
+ * });
19
+ * ```
20
+ */
21
+ async function paginatedSearch({ query, cursor, limit = 20, mapRow, cursorField = "id", cursorDirection = require_pagination.Direction.Asc }) {
22
+ const total = await query.resultSize();
23
+ let paginatedQuery = query.clone();
24
+ if (cursor) {
25
+ const operator = cursorDirection === require_pagination.Direction.Asc ? ">" : "<";
26
+ paginatedQuery = paginatedQuery.where(cursorField, operator, cursor);
27
+ }
28
+ const data = await paginatedQuery.orderBy(cursorField, cursorDirection).limit(limit + 1);
29
+ const hasMore = data.length > limit;
30
+ const rows = hasMore ? data.slice(0, limit) : data;
31
+ const lastRow = rows[rows.length - 1];
32
+ const nextCursor = hasMore && lastRow ? String(lastRow[cursorField]) : void 0;
33
+ const mapper = mapRow ?? ((row) => row);
34
+ const items = await Promise.all(rows.map(mapper));
35
+ return {
36
+ items,
37
+ pagination: {
38
+ total,
39
+ hasMore,
40
+ cursor: nextCursor
41
+ }
42
+ };
43
+ }
44
+
45
+ //#endregion
46
+ exports.Direction = require_pagination.Direction;
47
+ exports.decodeCursor = require_pagination.decodeCursor;
48
+ exports.encodeCursor = require_pagination.encodeCursor;
49
+ exports.paginatedSearch = paginatedSearch;
50
+ //# sourceMappingURL=pagination.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pagination.cjs","names":["Direction","row: TModel"],"sources":["../../src/objection/pagination.ts"],"sourcesContent":["import type { Model, QueryBuilder } from 'objection';\nimport {\n\tDirection,\n\tdecodeCursor,\n\tencodeCursor,\n\ttype PaginationResult,\n} from '../pagination';\n\nexport { Direction, decodeCursor, encodeCursor, type PaginationResult };\n\n/**\n * Options for paginated search with Objection.js models.\n */\nexport interface ObjectionPaginatedSearchOptions<\n\tTModel extends Model,\n\tTMapRow extends (row: TModel) => unknown = (row: TModel) => TModel,\n> {\n\t/** The Objection QueryBuilder to paginate (e.g. User.query(trx).where(...)) */\n\tquery: QueryBuilder<TModel>;\n\t/** Cursor value for pagination (value of cursorField from previous page) */\n\tcursor?: string;\n\t/** Maximum number of items per page (default: 20) */\n\tlimit?: number;\n\t/** Function to transform each row to the output format (default: identity) */\n\tmapRow?: TMapRow;\n\t/** Field to use for cursor pagination (default: 'id') */\n\tcursorField?: string;\n\t/** Sort direction for cursor field (default: Direction.Asc) */\n\tcursorDirection?: Direction;\n}\n\n/**\n * Cursor-based paginated search for Objection.js models.\n *\n * Accepts a pre-built QueryBuilder so callers can apply filters,\n * eager loading, and scopes before pagination is layered on top.\n *\n * @example\n * ```typescript\n * const result = await paginatedSearch({\n * query: User.query(trx).where('orgId', orgId).withGraphFetched('roles'),\n * cursor: previousCursor,\n * limit: 20,\n * cursorField: 'createdAt',\n * cursorDirection: Direction.Desc,\n * });\n * ```\n */\nexport async function paginatedSearch<\n\tTModel extends Model,\n\tTMapRow extends (row: TModel) => unknown = (row: TModel) => TModel,\n>({\n\tquery,\n\tcursor,\n\tlimit = 20,\n\tmapRow,\n\tcursorField = 'id',\n\tcursorDirection = Direction.Asc,\n}: ObjectionPaginatedSearchOptions<TModel, TMapRow>): Promise<\n\tPaginationResult<Awaited<ReturnType<TMapRow>>>\n> {\n\t// Get total count (without cursor filtering)\n\tconst total = await query.resultSize();\n\n\t// Apply cursor if provided\n\tlet paginatedQuery = query.clone();\n\tif (cursor) {\n\t\tconst operator = cursorDirection === Direction.Asc ? '>' : '<';\n\t\tpaginatedQuery = paginatedQuery.where(cursorField, operator, cursor);\n\t}\n\n\t// Fetch one extra to determine if there are more results\n\tconst data = await paginatedQuery\n\t\t.orderBy(cursorField, cursorDirection)\n\t\t.limit(limit + 1);\n\n\tconst hasMore = data.length > limit;\n\tconst rows = hasMore ? data.slice(0, limit) : data;\n\tconst lastRow = rows[rows.length - 1];\n\tconst nextCursor =\n\t\thasMore && lastRow\n\t\t\t? String((lastRow as Record<string, unknown>)[cursorField])\n\t\t\t: undefined;\n\n\tconst mapper = mapRow ?? ((row: TModel) => row);\n\tconst items = (await Promise.all(rows.map(mapper))) as Awaited<\n\t\tReturnType<TMapRow>\n\t>[];\n\n\treturn {\n\t\titems,\n\t\tpagination: {\n\t\t\ttotal,\n\t\t\thasMore,\n\t\t\tcursor: nextCursor,\n\t\t},\n\t};\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAgDA,eAAsB,gBAGpB,EACD,OACA,QACA,QAAQ,IACR,QACA,cAAc,MACd,kBAAkBA,6BAAU,KACsB,EAEjD;CAED,MAAM,QAAQ,MAAM,MAAM,YAAY;CAGtC,IAAI,iBAAiB,MAAM,OAAO;AAClC,KAAI,QAAQ;EACX,MAAM,WAAW,oBAAoBA,6BAAU,MAAM,MAAM;AAC3D,mBAAiB,eAAe,MAAM,aAAa,UAAU,OAAO;CACpE;CAGD,MAAM,OAAO,MAAM,eACjB,QAAQ,aAAa,gBAAgB,CACrC,MAAM,QAAQ,EAAE;CAElB,MAAM,UAAU,KAAK,SAAS;CAC9B,MAAM,OAAO,UAAU,KAAK,MAAM,GAAG,MAAM,GAAG;CAC9C,MAAM,UAAU,KAAK,KAAK,SAAS;CACnC,MAAM,aACL,WAAW,UACR,OAAQ,QAAoC,aAAa;CAG7D,MAAM,SAAS,WAAW,CAACC,QAAgB;CAC3C,MAAM,QAAS,MAAM,QAAQ,IAAI,KAAK,IAAI,OAAO,CAAC;AAIlD,QAAO;EACN;EACA,YAAY;GACX;GACA;GACA,QAAQ;EACR;CACD;AACD"}
@@ -0,0 +1,51 @@
1
+ import { Direction, PaginationResult, decodeCursor, encodeCursor } from "../pagination-BAFX7C1I.cjs";
2
+ import { Model, QueryBuilder } from "objection";
3
+
4
+ //#region src/objection/pagination.d.ts
5
+
6
+ /**
7
+ * Options for paginated search with Objection.js models.
8
+ */
9
+ interface ObjectionPaginatedSearchOptions<TModel extends Model, TMapRow extends (row: TModel) => unknown = (row: TModel) => TModel> {
10
+ /** The Objection QueryBuilder to paginate (e.g. User.query(trx).where(...)) */
11
+ query: QueryBuilder<TModel>;
12
+ /** Cursor value for pagination (value of cursorField from previous page) */
13
+ cursor?: string;
14
+ /** Maximum number of items per page (default: 20) */
15
+ limit?: number;
16
+ /** Function to transform each row to the output format (default: identity) */
17
+ mapRow?: TMapRow;
18
+ /** Field to use for cursor pagination (default: 'id') */
19
+ cursorField?: string;
20
+ /** Sort direction for cursor field (default: Direction.Asc) */
21
+ cursorDirection?: Direction;
22
+ }
23
+ /**
24
+ * Cursor-based paginated search for Objection.js models.
25
+ *
26
+ * Accepts a pre-built QueryBuilder so callers can apply filters,
27
+ * eager loading, and scopes before pagination is layered on top.
28
+ *
29
+ * @example
30
+ * ```typescript
31
+ * const result = await paginatedSearch({
32
+ * query: User.query(trx).where('orgId', orgId).withGraphFetched('roles'),
33
+ * cursor: previousCursor,
34
+ * limit: 20,
35
+ * cursorField: 'createdAt',
36
+ * cursorDirection: Direction.Desc,
37
+ * });
38
+ * ```
39
+ */
40
+ declare function paginatedSearch<TModel extends Model, TMapRow extends (row: TModel) => unknown = (row: TModel) => TModel>({
41
+ query,
42
+ cursor,
43
+ limit,
44
+ mapRow,
45
+ cursorField,
46
+ cursorDirection
47
+ }: ObjectionPaginatedSearchOptions<TModel, TMapRow>): Promise<PaginationResult<Awaited<ReturnType<TMapRow>>>>;
48
+ //# sourceMappingURL=pagination.d.ts.map
49
+ //#endregion
50
+ export { Direction, ObjectionPaginatedSearchOptions, PaginationResult, decodeCursor, encodeCursor, paginatedSearch };
51
+ //# sourceMappingURL=pagination.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pagination.d.cts","names":[],"sources":["../../src/objection/pagination.ts"],"sourcesContent":[],"mappings":";;;;;;AAaA;;AACgB,UADC,+BACD,CAAA,eAAA,KAAA,EAAA,gBAAA,CAAA,GAAA,EACO,MADP,EAAA,GAAA,OAAA,GAAA,CAAA,GAAA,EACkC,MADlC,EAAA,GAC6C,MAD7C,CAAA,CAAA;EAAK;EACQ,KAAqB,EAG1C,YAH0C,CAG7B,MAH6B,CAAA;EAAM;EAAW,MAG9C,CAAA,EAAA,MAAA;EAAM;EAAP,KAMV,CAAA,EAAA,MAAA;EAAO;EAIW,MAAA,CAAA,EAJlB,OAIkB;EAoBN;EAAe,WAAA,CAAA,EAAA,MAAA;EAAA;EAChB,eACE,CAAA,EAtBJ,SAsBI;;;;;;;;;;;;;;;;;AAQsC;;iBAVvC,+BACN,6BACO,2BAA2B,WAAW;;;;;;;GAQ1D,gCAAgC,QAAQ,WAAW,QACrD,iBAAiB,QAAQ,WAAW"}
@@ -0,0 +1,51 @@
1
+ import { Direction, PaginationResult, decodeCursor, encodeCursor } from "../pagination-BziGl-B8.mjs";
2
+ import { Model, QueryBuilder } from "objection";
3
+
4
+ //#region src/objection/pagination.d.ts
5
+
6
+ /**
7
+ * Options for paginated search with Objection.js models.
8
+ */
9
+ interface ObjectionPaginatedSearchOptions<TModel extends Model, TMapRow extends (row: TModel) => unknown = (row: TModel) => TModel> {
10
+ /** The Objection QueryBuilder to paginate (e.g. User.query(trx).where(...)) */
11
+ query: QueryBuilder<TModel>;
12
+ /** Cursor value for pagination (value of cursorField from previous page) */
13
+ cursor?: string;
14
+ /** Maximum number of items per page (default: 20) */
15
+ limit?: number;
16
+ /** Function to transform each row to the output format (default: identity) */
17
+ mapRow?: TMapRow;
18
+ /** Field to use for cursor pagination (default: 'id') */
19
+ cursorField?: string;
20
+ /** Sort direction for cursor field (default: Direction.Asc) */
21
+ cursorDirection?: Direction;
22
+ }
23
+ /**
24
+ * Cursor-based paginated search for Objection.js models.
25
+ *
26
+ * Accepts a pre-built QueryBuilder so callers can apply filters,
27
+ * eager loading, and scopes before pagination is layered on top.
28
+ *
29
+ * @example
30
+ * ```typescript
31
+ * const result = await paginatedSearch({
32
+ * query: User.query(trx).where('orgId', orgId).withGraphFetched('roles'),
33
+ * cursor: previousCursor,
34
+ * limit: 20,
35
+ * cursorField: 'createdAt',
36
+ * cursorDirection: Direction.Desc,
37
+ * });
38
+ * ```
39
+ */
40
+ declare function paginatedSearch<TModel extends Model, TMapRow extends (row: TModel) => unknown = (row: TModel) => TModel>({
41
+ query,
42
+ cursor,
43
+ limit,
44
+ mapRow,
45
+ cursorField,
46
+ cursorDirection
47
+ }: ObjectionPaginatedSearchOptions<TModel, TMapRow>): Promise<PaginationResult<Awaited<ReturnType<TMapRow>>>>;
48
+ //# sourceMappingURL=pagination.d.ts.map
49
+ //#endregion
50
+ export { Direction, ObjectionPaginatedSearchOptions, PaginationResult, decodeCursor, encodeCursor, paginatedSearch };
51
+ //# sourceMappingURL=pagination.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pagination.d.mts","names":[],"sources":["../../src/objection/pagination.ts"],"sourcesContent":[],"mappings":";;;;;;AAaA;;AACgB,UADC,+BACD,CAAA,eAAA,KAAA,EAAA,gBAAA,CAAA,GAAA,EACO,MADP,EAAA,GAAA,OAAA,GAAA,CAAA,GAAA,EACkC,MADlC,EAAA,GAC6C,MAD7C,CAAA,CAAA;EAAK;EACQ,KAAqB,EAG1C,YAH0C,CAG7B,MAH6B,CAAA;EAAM;EAAW,MAG9C,CAAA,EAAA,MAAA;EAAM;EAAP,KAMV,CAAA,EAAA,MAAA;EAAO;EAIW,MAAA,CAAA,EAJlB,OAIkB;EAoBN;EAAe,WAAA,CAAA,EAAA,MAAA;EAAA;EAChB,eACE,CAAA,EAtBJ,SAsBI;;;;;;;;;;;;;;;;;AAQsC;;iBAVvC,+BACN,6BACO,2BAA2B,WAAW;;;;;;;GAQ1D,gCAAgC,QAAQ,WAAW,QACrD,iBAAiB,QAAQ,WAAW"}