@b4moss/crudian 0.6.0 → 0.8.0

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.
package/README.md CHANGED
@@ -4,6 +4,8 @@ CRUD abstraction for DDD repositories.
4
4
 
5
5
  One npm package, adapter subpaths. Shared contracts live at the package root; backends are imported from subpaths. Callers inject their own DB/client — crudian never opens connections or reads env secrets for you.
6
6
 
7
+ **Versioning:** this npm package has its own SemVer (`package.json`). It is independent of the Go module (`packages/go/VERSION`). Shipping Go `0.7.0` does not require bumping this package.
8
+
7
9
  ## Install
8
10
 
9
11
  ```bash
@@ -1,9 +1,10 @@
1
1
  import type { Database } from "bun:sqlite";
2
+ import { type CreateCrudOptions } from "../index.js";
2
3
  import { type SyncSqliteCrud } from "../sqlite/sync-crud.js";
3
4
  export type BunSqliteCrud = SyncSqliteCrud<Database>;
4
5
  /**
5
6
  * Create a Crud bound to a Bun SQLite Database.
6
7
  * The same Database instance is reused for every operation.
7
8
  */
8
- export declare function createCrud(db: Database): BunSqliteCrud;
9
+ export declare function createCrud(db: Database, options?: CreateCrudOptions): BunSqliteCrud;
9
10
  //# sourceMappingURL=crud.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"crud.d.ts","sourceRoot":"","sources":["../../src/bun-sqlite/crud.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAoB,MAAM,YAAY,CAAA;AAE5D,OAAO,EAEL,KAAK,cAAc,EACpB,MAAM,wBAAwB,CAAA;AAM/B,MAAM,MAAM,aAAa,GAAG,cAAc,CAAC,QAAQ,CAAC,CAAA;AAEpD;;;GAGG;AACH,wBAAgB,UAAU,CAAC,EAAE,EAAE,QAAQ,GAAG,aAAa,CAyBtD"}
1
+ {"version":3,"file":"crud.d.ts","sourceRoot":"","sources":["../../src/bun-sqlite/crud.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAoB,MAAM,YAAY,CAAA;AAC5D,OAAO,EAAgB,KAAK,iBAAiB,EAAE,MAAM,aAAa,CAAA;AAClE,OAAO,EAEL,KAAK,cAAc,EACpB,MAAM,wBAAwB,CAAA;AAM/B,MAAM,MAAM,aAAa,GAAG,cAAc,CAAC,QAAQ,CAAC,CAAA;AAEpD;;;GAGG;AACH,wBAAgB,UAAU,CACxB,EAAE,EAAE,QAAQ,EACZ,OAAO,CAAC,EAAE,iBAAiB,GAC1B,aAAa,CA6Bf"}
@@ -7,7 +7,7 @@ function bindings(args) {
7
7
  * Create a Crud bound to a Bun SQLite Database.
8
8
  * The same Database instance is reused for every operation.
9
9
  */
10
- export function createCrud(db) {
10
+ export function createCrud(db, options) {
11
11
  if (db == null) {
12
12
  throw new CrudianError("db is required");
13
13
  }
@@ -28,5 +28,5 @@ export function createCrud(db) {
28
28
  transaction(fn) {
29
29
  return db.transaction(fn)();
30
30
  },
31
- });
31
+ }, options);
32
32
  }
@@ -1,5 +1,6 @@
1
1
  import type { BetterSQLite3Database } from "drizzle-orm/better-sqlite3";
2
2
  import type BetterSqlite3 from "better-sqlite3";
3
+ import { type CreateCrudOptions } from "../index.js";
3
4
  import { type SyncSqliteCrud } from "../sqlite/sync-crud.js";
4
5
  type DrizzleSqliteDb = BetterSQLite3Database<Record<string, unknown>> & {
5
6
  $client: BetterSqlite3.Database;
@@ -9,6 +10,6 @@ export type DrizzleCrud = SyncSqliteCrud<DrizzleSqliteDb>;
9
10
  * Create a Crud bound to a Drizzle better-sqlite3 database.
10
11
  * Raw SQL goes through the underlying better-sqlite3 client (`db.$client`).
11
12
  */
12
- export declare function createCrud(db: DrizzleSqliteDb): DrizzleCrud;
13
+ export declare function createCrud(db: DrizzleSqliteDb, options?: CreateCrudOptions): DrizzleCrud;
13
14
  export {};
14
15
  //# sourceMappingURL=crud.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"crud.d.ts","sourceRoot":"","sources":["../../src/drizzle/crud.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAA;AACvE,OAAO,KAAK,aAAa,MAAM,gBAAgB,CAAA;AAE/C,OAAO,EAEL,KAAK,cAAc,EACpB,MAAM,wBAAwB,CAAA;AAE/B,KAAK,eAAe,GAAG,qBAAqB,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG;IACtE,OAAO,EAAE,aAAa,CAAC,QAAQ,CAAA;CAChC,CAAA;AAED,MAAM,MAAM,WAAW,GAAG,cAAc,CAAC,eAAe,CAAC,CAAA;AAEzD;;;GAGG;AACH,wBAAgB,UAAU,CAAC,EAAE,EAAE,eAAe,GAAG,WAAW,CA2B3D"}
1
+ {"version":3,"file":"crud.d.ts","sourceRoot":"","sources":["../../src/drizzle/crud.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAA;AACvE,OAAO,KAAK,aAAa,MAAM,gBAAgB,CAAA;AAC/C,OAAO,EAAgB,KAAK,iBAAiB,EAAE,MAAM,aAAa,CAAA;AAClE,OAAO,EAEL,KAAK,cAAc,EACpB,MAAM,wBAAwB,CAAA;AAE/B,KAAK,eAAe,GAAG,qBAAqB,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG;IACtE,OAAO,EAAE,aAAa,CAAC,QAAQ,CAAA;CAChC,CAAA;AAED,MAAM,MAAM,WAAW,GAAG,cAAc,CAAC,eAAe,CAAC,CAAA;AAEzD;;;GAGG;AACH,wBAAgB,UAAU,CACxB,EAAE,EAAE,eAAe,EACnB,OAAO,CAAC,EAAE,iBAAiB,GAC1B,WAAW,CA+Bb"}
@@ -4,7 +4,7 @@ import { createSyncSqliteCrud, } from "../sqlite/sync-crud.js";
4
4
  * Create a Crud bound to a Drizzle better-sqlite3 database.
5
5
  * Raw SQL goes through the underlying better-sqlite3 client (`db.$client`).
6
6
  */
7
- export function createCrud(db) {
7
+ export function createCrud(db, options) {
8
8
  if (db == null) {
9
9
  throw new CrudianError("db is required");
10
10
  }
@@ -29,5 +29,5 @@ export function createCrud(db) {
29
29
  transaction(fn) {
30
30
  return client.transaction(fn)();
31
31
  },
32
- });
32
+ }, options);
33
33
  }
package/dist/index.d.ts CHANGED
@@ -8,5 +8,5 @@
8
8
  */
9
9
  export { CrudianError, assertString } from "./errors.js";
10
10
  export { WhereBuilder, where, isWhereBuilder, type Op, type CondNode, type GroupNode, type WhereNode, } from "./where.js";
11
- export type { Row, SearchResult, WhereInput, ReadQuery, SearchQuery, CountQuery, DeleteQuery, UpdateQuery, DuplicateQuery, } from "./types.js";
11
+ export type { Row, OffsetSearchResult, CursorSearchResult, SearchResult, WhereInput, ReadQuery, SearchQuery, CountQuery, DeleteQuery, UpdateQuery, DuplicateQuery, CreateCrudOptions, } from "./types.js";
12
12
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AACxD,OAAO,EACL,YAAY,EACZ,KAAK,EACL,cAAc,EACd,KAAK,EAAE,EACP,KAAK,QAAQ,EACb,KAAK,SAAS,EACd,KAAK,SAAS,GACf,MAAM,YAAY,CAAA;AACnB,YAAY,EACV,GAAG,EACH,YAAY,EACZ,UAAU,EACV,SAAS,EACT,WAAW,EACX,UAAU,EACV,WAAW,EACX,WAAW,EACX,cAAc,GACf,MAAM,YAAY,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AACxD,OAAO,EACL,YAAY,EACZ,KAAK,EACL,cAAc,EACd,KAAK,EAAE,EACP,KAAK,QAAQ,EACb,KAAK,SAAS,EACd,KAAK,SAAS,GACf,MAAM,YAAY,CAAA;AACnB,YAAY,EACV,GAAG,EACH,kBAAkB,EAClB,kBAAkB,EAClB,YAAY,EACZ,UAAU,EACV,SAAS,EACT,WAAW,EACX,UAAU,EACV,WAAW,EACX,WAAW,EACX,cAAc,EACd,iBAAiB,GAClB,MAAM,YAAY,CAAA"}
@@ -1,3 +1,4 @@
1
+ import { type CreateCrudOptions } from "../index.js";
1
2
  import { type AsyncSqliteCrud } from "../sqlite/async-crud.js";
2
3
  import type { Row } from "../types.js";
3
4
  /** Result shape used by the libSQL executor bridge. */
@@ -27,5 +28,5 @@ export type LibsqlCrud = AsyncSqliteCrud<LibsqlLikeClient>;
27
28
  * Methods are async. The injected client is exposed as `crud.db`.
28
29
  * Auth / URL are configured on the caller-created client (e.g. from env).
29
30
  */
30
- export declare function createCrud(client: LibsqlLikeClient): LibsqlCrud;
31
+ export declare function createCrud(client: LibsqlLikeClient, options?: CreateCrudOptions): LibsqlCrud;
31
32
  //# sourceMappingURL=crud.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"crud.d.ts","sourceRoot":"","sources":["../../src/libsql/crud.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,KAAK,eAAe,EACrB,MAAM,yBAAyB,CAAA;AAChC,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,aAAa,CAAA;AAEtC,uDAAuD;AACvD,MAAM,MAAM,eAAe,GAAG;IAC5B,IAAI,EAAE,KAAK,CAAC,GAAG,GAAG,OAAO,CAAC,CAAA;IAC1B,YAAY,EAAE,MAAM,CAAA;CACrB,CAAA;AAED,gEAAgE;AAChE,MAAM,MAAM,cAAc,GAAG;IAC3B,OAAO,CACL,IAAI,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,OAAO,EAAE,CAAA;KAAE,GAAG,MAAM,GAC/C,OAAO,CAAC,eAAe,CAAC,CAAA;CAC5B,CAAA;AAED,oEAAoE;AACpE,MAAM,MAAM,gBAAgB,GAAG,cAAc,GAAG;IAC9C,WAAW,CACT,IAAI,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,UAAU,GACnC,OAAO,CAAC,qBAAqB,CAAC,CAAA;CAClC,CAAA;AAED,MAAM,MAAM,qBAAqB,GAAG,cAAc,GAAG;IACnD,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;IACvB,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;IACzB,KAAK,IAAI,IAAI,CAAA;CACd,CAAA;AAED,MAAM,MAAM,UAAU,GAAG,eAAe,CAAC,gBAAgB,CAAC,CAAA;AAa1D;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,gBAAgB,GAAG,UAAU,CA6C/D"}
1
+ {"version":3,"file":"crud.d.ts","sourceRoot":"","sources":["../../src/libsql/crud.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,iBAAiB,EAAE,MAAM,aAAa,CAAA;AAClE,OAAO,EAEL,KAAK,eAAe,EACrB,MAAM,yBAAyB,CAAA;AAChC,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,aAAa,CAAA;AAEtC,uDAAuD;AACvD,MAAM,MAAM,eAAe,GAAG;IAC5B,IAAI,EAAE,KAAK,CAAC,GAAG,GAAG,OAAO,CAAC,CAAA;IAC1B,YAAY,EAAE,MAAM,CAAA;CACrB,CAAA;AAED,gEAAgE;AAChE,MAAM,MAAM,cAAc,GAAG;IAC3B,OAAO,CACL,IAAI,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,OAAO,EAAE,CAAA;KAAE,GAAG,MAAM,GAC/C,OAAO,CAAC,eAAe,CAAC,CAAA;CAC5B,CAAA;AAED,oEAAoE;AACpE,MAAM,MAAM,gBAAgB,GAAG,cAAc,GAAG;IAC9C,WAAW,CACT,IAAI,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,UAAU,GACnC,OAAO,CAAC,qBAAqB,CAAC,CAAA;CAClC,CAAA;AAED,MAAM,MAAM,qBAAqB,GAAG,cAAc,GAAG;IACnD,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;IACvB,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;IACzB,KAAK,IAAI,IAAI,CAAA;CACd,CAAA;AAED,MAAM,MAAM,UAAU,GAAG,eAAe,CAAC,gBAAgB,CAAC,CAAA;AAa1D;;;;GAIG;AACH,wBAAgB,UAAU,CACxB,MAAM,EAAE,gBAAgB,EACxB,OAAO,CAAC,EAAE,iBAAiB,GAC1B,UAAU,CAiDZ"}
@@ -16,7 +16,7 @@ function normalizeRow(row) {
16
16
  * Methods are async. The injected client is exposed as `crud.db`.
17
17
  * Auth / URL are configured on the caller-created client (e.g. from env).
18
18
  */
19
- export function createCrud(client) {
19
+ export function createCrud(client, options) {
20
20
  if (client == null) {
21
21
  throw new CrudianError("db is required");
22
22
  }
@@ -58,5 +58,5 @@ export function createCrud(client) {
58
58
  tx.close();
59
59
  }
60
60
  },
61
- });
61
+ }, options);
62
62
  }
@@ -1,3 +1,4 @@
1
+ import { type CreateCrudOptions } from "../index.js";
1
2
  import { type AsyncSqliteCrud } from "../sqlite/async-crud.js";
2
3
  /** Minimal surface of PrismaClient used by the adapter (raw SQL + TX). */
3
4
  export type PrismaLikeClient = {
@@ -10,5 +11,5 @@ export type PrismaCrud = AsyncSqliteCrud<PrismaLikeClient>;
10
11
  * Create a Crud bound to a PrismaClient (SQLite).
11
12
  * Methods are async. The injected client is exposed as `crud.db`.
12
13
  */
13
- export declare function createCrud(client: PrismaLikeClient): PrismaCrud;
14
+ export declare function createCrud(client: PrismaLikeClient, options?: CreateCrudOptions): PrismaCrud;
14
15
  //# sourceMappingURL=crud.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"crud.d.ts","sourceRoot":"","sources":["../../src/prisma/crud.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,KAAK,eAAe,EACrB,MAAM,yBAAyB,CAAA;AAGhC,0EAA0E;AAC1E,MAAM,MAAM,gBAAgB,GAAG;IAC7B,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;IACvE,eAAe,CAAC,CAAC,GAAG,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,CAAC,CAAC,CAAA;IAC7E,YAAY,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,gBAAgB,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAA;CACtE,CAAA;AAED,MAAM,MAAM,UAAU,GAAG,eAAe,CAAC,gBAAgB,CAAC,CAAA;AAU1D;;;GAGG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,gBAAgB,GAAG,UAAU,CA0C/D"}
1
+ {"version":3,"file":"crud.d.ts","sourceRoot":"","sources":["../../src/prisma/crud.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,iBAAiB,EAAE,MAAM,aAAa,CAAA;AAClE,OAAO,EAEL,KAAK,eAAe,EACrB,MAAM,yBAAyB,CAAA;AAGhC,0EAA0E;AAC1E,MAAM,MAAM,gBAAgB,GAAG;IAC7B,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;IACvE,eAAe,CAAC,CAAC,GAAG,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,CAAC,CAAC,CAAA;IAC7E,YAAY,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,gBAAgB,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAA;CACtE,CAAA;AAED,MAAM,MAAM,UAAU,GAAG,eAAe,CAAC,gBAAgB,CAAC,CAAA;AAU1D;;;GAGG;AACH,wBAAgB,UAAU,CACxB,MAAM,EAAE,gBAAgB,EACxB,OAAO,CAAC,EAAE,iBAAiB,GAC1B,UAAU,CA8CZ"}
@@ -12,7 +12,7 @@ function normalizeRow(row) {
12
12
  * Create a Crud bound to a PrismaClient (SQLite).
13
13
  * Methods are async. The injected client is exposed as `crud.db`.
14
14
  */
15
- export function createCrud(client) {
15
+ export function createCrud(client, options) {
16
16
  if (client == null) {
17
17
  throw new CrudianError("db is required");
18
18
  }
@@ -50,7 +50,7 @@ export function createCrud(client) {
50
50
  }
51
51
  });
52
52
  },
53
- });
53
+ }, options);
54
54
  }
55
55
  function normalizeQueryResult(result) {
56
56
  if (result == null)
@@ -1,4 +1,4 @@
1
- import { type CountQuery, type DeleteQuery, type DuplicateQuery, type ReadQuery, type Row, type SearchQuery, type SearchResult, type UpdateQuery } from "../index.js";
1
+ import { type CountQuery, type CreateCrudOptions, type DeleteQuery, type DuplicateQuery, type ReadQuery, type Row, type SearchQuery, type SearchResult, type UpdateQuery } from "../index.js";
2
2
  export type AsyncSqliteExecutor = {
3
3
  run(sql: string, args?: unknown[]): Promise<{
4
4
  changes: number;
@@ -24,5 +24,5 @@ export type AsyncSqliteCrud<TDb> = {
24
24
  count(table: string, query?: CountQuery): Promise<number>;
25
25
  transaction<T>(fn: () => Promise<T>): Promise<T>;
26
26
  };
27
- export declare function createAsyncSqliteCrud<TDb>(db: TDb, ex: AsyncSqliteExecutor): AsyncSqliteCrud<TDb>;
27
+ export declare function createAsyncSqliteCrud<TDb>(db: TDb, ex: AsyncSqliteExecutor, options?: CreateCrudOptions): AsyncSqliteCrud<TDb>;
28
28
  //# sourceMappingURL=async-crud.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"async-crud.d.ts","sourceRoot":"","sources":["../../src/sqlite/async-crud.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"async-crud.d.ts","sourceRoot":"","sources":["../../src/sqlite/async-crud.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,5 @@
1
1
  import { CrudianError, assertString, } from "../index.js";
2
+ import { createAsyncPkGuard, resolvePk } from "./pk.js";
2
3
  import { compileWhere, quoteIdent, resolveWhere } from "./sql.js";
3
4
  function requireWhere(query, label) {
4
5
  if (query.where === undefined || query.where === null) {
@@ -16,11 +17,14 @@ function rowFromObject(value) {
16
17
  }
17
18
  return { ...value };
18
19
  }
19
- export function createAsyncSqliteCrud(db, ex) {
20
+ export function createAsyncSqliteCrud(db, ex, options) {
21
+ const pk = resolvePk(options);
22
+ const ensurePkColumn = createAsyncPkGuard(pk, ex.all);
20
23
  const crud = {
21
24
  db,
22
25
  async create(table, cols) {
23
26
  assertString(table, "table");
27
+ await ensurePkColumn(table);
24
28
  if (cols == null || typeof cols !== "object" || Array.isArray(cols)) {
25
29
  throw new CrudianError("cols must be an object");
26
30
  }
@@ -39,6 +43,7 @@ export function createAsyncSqliteCrud(db, ex) {
39
43
  },
40
44
  async read(table, query = {}) {
41
45
  assertString(table, "table");
46
+ await ensurePkColumn(table);
42
47
  const tbl = quoteIdent(table);
43
48
  const where = compileWhere(resolveWhere(query.where));
44
49
  const sql = `SELECT ${selectColumns(query.columns)} FROM ${tbl}` +
@@ -49,6 +54,7 @@ export function createAsyncSqliteCrud(db, ex) {
49
54
  },
50
55
  async update(table, cols, query) {
51
56
  assertString(table, "table");
57
+ await ensurePkColumn(table);
52
58
  requireWhere(query, "update");
53
59
  if (cols == null || typeof cols !== "object" || Array.isArray(cols)) {
54
60
  throw new CrudianError("cols must be an object");
@@ -72,6 +78,7 @@ export function createAsyncSqliteCrud(db, ex) {
72
78
  },
73
79
  async delete(table, query) {
74
80
  assertString(table, "table");
81
+ await ensurePkColumn(table);
75
82
  requireWhere(query, "delete");
76
83
  const tbl = quoteIdent(table);
77
84
  const where = compileWhere(resolveWhere(query.where));
@@ -83,10 +90,21 @@ export function createAsyncSqliteCrud(db, ex) {
83
90
  },
84
91
  async search(table, query = {}) {
85
92
  assertString(table, "table");
93
+ await ensurePkColumn(table);
86
94
  const limit = query.limit ?? 20;
87
95
  if (typeof limit !== "number" || !Number.isFinite(limit) || limit <= 0) {
88
96
  throw new CrudianError("limit must be a positive number");
89
97
  }
98
+ const paging = query.paging ?? "offset";
99
+ if (paging !== "offset" && paging !== "cursor") {
100
+ throw new CrudianError('paging must be "offset" or "cursor"');
101
+ }
102
+ if (paging === "offset" && query.cursor !== undefined) {
103
+ throw new CrudianError("offset paging does not accept cursor");
104
+ }
105
+ if (paging === "cursor" && query.offset !== undefined) {
106
+ throw new CrudianError("cursor paging does not accept offset");
107
+ }
90
108
  if (query.cursor != null &&
91
109
  typeof query.cursor !== "number" &&
92
110
  typeof query.cursor !== "string") {
@@ -94,27 +112,48 @@ export function createAsyncSqliteCrud(db, ex) {
94
112
  }
95
113
  const tbl = quoteIdent(table);
96
114
  const where = compileWhere(resolveWhere(query.where));
115
+ const total = await crud.count(table, { where: query.where });
116
+ if (paging === "offset") {
117
+ const offset = query.offset ?? 0;
118
+ if (typeof offset !== "number" || !Number.isFinite(offset) || offset < 0) {
119
+ throw new CrudianError("offset must be a non-negative number");
120
+ }
121
+ const args = [...where.args];
122
+ const whereSql = where.sql ? ` WHERE ${where.sql}` : "";
123
+ const sql = `SELECT ${selectColumns(query.columns)} FROM ${tbl}` +
124
+ whereSql +
125
+ ` ORDER BY ${quoteIdent(pk)} ASC LIMIT ? OFFSET ?`;
126
+ args.push(limit, offset);
127
+ const items = (await ex.all(sql, args)).map((r) => rowFromObject(r));
128
+ return {
129
+ items,
130
+ total,
131
+ offset,
132
+ limit,
133
+ hasMore: offset + items.length < total,
134
+ };
135
+ }
97
136
  const args = [...where.args];
98
137
  const parts = [];
99
138
  if (where.sql)
100
139
  parts.push(`(${where.sql})`);
101
140
  if (query.cursor != null) {
102
- parts.push(`${quoteIdent("id")} > ?`);
141
+ parts.push(`${quoteIdent(pk)} > ?`);
103
142
  args.push(query.cursor);
104
143
  }
105
144
  const whereSql = parts.length > 0 ? ` WHERE ${parts.join(" AND ")}` : "";
106
145
  const sql = `SELECT ${selectColumns(query.columns)} FROM ${tbl}` +
107
146
  whereSql +
108
- ` ORDER BY ${quoteIdent("id")} ASC LIMIT ?`;
147
+ ` ORDER BY ${quoteIdent(pk)} ASC LIMIT ?`;
109
148
  args.push(limit + 1);
110
149
  const rows = (await ex.all(sql, args)).map((r) => rowFromObject(r));
111
150
  const hasMore = rows.length > limit;
112
151
  const items = hasMore ? rows.slice(0, limit) : rows;
113
152
  const last = items[items.length - 1];
114
- const nextCursor = hasMore && last != null && (typeof last.id === "number" || typeof last.id === "string")
115
- ? last.id
153
+ const pkVal = last != null ? last[pk] : undefined;
154
+ const nextCursor = hasMore && last != null && (typeof pkVal === "number" || typeof pkVal === "string")
155
+ ? pkVal
116
156
  : null;
117
- const total = await crud.count(table, { where: query.where });
118
157
  return { items, nextCursor, hasMore, total };
119
158
  },
120
159
  async list(table, query) {
@@ -122,6 +161,7 @@ export function createAsyncSqliteCrud(db, ex) {
122
161
  },
123
162
  async count(table, query = {}) {
124
163
  assertString(table, "table");
164
+ await ensurePkColumn(table);
125
165
  const tbl = quoteIdent(table);
126
166
  const where = compileWhere(resolveWhere(query.where));
127
167
  const sql = `SELECT COUNT(*) AS ${quoteIdent("row_count")} FROM ${tbl}` +
@@ -131,6 +171,7 @@ export function createAsyncSqliteCrud(db, ex) {
131
171
  },
132
172
  async upsert(table, cols) {
133
173
  assertString(table, "table");
174
+ await ensurePkColumn(table);
134
175
  if (cols == null || typeof cols !== "object" || Array.isArray(cols)) {
135
176
  throw new CrudianError("cols must be an object");
136
177
  }
@@ -138,19 +179,20 @@ export function createAsyncSqliteCrud(db, ex) {
138
179
  if (keys.length === 0) {
139
180
  throw new CrudianError("cols must not be empty");
140
181
  }
141
- if (!Object.prototype.hasOwnProperty.call(cols, "id")) {
142
- throw new CrudianError("upsert requires cols.id");
182
+ if (!Object.prototype.hasOwnProperty.call(cols, pk)) {
183
+ throw new CrudianError(`upsert requires cols.${pk}`);
143
184
  }
144
- const id = cols.id;
185
+ const id = cols[pk];
145
186
  const existing = await crud.read(table, {
146
- where: { type: "cond", op: "eq", column: "id", value: id },
187
+ where: { type: "cond", op: "eq", column: pk, value: id },
147
188
  });
148
189
  if (existing != null) {
149
- const { id: _id, ...patch } = cols;
190
+ const patch = { ...cols };
191
+ delete patch[pk];
150
192
  if (Object.keys(patch).length === 0)
151
193
  return existing;
152
194
  const updated = await crud.update(table, patch, {
153
- where: { type: "cond", op: "eq", column: "id", value: id },
195
+ where: { type: "cond", op: "eq", column: pk, value: id },
154
196
  });
155
197
  if (updated == null) {
156
198
  throw new CrudianError("upsert update failed");
@@ -161,22 +203,25 @@ export function createAsyncSqliteCrud(db, ex) {
161
203
  },
162
204
  async duplicate(table, query) {
163
205
  assertString(table, "table");
206
+ await ensurePkColumn(table);
164
207
  requireWhere(query, "duplicate");
165
208
  const source = await crud.read(table, { where: query.where });
166
209
  if (source == null)
167
210
  return null;
168
- const { id: _id, ...rest } = source;
211
+ const rest = { ...source };
212
+ delete rest[pk];
169
213
  const overrides = query.overrides != null &&
170
214
  typeof query.overrides === "object" &&
171
215
  !Array.isArray(query.overrides)
172
216
  ? query.overrides
173
217
  : {};
174
218
  const cols = { ...rest, ...overrides };
175
- delete cols.id;
219
+ delete cols[pk];
176
220
  return crud.create(table, cols);
177
221
  },
178
222
  async bulkCreate(table, rows) {
179
223
  assertString(table, "table");
224
+ await ensurePkColumn(table);
180
225
  if (!Array.isArray(rows)) {
181
226
  throw new CrudianError("rows must be an array");
182
227
  }
@@ -194,6 +239,7 @@ export function createAsyncSqliteCrud(db, ex) {
194
239
  },
195
240
  async bulkUpdate(table, cols, query) {
196
241
  assertString(table, "table");
242
+ await ensurePkColumn(table);
197
243
  requireWhere(query, "bulkUpdate");
198
244
  if (cols == null || typeof cols !== "object" || Array.isArray(cols)) {
199
245
  throw new CrudianError("cols must be an object");
@@ -217,6 +263,7 @@ export function createAsyncSqliteCrud(db, ex) {
217
263
  },
218
264
  async bulkUpsert(table, rows) {
219
265
  assertString(table, "table");
266
+ await ensurePkColumn(table);
220
267
  if (!Array.isArray(rows)) {
221
268
  throw new CrudianError("rows must be an array");
222
269
  }
@@ -227,8 +274,8 @@ export function createAsyncSqliteCrud(db, ex) {
227
274
  if (row == null || typeof row !== "object" || Array.isArray(row)) {
228
275
  throw new CrudianError("each row must be an object");
229
276
  }
230
- if (!Object.prototype.hasOwnProperty.call(row, "id")) {
231
- throw new CrudianError("bulkUpsert requires each row to have id");
277
+ if (!Object.prototype.hasOwnProperty.call(row, pk)) {
278
+ throw new CrudianError(`bulkUpsert requires each row to have ${pk}`);
232
279
  }
233
280
  await crud.upsert(table, row);
234
281
  count += 1;
@@ -0,0 +1,22 @@
1
+ import { type CreateCrudOptions } from "../index.js";
2
+ /** Resolve PK column name from createCrud options. Default: `"id"`. */
3
+ export declare function resolvePk(options?: CreateCrudOptions): string;
4
+ export type PkColumnChecker = {
5
+ get(sql: string, args?: unknown[]): {
6
+ name?: unknown;
7
+ } | RowLike | undefined;
8
+ };
9
+ export type AsyncPkColumnChecker = {
10
+ get(sql: string, args?: unknown[]): Promise<{
11
+ name?: unknown;
12
+ } | RowLike | undefined>;
13
+ };
14
+ type RowLike = Record<string, unknown>;
15
+ /**
16
+ * Ensure `pk` exists on `table` via PRAGMA table_info. Caches per table.
17
+ * Throws CrudianError when the column is missing.
18
+ */
19
+ export declare function createPkGuard(pk: string, get: (sql: string, args?: unknown[]) => RowLike | undefined, all: (sql: string, args?: unknown[]) => RowLike[]): (table: string) => void;
20
+ export declare function createAsyncPkGuard(pk: string, all: (sql: string, args?: unknown[]) => Promise<RowLike[]>): (table: string) => Promise<void>;
21
+ export {};
22
+ //# sourceMappingURL=pk.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pk.d.ts","sourceRoot":"","sources":["../../src/sqlite/pk.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,iBAAiB,EAAE,MAAM,aAAa,CAAA;AAGlE,uEAAuE;AACvE,wBAAgB,SAAS,CAAC,OAAO,CAAC,EAAE,iBAAiB,GAAG,MAAM,CAW7D;AAED,MAAM,MAAM,eAAe,GAAG;IAC5B,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,EAAE,GAAG;QAAE,IAAI,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,GAAG,SAAS,CAAA;CAC7E,CAAA;AAED,MAAM,MAAM,oBAAoB,GAAG;IACjC,GAAG,CACD,GAAG,EAAE,MAAM,EACX,IAAI,CAAC,EAAE,OAAO,EAAE,GACf,OAAO,CAAC;QAAE,IAAI,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,GAAG,SAAS,CAAC,CAAA;CACrD,CAAA;AAED,KAAK,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;AAEtC;;;GAGG;AACH,wBAAgB,aAAa,CAC3B,EAAE,EAAE,MAAM,EACV,GAAG,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,EAAE,KAAK,OAAO,GAAG,SAAS,EAC3D,GAAG,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,EAAE,KAAK,OAAO,EAAE,IAGlB,OAAO,MAAM,KAAG,IAAI,CAapD;AAED,wBAAgB,kBAAkB,CAChC,EAAE,EAAE,MAAM,EACV,GAAG,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC,OAAO,EAAE,CAAC,IAGrB,OAAO,MAAM,KAAG,OAAO,CAAC,IAAI,CAAC,CAanE"}
@@ -0,0 +1,45 @@
1
+ import { CrudianError } from "../index.js";
2
+ import { quoteIdent } from "./sql.js";
3
+ /** Resolve PK column name from createCrud options. Default: `"id"`. */
4
+ export function resolvePk(options) {
5
+ if (options == null || options.pk === undefined) {
6
+ return "id";
7
+ }
8
+ if (typeof options.pk !== "string") {
9
+ throw new CrudianError("pk must be a string");
10
+ }
11
+ if (options.pk === "") {
12
+ throw new CrudianError("pk must not be empty");
13
+ }
14
+ return options.pk;
15
+ }
16
+ /**
17
+ * Ensure `pk` exists on `table` via PRAGMA table_info. Caches per table.
18
+ * Throws CrudianError when the column is missing.
19
+ */
20
+ export function createPkGuard(pk, get, all) {
21
+ const ok = new Set();
22
+ return function ensurePkColumn(table) {
23
+ if (ok.has(table))
24
+ return;
25
+ const rows = all(`PRAGMA table_info(${quoteIdent(table)})`);
26
+ const names = new Set(rows.map((r) => String(r.name ?? "")).filter((n) => n.length > 0));
27
+ if (!names.has(pk)) {
28
+ throw new CrudianError(`pk column "${pk}" does not exist on table "${table}"`);
29
+ }
30
+ ok.add(table);
31
+ };
32
+ }
33
+ export function createAsyncPkGuard(pk, all) {
34
+ const ok = new Set();
35
+ return async function ensurePkColumn(table) {
36
+ if (ok.has(table))
37
+ return;
38
+ const rows = await all(`PRAGMA table_info(${quoteIdent(table)})`);
39
+ const names = new Set(rows.map((r) => String(r.name ?? "")).filter((n) => n.length > 0));
40
+ if (!names.has(pk)) {
41
+ throw new CrudianError(`pk column "${pk}" does not exist on table "${table}"`);
42
+ }
43
+ ok.add(table);
44
+ };
45
+ }
@@ -1,4 +1,4 @@
1
- import { type CountQuery, type DeleteQuery, type DuplicateQuery, type ReadQuery, type Row, type SearchQuery, type SearchResult, type UpdateQuery } from "../index.js";
1
+ import { type CountQuery, type CreateCrudOptions, type DeleteQuery, type DuplicateQuery, type ReadQuery, type Row, type SearchQuery, type SearchResult, type UpdateQuery } from "../index.js";
2
2
  export type SyncSqliteExecutor = {
3
3
  run(sql: string, args?: unknown[]): {
4
4
  changes: number;
@@ -24,5 +24,5 @@ export type SyncSqliteCrud<TDb> = {
24
24
  count(table: string, query?: CountQuery): number;
25
25
  transaction<T>(fn: () => T): T;
26
26
  };
27
- export declare function createSyncSqliteCrud<TDb>(db: TDb, ex: SyncSqliteExecutor): SyncSqliteCrud<TDb>;
27
+ export declare function createSyncSqliteCrud<TDb>(db: TDb, ex: SyncSqliteExecutor, options?: CreateCrudOptions): SyncSqliteCrud<TDb>;
28
28
  //# sourceMappingURL=sync-crud.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"sync-crud.d.ts","sourceRoot":"","sources":["../../src/sqlite/sync-crud.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"sync-crud.d.ts","sourceRoot":"","sources":["../../src/sqlite/sync-crud.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,5 @@
1
1
  import { CrudianError, assertString, } from "../index.js";
2
+ import { createPkGuard, resolvePk } from "./pk.js";
2
3
  import { compileWhere, quoteIdent, resolveWhere } from "./sql.js";
3
4
  function requireWhere(query, label) {
4
5
  if (query.where === undefined || query.where === null) {
@@ -16,11 +17,14 @@ function rowFromObject(value) {
16
17
  }
17
18
  return { ...value };
18
19
  }
19
- export function createSyncSqliteCrud(db, ex) {
20
+ export function createSyncSqliteCrud(db, ex, options) {
21
+ const pk = resolvePk(options);
22
+ const ensurePkColumn = createPkGuard(pk, ex.get, ex.all);
20
23
  const crud = {
21
24
  db,
22
25
  create(table, cols) {
23
26
  assertString(table, "table");
27
+ ensurePkColumn(table);
24
28
  if (cols == null || typeof cols !== "object" || Array.isArray(cols)) {
25
29
  throw new CrudianError("cols must be an object");
26
30
  }
@@ -33,13 +37,15 @@ export function createSyncSqliteCrud(db, ex) {
33
37
  const placeholders = keys.map(() => "?").join(", ");
34
38
  const args = keys.map((k) => cols[k]);
35
39
  ex.run(`INSERT INTO ${tbl} (${colSql}) VALUES (${placeholders})`, args);
36
- const idRow = ex.get("SELECT last_insert_rowid() AS id");
37
- const id = Number(idRow?.id);
38
- const row = ex.get(`SELECT * FROM ${tbl} WHERE "id" = ?`, [id]);
40
+ const pkValue = Object.prototype.hasOwnProperty.call(cols, pk)
41
+ ? cols[pk]
42
+ : Number(ex.get("SELECT last_insert_rowid() AS id")?.id);
43
+ const row = ex.get(`SELECT * FROM ${tbl} WHERE ${quoteIdent(pk)} = ?`, [pkValue]);
39
44
  return rowFromObject(row);
40
45
  },
41
46
  read(table, query = {}) {
42
47
  assertString(table, "table");
48
+ ensurePkColumn(table);
43
49
  const tbl = quoteIdent(table);
44
50
  const where = compileWhere(resolveWhere(query.where));
45
51
  const sql = `SELECT ${selectColumns(query.columns)} FROM ${tbl}` +
@@ -50,6 +56,7 @@ export function createSyncSqliteCrud(db, ex) {
50
56
  },
51
57
  update(table, cols, query) {
52
58
  assertString(table, "table");
59
+ ensurePkColumn(table);
53
60
  requireWhere(query, "update");
54
61
  if (cols == null || typeof cols !== "object" || Array.isArray(cols)) {
55
62
  throw new CrudianError("cols must be an object");
@@ -73,6 +80,7 @@ export function createSyncSqliteCrud(db, ex) {
73
80
  },
74
81
  delete(table, query) {
75
82
  assertString(table, "table");
83
+ ensurePkColumn(table);
76
84
  requireWhere(query, "delete");
77
85
  const tbl = quoteIdent(table);
78
86
  const where = compileWhere(resolveWhere(query.where));
@@ -84,10 +92,21 @@ export function createSyncSqliteCrud(db, ex) {
84
92
  },
85
93
  search(table, query = {}) {
86
94
  assertString(table, "table");
95
+ ensurePkColumn(table);
87
96
  const limit = query.limit ?? 20;
88
97
  if (typeof limit !== "number" || !Number.isFinite(limit) || limit <= 0) {
89
98
  throw new CrudianError("limit must be a positive number");
90
99
  }
100
+ const paging = query.paging ?? "offset";
101
+ if (paging !== "offset" && paging !== "cursor") {
102
+ throw new CrudianError('paging must be "offset" or "cursor"');
103
+ }
104
+ if (paging === "offset" && query.cursor !== undefined) {
105
+ throw new CrudianError("offset paging does not accept cursor");
106
+ }
107
+ if (paging === "cursor" && query.offset !== undefined) {
108
+ throw new CrudianError("cursor paging does not accept offset");
109
+ }
91
110
  if (query.cursor != null &&
92
111
  typeof query.cursor !== "number" &&
93
112
  typeof query.cursor !== "string") {
@@ -95,27 +114,48 @@ export function createSyncSqliteCrud(db, ex) {
95
114
  }
96
115
  const tbl = quoteIdent(table);
97
116
  const where = compileWhere(resolveWhere(query.where));
117
+ const total = crud.count(table, { where: query.where });
118
+ if (paging === "offset") {
119
+ const offset = query.offset ?? 0;
120
+ if (typeof offset !== "number" || !Number.isFinite(offset) || offset < 0) {
121
+ throw new CrudianError("offset must be a non-negative number");
122
+ }
123
+ const args = [...where.args];
124
+ const whereSql = where.sql ? ` WHERE ${where.sql}` : "";
125
+ const sql = `SELECT ${selectColumns(query.columns)} FROM ${tbl}` +
126
+ whereSql +
127
+ ` ORDER BY ${quoteIdent(pk)} ASC LIMIT ? OFFSET ?`;
128
+ args.push(limit, offset);
129
+ const items = ex.all(sql, args).map((r) => rowFromObject(r));
130
+ return {
131
+ items,
132
+ total,
133
+ offset,
134
+ limit,
135
+ hasMore: offset + items.length < total,
136
+ };
137
+ }
98
138
  const args = [...where.args];
99
139
  const parts = [];
100
140
  if (where.sql)
101
141
  parts.push(`(${where.sql})`);
102
142
  if (query.cursor != null) {
103
- parts.push(`${quoteIdent("id")} > ?`);
143
+ parts.push(`${quoteIdent(pk)} > ?`);
104
144
  args.push(query.cursor);
105
145
  }
106
146
  const whereSql = parts.length > 0 ? ` WHERE ${parts.join(" AND ")}` : "";
107
147
  const sql = `SELECT ${selectColumns(query.columns)} FROM ${tbl}` +
108
148
  whereSql +
109
- ` ORDER BY ${quoteIdent("id")} ASC LIMIT ?`;
149
+ ` ORDER BY ${quoteIdent(pk)} ASC LIMIT ?`;
110
150
  args.push(limit + 1);
111
151
  const rows = ex.all(sql, args).map((r) => rowFromObject(r));
112
152
  const hasMore = rows.length > limit;
113
153
  const items = hasMore ? rows.slice(0, limit) : rows;
114
154
  const last = items[items.length - 1];
115
- const nextCursor = hasMore && last != null && (typeof last.id === "number" || typeof last.id === "string")
116
- ? last.id
155
+ const pkVal = last != null ? last[pk] : undefined;
156
+ const nextCursor = hasMore && last != null && (typeof pkVal === "number" || typeof pkVal === "string")
157
+ ? pkVal
117
158
  : null;
118
- const total = crud.count(table, { where: query.where });
119
159
  return { items, nextCursor, hasMore, total };
120
160
  },
121
161
  list(table, query) {
@@ -123,6 +163,7 @@ export function createSyncSqliteCrud(db, ex) {
123
163
  },
124
164
  count(table, query = {}) {
125
165
  assertString(table, "table");
166
+ ensurePkColumn(table);
126
167
  const tbl = quoteIdent(table);
127
168
  const where = compileWhere(resolveWhere(query.where));
128
169
  const sql = `SELECT COUNT(*) AS ${quoteIdent("row_count")} FROM ${tbl}` +
@@ -132,6 +173,7 @@ export function createSyncSqliteCrud(db, ex) {
132
173
  },
133
174
  upsert(table, cols) {
134
175
  assertString(table, "table");
176
+ ensurePkColumn(table);
135
177
  if (cols == null || typeof cols !== "object" || Array.isArray(cols)) {
136
178
  throw new CrudianError("cols must be an object");
137
179
  }
@@ -139,19 +181,20 @@ export function createSyncSqliteCrud(db, ex) {
139
181
  if (keys.length === 0) {
140
182
  throw new CrudianError("cols must not be empty");
141
183
  }
142
- if (!Object.prototype.hasOwnProperty.call(cols, "id")) {
143
- throw new CrudianError("upsert requires cols.id");
184
+ if (!Object.prototype.hasOwnProperty.call(cols, pk)) {
185
+ throw new CrudianError(`upsert requires cols.${pk}`);
144
186
  }
145
- const id = cols.id;
187
+ const id = cols[pk];
146
188
  const existing = crud.read(table, {
147
- where: { type: "cond", op: "eq", column: "id", value: id },
189
+ where: { type: "cond", op: "eq", column: pk, value: id },
148
190
  });
149
191
  if (existing != null) {
150
- const { id: _id, ...patch } = cols;
192
+ const patch = { ...cols };
193
+ delete patch[pk];
151
194
  if (Object.keys(patch).length === 0)
152
195
  return existing;
153
196
  const updated = crud.update(table, patch, {
154
- where: { type: "cond", op: "eq", column: "id", value: id },
197
+ where: { type: "cond", op: "eq", column: pk, value: id },
155
198
  });
156
199
  if (updated == null) {
157
200
  throw new CrudianError("upsert update failed");
@@ -162,22 +205,25 @@ export function createSyncSqliteCrud(db, ex) {
162
205
  },
163
206
  duplicate(table, query) {
164
207
  assertString(table, "table");
208
+ ensurePkColumn(table);
165
209
  requireWhere(query, "duplicate");
166
210
  const source = crud.read(table, { where: query.where });
167
211
  if (source == null)
168
212
  return null;
169
- const { id: _id, ...rest } = source;
213
+ const rest = { ...source };
214
+ delete rest[pk];
170
215
  const overrides = query.overrides != null &&
171
216
  typeof query.overrides === "object" &&
172
217
  !Array.isArray(query.overrides)
173
218
  ? query.overrides
174
219
  : {};
175
220
  const cols = { ...rest, ...overrides };
176
- delete cols.id;
221
+ delete cols[pk];
177
222
  return crud.create(table, cols);
178
223
  },
179
224
  bulkCreate(table, rows) {
180
225
  assertString(table, "table");
226
+ ensurePkColumn(table);
181
227
  if (!Array.isArray(rows)) {
182
228
  throw new CrudianError("rows must be an array");
183
229
  }
@@ -195,6 +241,7 @@ export function createSyncSqliteCrud(db, ex) {
195
241
  },
196
242
  bulkUpdate(table, cols, query) {
197
243
  assertString(table, "table");
244
+ ensurePkColumn(table);
198
245
  requireWhere(query, "bulkUpdate");
199
246
  if (cols == null || typeof cols !== "object" || Array.isArray(cols)) {
200
247
  throw new CrudianError("cols must be an object");
@@ -218,6 +265,7 @@ export function createSyncSqliteCrud(db, ex) {
218
265
  },
219
266
  bulkUpsert(table, rows) {
220
267
  assertString(table, "table");
268
+ ensurePkColumn(table);
221
269
  if (!Array.isArray(rows)) {
222
270
  throw new CrudianError("rows must be an array");
223
271
  }
@@ -228,8 +276,8 @@ export function createSyncSqliteCrud(db, ex) {
228
276
  if (row == null || typeof row !== "object" || Array.isArray(row)) {
229
277
  throw new CrudianError("each row must be an object");
230
278
  }
231
- if (!Object.prototype.hasOwnProperty.call(row, "id")) {
232
- throw new CrudianError("bulkUpsert requires each row to have id");
279
+ if (!Object.prototype.hasOwnProperty.call(row, pk)) {
280
+ throw new CrudianError(`bulkUpsert requires each row to have ${pk}`);
233
281
  }
234
282
  crud.upsert(table, row);
235
283
  count += 1;
package/dist/types.d.ts CHANGED
@@ -1,12 +1,20 @@
1
1
  import type { WhereBuilder, WhereNode } from "./where.js";
2
2
  export type Row = Record<string, unknown>;
3
- export type SearchResult<T = Row> = {
3
+ export type OffsetSearchResult<T = Row> = {
4
+ items: T[];
5
+ total: number;
6
+ offset: number;
7
+ limit: number;
8
+ hasMore: boolean;
9
+ };
10
+ export type CursorSearchResult<T = Row> = {
4
11
  items: T[];
5
12
  nextCursor: number | string | null;
6
13
  hasMore: boolean;
7
14
  /** Rows matching `where` (ignores limit/cursor). */
8
15
  total: number;
9
16
  };
17
+ export type SearchResult<T = Row> = OffsetSearchResult<T> | CursorSearchResult<T>;
10
18
  export type WhereInput = WhereBuilder | WhereNode;
11
19
  export type ReadQuery = {
12
20
  columns?: string[];
@@ -16,7 +24,11 @@ export type SearchQuery = {
16
24
  columns?: string[];
17
25
  where?: WhereInput;
18
26
  limit?: number;
19
- /** Raw `id` cursor (keyset). */
27
+ /** Pagination mode. Default: `"offset"`. */
28
+ paging?: "offset" | "cursor";
29
+ /** Offset for `paging: "offset"` (default `0`). */
30
+ offset?: number;
31
+ /** Raw PK cursor (keyset; default column `id`) for `paging: "cursor"`. */
20
32
  cursor?: number | string | null;
21
33
  };
22
34
  export type CountQuery = {
@@ -32,4 +44,9 @@ export type DuplicateQuery = {
32
44
  where: WhereInput;
33
45
  overrides?: Record<string, unknown>;
34
46
  };
47
+ /** Options for `createCrud(db, options?)`. */
48
+ export type CreateCrudOptions = {
49
+ /** Primary key column name. Default: `"id"`. */
50
+ pk?: string;
51
+ };
35
52
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AAEzD,MAAM,MAAM,GAAG,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;AAEzC,MAAM,MAAM,YAAY,CAAC,CAAC,GAAG,GAAG,IAAI;IAClC,KAAK,EAAE,CAAC,EAAE,CAAA;IACV,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAA;IAClC,OAAO,EAAE,OAAO,CAAA;IAChB,oDAAoD;IACpD,KAAK,EAAE,MAAM,CAAA;CACd,CAAA;AAED,MAAM,MAAM,UAAU,GAAG,YAAY,GAAG,SAAS,CAAA;AAEjD,MAAM,MAAM,SAAS,GAAG;IACtB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;IAClB,KAAK,CAAC,EAAE,UAAU,CAAA;CACnB,CAAA;AAED,MAAM,MAAM,WAAW,GAAG;IACxB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;IAClB,KAAK,CAAC,EAAE,UAAU,CAAA;IAClB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,gCAAgC;IAChC,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAA;CAChC,CAAA;AAED,MAAM,MAAM,UAAU,GAAG;IACvB,KAAK,CAAC,EAAE,UAAU,CAAA;CACnB,CAAA;AAED,MAAM,MAAM,WAAW,GAAG;IACxB,KAAK,EAAE,UAAU,CAAA;CAClB,CAAA;AAED,MAAM,MAAM,WAAW,GAAG;IACxB,KAAK,EAAE,UAAU,CAAA;CAClB,CAAA;AAED,MAAM,MAAM,cAAc,GAAG;IAC3B,KAAK,EAAE,UAAU,CAAA;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CACpC,CAAA"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AAEzD,MAAM,MAAM,GAAG,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;AAEzC,MAAM,MAAM,kBAAkB,CAAC,CAAC,GAAG,GAAG,IAAI;IACxC,KAAK,EAAE,CAAC,EAAE,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,OAAO,CAAA;CACjB,CAAA;AAED,MAAM,MAAM,kBAAkB,CAAC,CAAC,GAAG,GAAG,IAAI;IACxC,KAAK,EAAE,CAAC,EAAE,CAAA;IACV,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAA;IAClC,OAAO,EAAE,OAAO,CAAA;IAChB,oDAAoD;IACpD,KAAK,EAAE,MAAM,CAAA;CACd,CAAA;AAED,MAAM,MAAM,YAAY,CAAC,CAAC,GAAG,GAAG,IAAI,kBAAkB,CAAC,CAAC,CAAC,GAAG,kBAAkB,CAAC,CAAC,CAAC,CAAA;AAEjF,MAAM,MAAM,UAAU,GAAG,YAAY,GAAG,SAAS,CAAA;AAEjD,MAAM,MAAM,SAAS,GAAG;IACtB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;IAClB,KAAK,CAAC,EAAE,UAAU,CAAA;CACnB,CAAA;AAED,MAAM,MAAM,WAAW,GAAG;IACxB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;IAClB,KAAK,CAAC,EAAE,UAAU,CAAA;IAClB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,4CAA4C;IAC5C,MAAM,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAAA;IAC5B,mDAAmD;IACnD,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,0EAA0E;IAC1E,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAA;CAChC,CAAA;AAED,MAAM,MAAM,UAAU,GAAG;IACvB,KAAK,CAAC,EAAE,UAAU,CAAA;CACnB,CAAA;AAED,MAAM,MAAM,WAAW,GAAG;IACxB,KAAK,EAAE,UAAU,CAAA;CAClB,CAAA;AAED,MAAM,MAAM,WAAW,GAAG;IACxB,KAAK,EAAE,UAAU,CAAA;CAClB,CAAA;AAED,MAAM,MAAM,cAAc,GAAG;IAC3B,KAAK,EAAE,UAAU,CAAA;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CACpC,CAAA;AAED,8CAA8C;AAC9C,MAAM,MAAM,iBAAiB,GAAG;IAC9B,gDAAgD;IAChD,EAAE,CAAC,EAAE,MAAM,CAAA;CACZ,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@b4moss/crudian",
3
- "version": "0.6.0",
3
+ "version": "0.8.0",
4
4
  "description": "CRUD abstraction for DDD repositories",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -43,9 +43,9 @@
43
43
  "prisma:generate": "prisma generate --schema prisma/schema.prisma",
44
44
  "test": "bun run test:bun-sqlite && bun run test:drizzle && bun run test:prisma && bun run test:libsql",
45
45
  "test:bun-sqlite": "bun test src/bun-sqlite",
46
- "test:drizzle": "tsx --test src/drizzle/crud.test.ts",
47
- "test:prisma": "bun run prisma:generate && tsx --test src/prisma/crud.test.ts",
48
- "test:libsql": "tsx --test src/libsql/crud.test.ts"
46
+ "test:drizzle": "tsx --test src/drizzle/crud.test.ts src/drizzle/pk.test.ts",
47
+ "test:prisma": "bun run prisma:generate && tsx --test src/prisma/crud.test.ts src/prisma/pk.test.ts",
48
+ "test:libsql": "tsx --test src/libsql/crud.test.ts src/libsql/pk.test.ts"
49
49
  },
50
50
  "engines": {
51
51
  "node": ">=24",
@@ -77,7 +77,7 @@
77
77
  "@types/better-sqlite3": "^7.6.13",
78
78
  "better-sqlite3": "^13",
79
79
  "bun-types": "^1.2.0",
80
- "drizzle-orm": "^0.44.4",
80
+ "drizzle-orm": "^0.45.2",
81
81
  "prisma": "^6.14.0",
82
82
  "tsx": "^4.23.12",
83
83
  "typescript": "^5.8.0"