@zudojs/database 1.3.2 → 1.5.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.
Files changed (98) hide show
  1. package/README.md +83 -0
  2. package/dist/cache/cache.memory.d.ts +0 -1
  3. package/dist/cache/cache.memory.js +0 -1
  4. package/dist/cache/index.d.ts +0 -1
  5. package/dist/cache/index.js +0 -1
  6. package/dist/database/database.core.d.ts +20 -7
  7. package/dist/database/database.core.js +8 -6
  8. package/dist/database/index.d.ts +0 -1
  9. package/dist/database/index.js +0 -1
  10. package/dist/databaseClient/databaseClient.core.d.ts +30 -15
  11. package/dist/databaseClient/databaseClient.core.js +19 -3
  12. package/dist/databaseClient/databaseClient.errors.d.ts +19 -2
  13. package/dist/databaseClient/databaseClient.errors.js +8 -1
  14. package/dist/databaseClient/databaseClient.logger.d.ts +0 -1
  15. package/dist/databaseClient/databaseClient.logger.js +0 -1
  16. package/dist/databaseClient/databaseClient.type.d.ts +52 -0
  17. package/dist/databaseClient/databaseClient.type.js +11 -0
  18. package/dist/databaseClient/index.d.ts +2 -3
  19. package/dist/databaseClient/index.js +1 -2
  20. package/dist/databaseConnection/databaseConnection.manager.d.ts +0 -1
  21. package/dist/databaseConnection/databaseConnection.manager.js +0 -1
  22. package/dist/databaseConnection/index.d.ts +0 -1
  23. package/dist/databaseConnection/index.js +0 -1
  24. package/dist/databaseType/databaseType.type.d.ts +6 -5
  25. package/dist/databaseType/databaseType.type.js +0 -1
  26. package/dist/databaseType/index.d.ts +0 -1
  27. package/dist/databaseType/index.js +0 -1
  28. package/dist/health/health.check.d.ts +0 -1
  29. package/dist/health/health.check.js +0 -1
  30. package/dist/health/index.d.ts +0 -1
  31. package/dist/health/index.js +0 -1
  32. package/dist/index.d.ts +3 -4
  33. package/dist/index.js +2 -3
  34. package/dist/locks/index.d.ts +0 -1
  35. package/dist/locks/index.js +0 -1
  36. package/dist/locks/locks.core.d.ts +8 -7
  37. package/dist/locks/locks.core.js +2 -1
  38. package/dist/migration/index.d.ts +0 -1
  39. package/dist/migration/index.js +0 -1
  40. package/dist/migration/migration.dialect.d.ts +0 -1
  41. package/dist/migration/migration.dialect.js +0 -1
  42. package/dist/migration/migration.helpers.d.ts +4 -4
  43. package/dist/migration/migration.helpers.js +4 -1
  44. package/dist/migration/migration.runner.d.ts +16 -5
  45. package/dist/migration/migration.runner.js +69 -17
  46. package/dist/migration/migration.types.d.ts +20 -6
  47. package/dist/migration/migration.types.js +0 -1
  48. package/dist/pagination/index.d.ts +1 -1
  49. package/dist/pagination/index.js +1 -1
  50. package/dist/pagination/pagination.core.d.ts +0 -1
  51. package/dist/pagination/pagination.core.js +0 -1
  52. package/dist/pagination/pagination.cursorError.d.ts +0 -1
  53. package/dist/pagination/pagination.cursorError.js +0 -1
  54. package/dist/pagination/pagination.keyset.d.ts +12 -1
  55. package/dist/pagination/pagination.keyset.js +15 -3
  56. package/dist/pagination/pagination.keysetDirection.d.ts +0 -1
  57. package/dist/pagination/pagination.keysetDirection.js +0 -1
  58. package/dist/pagination/pagination.keysetValue.d.ts +37 -0
  59. package/dist/pagination/pagination.keysetValue.js +55 -0
  60. package/dist/queryBuilder/index.d.ts +0 -1
  61. package/dist/queryBuilder/index.js +0 -1
  62. package/dist/queryBuilder/queryBuilder.core.d.ts +0 -1
  63. package/dist/queryBuilder/queryBuilder.core.js +0 -1
  64. package/dist/queryBuilder/queryBuilder.factory.d.ts +0 -1
  65. package/dist/queryBuilder/queryBuilder.factory.js +0 -1
  66. package/dist/queryBuilder/queryBuilder.filter.d.ts +0 -1
  67. package/dist/queryBuilder/queryBuilder.filter.js +0 -1
  68. package/dist/queryBuilder/queryBuilder.prisma.d.ts +0 -1
  69. package/dist/queryBuilder/queryBuilder.prisma.js +0 -1
  70. package/dist/queryBuilder/queryBuilder.type.d.ts +0 -1
  71. package/dist/queryBuilder/queryBuilder.type.js +0 -1
  72. package/dist/relations/index.d.ts +0 -1
  73. package/dist/relations/index.js +0 -1
  74. package/dist/relations/relations.definition.d.ts +0 -1
  75. package/dist/relations/relations.definition.js +0 -1
  76. package/dist/repository/index.d.ts +1 -2
  77. package/dist/repository/index.js +0 -1
  78. package/dist/repository/repository.base.d.ts +27 -1
  79. package/dist/repository/repository.base.js +13 -2
  80. package/dist/repository/repository.delegate.d.ts +0 -1
  81. package/dist/repository/repository.delegate.js +0 -1
  82. package/dist/repository/repository.errors.d.ts +3 -1
  83. package/dist/repository/repository.errors.js +17 -2
  84. package/dist/seed/index.d.ts +0 -1
  85. package/dist/seed/index.js +0 -1
  86. package/dist/seed/seed.runner.d.ts +14 -12
  87. package/dist/seed/seed.runner.js +0 -1
  88. package/dist/transaction/index.d.ts +0 -1
  89. package/dist/transaction/index.js +0 -1
  90. package/dist/transaction/transaction.backoff.d.ts +0 -1
  91. package/dist/transaction/transaction.backoff.js +0 -1
  92. package/dist/transaction/transaction.core.d.ts +27 -11
  93. package/dist/transaction/transaction.core.js +11 -2
  94. package/dist/unitOfWork/index.d.ts +0 -1
  95. package/dist/unitOfWork/index.js +0 -1
  96. package/dist/unitOfWork/unitOfWork.core.d.ts +12 -11
  97. package/dist/unitOfWork/unitOfWork.core.js +0 -1
  98. package/package.json +4 -4
package/README.md CHANGED
@@ -81,6 +81,49 @@ repository passes (`RepositoryDelegateOperations`).
81
81
  `adapter` (in which case it constructs the `PrismaClient` for you). It throws a
82
82
  `DatabaseError` if neither is supplied.
83
83
 
84
+ ### Typed transaction clients
85
+
86
+ The transaction client handed to `transaction()` callbacks is inferred from the
87
+ `prisma` instance you pass, so model delegates keep the types of your generated
88
+ client. This works with Prisma 7's `prisma-client` generator (client generated
89
+ into your application, e.g. `src/generated/prisma`) and with the legacy
90
+ `prisma-client-js` generator alike; the package's published types never import
91
+ `@prisma/client`, so they compile with `skipLibCheck: false`.
92
+
93
+ ```typescript
94
+ import { PrismaClient } from "./generated/prisma/client.js";
95
+
96
+ const client = createDatabaseClient({ prisma: new PrismaClient({ adapter }) });
97
+
98
+ await client.transaction(async (tx) => {
99
+ await tx.user.create({ data: { email: "bob@example.com", name: "Bob" } }); // fully typed
100
+ });
101
+ ```
102
+
103
+ `withTransaction`, `withTransactionRetry`, `TransactionManager`,
104
+ `DatabaseUnitOfWork`, the `Database` facade, the lock manager and the
105
+ migration and seed runners all take the type from the client they wrap.
106
+
107
+ When the concrete client type is unknown (`new DatabaseClient(options)`,
108
+ `createDatabaseClient({ adapter })`, `getDatabase()`), callbacks receive
109
+ `DatabaseTransactionContext`: the raw-query surface (`$queryRaw`,
110
+ `$executeRaw`, `$queryRawUnsafe`, `$executeRawUnsafe`) without model
111
+ delegates. Pass the client type to opt in, for example
112
+ `createDatabaseClient<PrismaClient>({ adapter })`. `TransactionClientOf<typeof
113
+ prisma>` names the inferred type if you need to annotate it.
114
+
115
+ The adapter-only form constructs `PrismaClient` from `@prisma/client` at
116
+ runtime, which only exists with the `prisma-client-js` generator. With the
117
+ `prisma-client` generator, construct the client yourself and pass it as
118
+ `prisma`.
119
+
120
+ **Writing your own transaction client** (a hand-written adapter, a test
121
+ double, a PGlite wrapper): since 1.4.0 `DatabaseTransactionContext` is a real
122
+ structural type rather than a type that resolved to `any`, so an object you
123
+ return as one must implement all four raw-query methods — `$queryRaw`,
124
+ `$executeRaw`, `$queryRawUnsafe` and `$executeRawUnsafe` — or TypeScript
125
+ reports TS2739. Code that only *receives* a transaction client is unaffected.
126
+
84
127
  ## Querying
85
128
 
86
129
  ```typescript
@@ -137,6 +180,21 @@ cursor or its contents. Building keyset pages by hand? Fetch with
137
180
  `keysetFetchSort(sort, getKeysetDirection(payload))` and pass that
138
181
  `direction` to `createKeysetPage`.
139
182
 
183
+ `paginateCursor` appends the id field to `sort` as a tiebreaker, so a cursor
184
+ positioned at a row you hold must include it: use
185
+ `users.createCursor(row, { sort })` (signed with `cursorSecret`), not
186
+ `createKeysetCursor(row, sort)` with the bare sort, which `paginateCursor`
187
+ rejects as missing the id field.
188
+
189
+ A `Date` sort value is encoded at millisecond precision. PostgreSQL
190
+ `timestamp`/`timestamptz` columns keep microseconds unless declared `(3)`,
191
+ and Prisma returns `Date`s, so the cursor compares such a value as its
192
+ millisecond bucket (`>= C AND < C + 1ms` for a tie) and lets the id
193
+ tiebreaker order rows created in the same millisecond. That is exact for
194
+ identical timestamps (rows inserted by one statement or transaction) and for
195
+ ids that increase with insertion order (serial, ULID, UUIDv7) — with random
196
+ ids, sort by a millisecond-precision column or add a monotonic tiebreaker.
197
+
140
198
  ## Migrations and seeds
141
199
 
142
200
  ```typescript
@@ -180,6 +238,31 @@ Each migration or seed runs in its own transaction by default
180
238
  (`perItemTransaction: true`); pass `transaction: { timeoutMs, maxWaitMs, isolationLevel }`
181
239
  to size it for long-running steps.
182
240
 
241
+ A migration that cannot run inside a transaction (`CREATE INDEX CONCURRENTLY`,
242
+ `ALTER TYPE ... ADD VALUE`) sets `transaction: false`. Its `up`/`down` then
243
+ receive the root client and run outside any transaction; the applied check
244
+ and the history record still happen in short transactions under the advisory
245
+ lock, which is released while the body runs, so write such a migration
246
+ idempotently (`IF NOT EXISTS`). It requires `perItemTransaction: true`; a
247
+ batch runner refuses it at construction.
248
+
249
+ ```typescript
250
+ {
251
+ version: 20260926120000,
252
+ name: "orders_customer_idx",
253
+ transaction: false,
254
+ up: (db) => db.$executeRawUnsafe(
255
+ 'CREATE INDEX CONCURRENTLY IF NOT EXISTS "orders_customer_idx" ON "orders" ("customerId")',
256
+ ),
257
+ down: (db) => db.$executeRawUnsafe('DROP INDEX CONCURRENTLY IF EXISTS "orders_customer_idx"'),
258
+ }
259
+ ```
260
+
261
+ `createTransactionContext` here builds the immutable status record that
262
+ `TransactionManager.run` reports (`transactionId`, `startedAt`, `status`);
263
+ it is unrelated to the `createTransactionContext` of `@zudojs/transactions`,
264
+ which creates that package's AsyncLocalStorage propagation store.
265
+
183
266
  ## Errors
184
267
 
185
268
  Errors your own transaction callback throws that are already `@zudojs/errors`
@@ -164,4 +164,3 @@ export declare function getOrSet<TValue>(cache: DatabaseCache<TValue>, key: stri
164
164
  * namespace only.
165
165
  */
166
166
  export declare function invalidateByPrefix(cache: DatabaseCache, prefix: string): number;
167
- //# sourceMappingURL=cache.memory.d.ts.map
@@ -374,4 +374,3 @@ function validateKey(key) {
374
374
  throw new TypeError("A non-empty cache key is required.");
375
375
  }
376
376
  }
377
- //# sourceMappingURL=cache.memory.js.map
@@ -4,4 +4,3 @@
4
4
  * In-memory LRU cache for database read results.
5
5
  */
6
6
  export { MemoryDatabaseCache, createDatabaseCache, createCacheKey, escapeCachePart, serializeCachePart, getOrSet, invalidateByPrefix, CACHE_KEY_SEPARATOR, type CacheEntry, type CacheOptions, type MemoryCacheOptions, type CacheStats, type DatabaseCache, } from "./cache.memory.js";
7
- //# sourceMappingURL=index.d.ts.map
@@ -4,4 +4,3 @@
4
4
  * In-memory LRU cache for database read results.
5
5
  */
6
6
  export { MemoryDatabaseCache, createDatabaseCache, createCacheKey, escapeCachePart, serializeCachePart, getOrSet, invalidateByPrefix, CACHE_KEY_SEPARATOR, } from "./cache.memory.js";
7
- //# sourceMappingURL=index.js.map
@@ -1,4 +1,4 @@
1
- import { DatabaseClient, type DatabaseClientOptions, type DatabaseTransactionContext, type PrismaClientLike } from "../databaseClient/databaseClient.core.js";
1
+ import { DatabaseClient, type DatabaseClientOptions, type DatabaseTransactionContext, type PrismaClientLike, type TransactionClientOf } from "../databaseClient/databaseClient.core.js";
2
2
  import type { DatabaseHealth, DatabaseStatus, TransactionCallback, TransactionOptions } from "../databaseType/databaseType.type.js";
3
3
  /**
4
4
  * Database facade used by the application layer.
@@ -6,14 +6,18 @@ import type { DatabaseHealth, DatabaseStatus, TransactionCallback, TransactionOp
6
6
  * This module provides a single database lifecycle entry point while
7
7
  * keeping the underlying Prisma client implementation inside the
8
8
  * database package.
9
+ *
10
+ * `TTransaction` is the transaction client handed to `transaction()`
11
+ * callbacks. {@link createDatabase} infers it from the wrapped client or
12
+ * from `options.prisma`.
9
13
  */
10
- export declare class Database {
14
+ export declare class Database<TTransaction extends DatabaseTransactionContext = DatabaseTransactionContext> {
11
15
  private readonly client;
12
16
  /**
13
17
  * @param options Client options, or an existing {@link DatabaseClient}
14
18
  * to wrap so a single client is shared by the facade and other managers.
15
19
  */
16
- constructor(options?: DatabaseClientOptions | DatabaseClient);
20
+ constructor(options?: DatabaseClientOptions | DatabaseClient<TTransaction>);
17
21
  /**
18
22
  * Initializes the database connection.
19
23
  */
@@ -41,14 +45,14 @@ export declare class Database {
41
45
  /**
42
46
  * Executes work inside a database transaction.
43
47
  */
44
- transaction<TResult>(callback: TransactionCallback<DatabaseTransactionContext, TResult>, options?: TransactionOptions): Promise<TResult>;
48
+ transaction<TResult>(callback: TransactionCallback<TTransaction, TResult>, options?: TransactionOptions): Promise<TResult>;
45
49
  /**
46
50
  * Returns the underlying database client.
47
51
  *
48
52
  * This should primarily be used by repository and infrastructure
49
53
  * implementations that require direct Prisma access.
50
54
  */
51
- getClient(): DatabaseClient;
55
+ getClient(): DatabaseClient<TTransaction>;
52
56
  /**
53
57
  * Returns the underlying Prisma client.
54
58
  */
@@ -59,7 +63,17 @@ export declare class Database {
59
63
  destroy(): Promise<void>;
60
64
  }
61
65
  /**
62
- * Creates a database facade.
66
+ * Creates a database facade over an existing client, keeping its
67
+ * transaction client type.
68
+ */
69
+ export declare function createDatabase<TTransaction extends DatabaseTransactionContext = DatabaseTransactionContext>(client: DatabaseClient<TTransaction>): Database<TTransaction>;
70
+ /**
71
+ * Creates a database facade from client options. The transaction client
72
+ * type is inferred from `options.prisma`.
73
+ */
74
+ export declare function createDatabase<TClient extends PrismaClientLike = PrismaClientLike>(options?: DatabaseClientOptions<TClient>): Database<TransactionClientOf<TClient>>;
75
+ /**
76
+ * Creates a database facade from client options or an existing client.
63
77
  */
64
78
  export declare function createDatabase(options?: DatabaseClientOptions | DatabaseClient): Database;
65
79
  /**
@@ -88,4 +102,3 @@ export declare function disconnectDatabase(): Promise<void>;
88
102
  * runtime environments.
89
103
  */
90
104
  export declare function resetDatabase(): Promise<void>;
91
- //# sourceMappingURL=database.core.d.ts.map
@@ -1,10 +1,14 @@
1
- import { DatabaseClient, createDatabaseClient, } from "../databaseClient/databaseClient.core.js";
1
+ import { DatabaseClient, } from "../databaseClient/databaseClient.core.js";
2
2
  /**
3
3
  * Database facade used by the application layer.
4
4
  *
5
5
  * This module provides a single database lifecycle entry point while
6
6
  * keeping the underlying Prisma client implementation inside the
7
7
  * database package.
8
+ *
9
+ * `TTransaction` is the transaction client handed to `transaction()`
10
+ * callbacks. {@link createDatabase} infers it from the wrapped client or
11
+ * from `options.prisma`.
8
12
  */
9
13
  export class Database {
10
14
  client;
@@ -14,7 +18,9 @@ export class Database {
14
18
  */
15
19
  constructor(options = {}) {
16
20
  this.client =
17
- options instanceof DatabaseClient ? options : createDatabaseClient(options);
21
+ options instanceof DatabaseClient
22
+ ? options
23
+ : new DatabaseClient(options);
18
24
  }
19
25
  /**
20
26
  * Initializes the database connection.
@@ -80,9 +86,6 @@ export class Database {
80
86
  await this.client.destroy();
81
87
  }
82
88
  }
83
- /**
84
- * Creates a database facade.
85
- */
86
89
  export function createDatabase(options = {}) {
87
90
  return new Database(options);
88
91
  }
@@ -147,4 +150,3 @@ export async function resetDatabase() {
147
150
  defaultDatabase = undefined;
148
151
  await database.destroy();
149
152
  }
150
- //# sourceMappingURL=database.core.js.map
@@ -4,4 +4,3 @@
4
4
  * High-level database lifecycle entry point.
5
5
  */
6
6
  export { Database, createDatabase, getDatabase, connectDatabase, disconnectDatabase, resetDatabase, } from "./database.core.js";
7
- //# sourceMappingURL=index.d.ts.map
@@ -4,4 +4,3 @@
4
4
  * High-level database lifecycle entry point.
5
5
  */
6
6
  export { Database, createDatabase, getDatabase, connectDatabase, disconnectDatabase, resetDatabase, } from "./database.core.js";
7
- //# sourceMappingURL=index.js.map
@@ -11,14 +11,10 @@
11
11
  * Only PostgreSQL is exercised by the runners, locks and health helpers in
12
12
  * this package.
13
13
  */
14
- import type { Prisma } from "@prisma/client";
15
14
  import { DatabaseError } from "@zudojs/errors";
16
15
  import type { DatabaseClient as DatabaseClientContract, DatabaseConnectionOptions, DatabaseHealth, DatabaseLogger, DatabaseOperationOptions, DatabaseStatus, TransactionCallback, TransactionIsolationLevel, TransactionOptions } from "../databaseType/databaseType.type.js";
17
- /**
18
- * Transaction client handed to callbacks. This is Prisma's interactive
19
- * transaction client (model delegates plus raw query helpers).
20
- */
21
- export type DatabaseTransactionContext = Prisma.TransactionClient;
16
+ import type { DatabaseTransactionContext, PrismaSqlLike, TransactionClientOf } from "./databaseClient.type.js";
17
+ export type { DatabaseTransactionContext, PrismaSqlLike, TransactionClientOf, } from "./databaseClient.type.js";
22
18
  /**
23
19
  * Isolation levels accepted by Prisma's interactive transactions. The
24
20
  * values are identical to the string names, so no namespace lookup is
@@ -79,12 +75,15 @@ export interface PrismaDriverAdapterLike {
79
75
  * Prisma 7 requires either a driver adapter or an already constructed
80
76
  * client; connection URLs, pool sizes and SSL flags are configured on the
81
77
  * adapter and are therefore not accepted here.
78
+ *
79
+ * `TClient` is the type of `prisma`; {@link createDatabaseClient} infers
80
+ * it to type the transaction client handed to callbacks.
82
81
  */
83
- export interface DatabaseClientOptions extends Pick<DatabaseConnectionOptions, "connectionTimeoutMs" | "logging"> {
82
+ export interface DatabaseClientOptions<TClient extends PrismaClientLike = PrismaClientLike> extends Pick<DatabaseConnectionOptions, "connectionTimeoutMs" | "logging"> {
84
83
  /**
85
84
  * Pre-built Prisma client. Takes precedence over `adapter`.
86
85
  */
87
- readonly prisma?: PrismaClientLike;
86
+ readonly prisma?: TClient;
88
87
  /**
89
88
  * Prisma driver adapter used to construct a client when `prisma` is
90
89
  * not supplied.
@@ -102,8 +101,15 @@ export type RawQueryOptions = DatabaseOperationOptions;
102
101
  * `connect()` de-duplicates concurrent calls through a shared in-flight
103
102
  * promise, and `disconnect()` waits for an in-flight connect before
104
103
  * tearing the client down.
104
+ *
105
+ * `TTransaction` is the client handed to `transaction()` callbacks.
106
+ * {@link createDatabaseClient} infers it from the Prisma client passed as
107
+ * `prisma`, so `tx.user.create(...)` is typed by the generated client. The
108
+ * constructor cannot infer it; `new DatabaseClient(options)` uses the
109
+ * structural {@link DatabaseTransactionContext} unless a type argument is
110
+ * given.
105
111
  */
106
- export declare class DatabaseClient implements DatabaseClientContract<DatabaseTransactionContext> {
112
+ export declare class DatabaseClient<TTransaction extends DatabaseTransactionContext = DatabaseTransactionContext> implements DatabaseClientContract<TTransaction> {
107
113
  private readonly prisma;
108
114
  private readonly logger;
109
115
  private readonly options;
@@ -151,7 +157,7 @@ export declare class DatabaseClient implements DatabaseClientContract<DatabaseTr
151
157
  * being logged as a database failure. Driver and database failures, and
152
158
  * any other thrown value, are normalised to a `DatabaseError` and logged.
153
159
  */
154
- transaction<TResult>(callback: TransactionCallback<DatabaseTransactionContext, TResult>, options?: TransactionOptions): Promise<TResult>;
160
+ transaction<TResult>(callback: TransactionCallback<TTransaction, TResult>, options?: TransactionOptions): Promise<TResult>;
155
161
  /**
156
162
  * Executes a raw statement with positional parameters and returns the
157
163
  * affected row count.
@@ -166,11 +172,11 @@ export declare class DatabaseClient implements DatabaseClientContract<DatabaseTr
166
172
  *
167
173
  * Only available when the underlying client supports `$executeRaw`.
168
174
  */
169
- executeRaw(query: Prisma.Sql, options?: RawQueryOptions): Promise<number>;
175
+ executeRaw(query: PrismaSqlLike, options?: RawQueryOptions): Promise<number>;
170
176
  /**
171
177
  * Executes a `Prisma.sql` tagged query.
172
178
  */
173
- queryRaw<TResult = unknown>(query: Prisma.Sql, options?: RawQueryOptions): Promise<TResult>;
179
+ queryRaw<TResult = unknown>(query: PrismaSqlLike, options?: RawQueryOptions): Promise<TResult>;
174
180
  ensureConnected(): Promise<void>;
175
181
  destroy(): Promise<void>;
176
182
  private registerQueryLogging;
@@ -209,6 +215,15 @@ export declare function createAbortError(signal?: AbortSignal): DatabaseAbortErr
209
215
  * running. The abort listener is removed once the operation settles.
210
216
  */
211
217
  export declare function raceAbort<T>(promise: Promise<T>, signal: AbortSignal | undefined): Promise<T>;
212
- /** Creates a database client. */
213
- export declare function createDatabaseClient(options?: DatabaseClientOptions): DatabaseClient;
214
- //# sourceMappingURL=databaseClient.core.d.ts.map
218
+ /**
219
+ * Creates a database client.
220
+ *
221
+ * The transaction client handed to `transaction()` callbacks is inferred
222
+ * from `options.prisma`: with a generated client it is that client's own
223
+ * interactive transaction client, so model delegates are fully typed.
224
+ * Without `prisma` (adapter only) it is the structural
225
+ * {@link DatabaseTransactionContext}; pass the generated client type as a
226
+ * type argument (`createDatabaseClient<PrismaClient>({ adapter })`) to type
227
+ * the delegates.
228
+ */
229
+ export declare function createDatabaseClient<TClient extends PrismaClientLike = PrismaClientLike>(options?: DatabaseClientOptions<TClient>): DatabaseClient<TransactionClientOf<TClient>>;
@@ -32,6 +32,13 @@ export const SUPPORTED_ISOLATION_LEVELS = Object.freeze([
32
32
  * `connect()` de-duplicates concurrent calls through a shared in-flight
33
33
  * promise, and `disconnect()` waits for an in-flight connect before
34
34
  * tearing the client down.
35
+ *
36
+ * `TTransaction` is the client handed to `transaction()` callbacks.
37
+ * {@link createDatabaseClient} infers it from the Prisma client passed as
38
+ * `prisma`, so `tx.user.create(...)` is typed by the generated client. The
39
+ * constructor cannot infer it; `new DatabaseClient(options)` uses the
40
+ * structural {@link DatabaseTransactionContext} unless a type argument is
41
+ * given.
35
42
  */
36
43
  export class DatabaseClient {
37
44
  prisma;
@@ -358,7 +365,7 @@ let cachedPrismaClientConstructor;
358
365
  function resolvePrismaClientConstructor() {
359
366
  if (cachedPrismaClientConstructor)
360
367
  return cachedPrismaClientConstructor;
361
- const guidance = "Install it and run `prisma generate`, or pass an already-constructed client as `prisma` in the DatabaseClient options.";
368
+ const guidance = "Install it and run `prisma generate`, or pass an already-constructed client as `prisma` in the DatabaseClient options (required with the `prisma-client` generator, whose client is generated into your application rather than into @prisma/client).";
362
369
  let module;
363
370
  try {
364
371
  module = requirePeer("@prisma/client");
@@ -489,8 +496,17 @@ export function raceAbort(promise, signal) {
489
496
  });
490
497
  });
491
498
  }
492
- /** Creates a database client. */
499
+ /**
500
+ * Creates a database client.
501
+ *
502
+ * The transaction client handed to `transaction()` callbacks is inferred
503
+ * from `options.prisma`: with a generated client it is that client's own
504
+ * interactive transaction client, so model delegates are fully typed.
505
+ * Without `prisma` (adapter only) it is the structural
506
+ * {@link DatabaseTransactionContext}; pass the generated client type as a
507
+ * type argument (`createDatabaseClient<PrismaClient>({ adapter })`) to type
508
+ * the delegates.
509
+ */
493
510
  export function createDatabaseClient(options = {}) {
494
511
  return new DatabaseClient(options);
495
512
  }
496
- //# sourceMappingURL=databaseClient.core.js.map
@@ -11,7 +11,7 @@
11
11
  * `clientVersion`), so the mapping works regardless of which copy of
12
12
  * `@prisma/client` produced the error.
13
13
  */
14
- import { DatabaseError, DatabaseOperation, type BaseError, type DatabaseErrorOptions } from "@zudojs/errors";
14
+ import { DatabaseError, DatabaseOperation, ErrorCode, type BaseError, type DatabaseErrorOptions } from "@zudojs/errors";
15
15
  import type { DatabaseErrorInfo } from "../databaseType/databaseType.type.js";
16
16
  /**
17
17
  * Structural `DatabaseError` guard.
@@ -67,10 +67,28 @@ export interface PrismaErrorLike {
67
67
  readonly message?: string;
68
68
  readonly retryable?: boolean;
69
69
  }
70
+ /**
71
+ * How a Prisma error code is normalised: its classification, HTTP status,
72
+ * framework error code, client-safe message and whether that message may
73
+ * be exposed.
74
+ */
75
+ export interface PrismaCodeMapping {
76
+ readonly kind: DatabaseErrorKind;
77
+ readonly statusCode: number;
78
+ readonly code: ErrorCode;
79
+ readonly message: string;
80
+ readonly expose: boolean;
81
+ }
70
82
  /**
71
83
  * Codes that indicate a transient transaction failure worth retrying.
72
84
  */
73
85
  export declare const RETRYABLE_DATABASE_CODES: ReadonlySet<string>;
86
+ /**
87
+ * The mapping {@link normalizeDatabaseError} applies to a Prisma error
88
+ * code, or `undefined` for a code it does not know. Shared with the
89
+ * repository mapper so both classify the same code the same way.
90
+ */
91
+ export declare function getPrismaCodeMapping(code: string): PrismaCodeMapping | undefined;
74
92
  /**
75
93
  * Detects a Prisma error structurally.
76
94
  */
@@ -120,4 +138,3 @@ export declare function normalizeDatabaseError(error: unknown, options?: Normali
120
138
  * normalised first, so Prisma codes appear as `code`.
121
139
  */
122
140
  export declare function toDatabaseErrorInfo(error: unknown, options?: NormalizeDatabaseErrorOptions): DatabaseErrorInfo;
123
- //# sourceMappingURL=databaseClient.errors.d.ts.map
@@ -199,6 +199,14 @@ export const RETRYABLE_DATABASE_CODES = new Set([
199
199
  "40001", // PostgreSQL: serialization_failure
200
200
  "40P01", // PostgreSQL: deadlock_detected
201
201
  ]);
202
+ /**
203
+ * The mapping {@link normalizeDatabaseError} applies to a Prisma error
204
+ * code, or `undefined` for a code it does not know. Shared with the
205
+ * repository mapper so both classify the same code the same way.
206
+ */
207
+ export function getPrismaCodeMapping(code) {
208
+ return PRISMA_CODE_MAP[code];
209
+ }
202
210
  /**
203
211
  * Detects a Prisma error structurally.
204
212
  */
@@ -435,4 +443,3 @@ export function toDatabaseErrorInfo(error, options = {}) {
435
443
  metadata,
436
444
  };
437
445
  }
438
- //# sourceMappingURL=databaseClient.errors.js.map
@@ -17,4 +17,3 @@ export declare const DEFAULT_DATABASE_LOGGER_NAME = "@zudojs/database";
17
17
  export declare function createDatabaseLoggerAdapter(logger: Logger): DatabaseLogger;
18
18
  /** Creates the fallback database logger, backed by `@zudojs/logger`. */
19
19
  export declare function createDefaultLogger(): DatabaseLogger;
20
- //# sourceMappingURL=databaseClient.logger.d.ts.map
@@ -52,4 +52,3 @@ export function createDefaultLogger() {
52
52
  level: LoggerLevel.DEBUG,
53
53
  }));
54
54
  }
55
- //# sourceMappingURL=databaseClient.logger.js.map
@@ -0,0 +1,52 @@
1
+ /**
2
+ * @zudojs/database — Database Client Types
3
+ *
4
+ * Transaction-client types owned by this package. They are structural on
5
+ * purpose: nothing here imports `@prisma/client`, so the published
6
+ * declarations resolve whether the consumer's generated client lives in
7
+ * `node_modules/.prisma/client` (`prisma-client-js`) or in an application
8
+ * directory such as `src/generated/prisma` (`prisma-client`, the Prisma 7
9
+ * default).
10
+ */
11
+ /**
12
+ * A `Prisma.sql` tagged query. Any `Prisma.Sql` instance satisfies it.
13
+ */
14
+ export interface PrismaSqlLike {
15
+ readonly strings: readonly string[];
16
+ readonly values: readonly unknown[];
17
+ readonly sql: string;
18
+ }
19
+ /**
20
+ * The raw-query surface every Prisma interactive transaction client
21
+ * exposes. This is the transaction type used when the concrete client type
22
+ * is not known: the default type argument of `DatabaseClient`,
23
+ * `TransactionManager`, `DatabaseUnitOfWork` and the other transaction
24
+ * helpers, and the type the migration, seed and lock helpers require.
25
+ *
26
+ * `createDatabaseClient({ prisma })` infers the real transaction client
27
+ * (model delegates included) from the client passed in; see
28
+ * {@link TransactionClientOf}.
29
+ *
30
+ * Declared as a type alias rather than an interface so it keeps an
31
+ * implicit index signature and stays assignable to
32
+ * `BaseRepository#withTransaction`'s `TransactionClientLike`.
33
+ */
34
+ export type DatabaseTransactionContext = {
35
+ $queryRawUnsafe<TResult = unknown>(query: string, ...values: unknown[]): Promise<TResult>;
36
+ $executeRawUnsafe(query: string, ...values: unknown[]): Promise<number>;
37
+ $queryRaw<TResult = unknown>(query: TemplateStringsArray | PrismaSqlLike, ...values: unknown[]): Promise<TResult>;
38
+ $executeRaw(query: TemplateStringsArray | PrismaSqlLike, ...values: unknown[]): Promise<number>;
39
+ };
40
+ /**
41
+ * The interactive-transaction callback parameter of a Prisma client: for a
42
+ * generated client this is its own `Omit<PrismaClient, ITXClientDenyList>`
43
+ * (or the extended equivalent after `$extends`), so model delegates such
44
+ * as `tx.user` keep their generated types.
45
+ *
46
+ * Falls back to {@link DatabaseTransactionContext} for clients whose
47
+ * transaction callback cannot be read (hand-written stubs,
48
+ * `PrismaClientLike` itself) or does not expose the raw-query surface.
49
+ */
50
+ export type TransactionClientOf<TClient> = TClient extends {
51
+ $transaction(callback: (transaction: infer TTransaction) => never, ...rest: never[]): unknown;
52
+ } ? [TTransaction] extends [never] ? DatabaseTransactionContext : [TTransaction] extends [DatabaseTransactionContext] ? TTransaction : DatabaseTransactionContext : DatabaseTransactionContext;
@@ -0,0 +1,11 @@
1
+ /**
2
+ * @zudojs/database — Database Client Types
3
+ *
4
+ * Transaction-client types owned by this package. They are structural on
5
+ * purpose: nothing here imports `@prisma/client`, so the published
6
+ * declarations resolve whether the consumer's generated client lives in
7
+ * `node_modules/.prisma/client` (`prisma-client-js`) or in an application
8
+ * directory such as `src/generated/prisma` (`prisma-client`, the Prisma 7
9
+ * default).
10
+ */
11
+ export {};
@@ -3,6 +3,5 @@
3
3
  *
4
4
  * Prisma-backed database client and connection infrastructure.
5
5
  */
6
- export { DatabaseClient, DatabaseAbortError, createDatabaseClient, buildPrismaTransactionOptions, createAbortError, raceAbort, throwIfAborted, SUPPORTED_ISOLATION_LEVELS, type DatabaseClientOptions, type DatabaseTransactionContext, type PrismaClientLike, type PrismaDriverAdapterLike, type PrismaQueryEvent, type PrismaTransactionOptions, type RawQueryOptions, } from "./databaseClient.core.js";
7
- export { normalizeDatabaseError, withDatabaseErrorMetadata, isPrismaError, isRetryableTransactionError, isConflictError, isNotFoundError, getDatabaseErrorCode, getDatabaseErrorKind, isDatabaseErrorLike, isNonDatabaseBaseError, toDatabaseErrorInfo, RETRYABLE_DATABASE_CODES, type DatabaseErrorKind, type NormalizeDatabaseErrorOptions, type PrismaErrorLike, } from "./databaseClient.errors.js";
8
- //# sourceMappingURL=index.d.ts.map
6
+ export { DatabaseClient, DatabaseAbortError, createDatabaseClient, buildPrismaTransactionOptions, createAbortError, raceAbort, throwIfAborted, SUPPORTED_ISOLATION_LEVELS, type DatabaseClientOptions, type DatabaseTransactionContext, type PrismaClientLike, type PrismaDriverAdapterLike, type PrismaQueryEvent, type PrismaTransactionOptions, type PrismaSqlLike, type RawQueryOptions, type TransactionClientOf, } from "./databaseClient.core.js";
7
+ export { normalizeDatabaseError, withDatabaseErrorMetadata, isPrismaError, isRetryableTransactionError, isConflictError, isNotFoundError, getDatabaseErrorCode, getDatabaseErrorKind, getPrismaCodeMapping, isDatabaseErrorLike, isNonDatabaseBaseError, toDatabaseErrorInfo, RETRYABLE_DATABASE_CODES, type DatabaseErrorKind, type NormalizeDatabaseErrorOptions, type PrismaCodeMapping, type PrismaErrorLike, } from "./databaseClient.errors.js";
@@ -4,5 +4,4 @@
4
4
  * Prisma-backed database client and connection infrastructure.
5
5
  */
6
6
  export { DatabaseClient, DatabaseAbortError, createDatabaseClient, buildPrismaTransactionOptions, createAbortError, raceAbort, throwIfAborted, SUPPORTED_ISOLATION_LEVELS, } from "./databaseClient.core.js";
7
- export { normalizeDatabaseError, withDatabaseErrorMetadata, isPrismaError, isRetryableTransactionError, isConflictError, isNotFoundError, getDatabaseErrorCode, getDatabaseErrorKind, isDatabaseErrorLike, isNonDatabaseBaseError, toDatabaseErrorInfo, RETRYABLE_DATABASE_CODES, } from "./databaseClient.errors.js";
8
- //# sourceMappingURL=index.js.map
7
+ export { normalizeDatabaseError, withDatabaseErrorMetadata, isPrismaError, isRetryableTransactionError, isConflictError, isNotFoundError, getDatabaseErrorCode, getDatabaseErrorKind, getPrismaCodeMapping, isDatabaseErrorLike, isNonDatabaseBaseError, toDatabaseErrorInfo, RETRYABLE_DATABASE_CODES, } from "./databaseClient.errors.js";
@@ -165,4 +165,3 @@ export declare class DatabaseConnectionManager {
165
165
  * Creates a database connection manager.
166
166
  */
167
167
  export declare function createConnectionManager(options?: DatabaseConnectionManagerOptions): DatabaseConnectionManager;
168
- //# sourceMappingURL=databaseConnection.manager.d.ts.map
@@ -312,4 +312,3 @@ function sleep(milliseconds, signal) {
312
312
  export function createConnectionManager(options = {}) {
313
313
  return new DatabaseConnectionManager(options);
314
314
  }
315
- //# sourceMappingURL=databaseConnection.manager.js.map
@@ -4,4 +4,3 @@
4
4
  * Connection lifecycle management with health checks.
5
5
  */
6
6
  export { DatabaseConnectionManager, createConnectionManager, type DatabaseConnectionEvent, type DatabaseConnectionListener, type DatabaseConnectionEventDetails, type DatabaseConnectionManagerOptions, type DatabaseReconnectOptions, } from "./databaseConnection.manager.js";
7
- //# sourceMappingURL=index.d.ts.map
@@ -4,4 +4,3 @@
4
4
  * Connection lifecycle management with health checks.
5
5
  */
6
6
  export { DatabaseConnectionManager, createConnectionManager, } from "./databaseConnection.manager.js";
7
- //# sourceMappingURL=index.js.map
@@ -174,15 +174,17 @@ export interface DatabaseEntity<TId = string> {
174
174
  readonly updatedAt: Date;
175
175
  }
176
176
  /**
177
- * Soft-deletable entity contract.
177
+ * Soft-deletable entity contract. `TId` is the primary key type (default
178
+ * `string`), as on {@link DatabaseEntity}.
178
179
  */
179
- export interface SoftDeletableEntity extends DatabaseEntity {
180
+ export interface SoftDeletableEntity<TId = string> extends DatabaseEntity<TId> {
180
181
  readonly deletedAt: Date | null;
181
182
  }
182
183
  /**
183
- * Auditable entity contract.
184
+ * Auditable entity contract. `TId` is the primary key type (default
185
+ * `string`), as on {@link DatabaseEntity}.
184
186
  */
185
- export interface AuditableEntity extends DatabaseEntity {
187
+ export interface AuditableEntity<TId = string> extends DatabaseEntity<TId> {
186
188
  readonly createdBy?: string;
187
189
  readonly updatedBy?: string;
188
190
  }
@@ -221,4 +223,3 @@ export interface DatabaseLogger {
221
223
  * Default no-op database logger.
222
224
  */
223
225
  export declare const noopDatabaseLogger: DatabaseLogger;
224
- //# sourceMappingURL=databaseType.type.d.ts.map
@@ -7,4 +7,3 @@ export const noopDatabaseLogger = Object.freeze({
7
7
  warn: () => undefined,
8
8
  error: () => undefined,
9
9
  });
10
- //# sourceMappingURL=databaseType.type.js.map
@@ -4,4 +4,3 @@
4
4
  * Core type definitions for the database package.
5
5
  */
6
6
  export * from "./databaseType.type.js";
7
- //# sourceMappingURL=index.d.ts.map
@@ -4,4 +4,3 @@
4
4
  * Core type definitions for the database package.
5
5
  */
6
6
  export * from "./databaseType.type.js";
7
- //# sourceMappingURL=index.js.map
@@ -71,4 +71,3 @@ export declare function assertDatabaseHealth(client: DatabaseClient, options?: D
71
71
  * Checks whether a database is reachable.
72
72
  */
73
73
  export declare function isDatabaseHealthy(client: DatabaseClient, options?: DatabaseHealthOptions): Promise<boolean>;
74
- //# sourceMappingURL=health.check.d.ts.map
@@ -187,4 +187,3 @@ function normalizeHealthError(error) {
187
187
  : {}),
188
188
  };
189
189
  }
190
- //# sourceMappingURL=health.check.js.map
@@ -4,4 +4,3 @@
4
4
  * Database health and readiness monitoring.
5
5
  */
6
6
  export { checkDatabaseHealth, checkDatabaseReadiness, assertDatabaseHealth, isDatabaseHealthy, getHealthCheckCause, DatabaseUnhealthyError, DEFAULT_HEALTH_TIMEOUT_MS, type DatabaseHealthStatus, type DatabaseHealth, type DatabaseHealthOptions, type DatabaseReadiness, } from "./health.check.js";
7
- //# sourceMappingURL=index.d.ts.map
@@ -4,4 +4,3 @@
4
4
  * Database health and readiness monitoring.
5
5
  */
6
6
  export { checkDatabaseHealth, checkDatabaseReadiness, assertDatabaseHealth, isDatabaseHealthy, getHealthCheckCause, DatabaseUnhealthyError, DEFAULT_HEALTH_TIMEOUT_MS, } from "./health.check.js";
7
- //# sourceMappingURL=index.js.map