@vertz/db 0.2.0 → 0.2.3
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 +412 -694
- package/dist/d1/index.d.ts +241 -0
- package/dist/d1/index.js +8 -0
- package/dist/diagnostic/index.js +1 -1
- package/dist/index.d.ts +932 -626
- package/dist/index.js +1759 -533
- package/dist/internals.d.ts +96 -31
- package/dist/internals.js +8 -7
- package/dist/plugin/index.d.ts +1 -1
- package/dist/plugin/index.js +7 -3
- package/dist/postgres/index.d.ts +77 -0
- package/dist/postgres/index.js +7 -0
- package/dist/shared/{chunk-3f2grpak.js → chunk-0e1vy9qd.js} +147 -52
- package/dist/shared/chunk-2gd1fqcw.js +7 -0
- package/dist/shared/{chunk-xp022dyp.js → chunk-agyds4jw.js} +25 -19
- package/dist/shared/chunk-dvwe5jsq.js +7 -0
- package/dist/shared/chunk-j4kwq1gh.js +5 -0
- package/dist/shared/{chunk-wj026daz.js → chunk-k04v1jjx.js} +2 -2
- package/dist/shared/chunk-kb4tnn2k.js +26 -0
- package/dist/shared/chunk-pnk6yzjv.js +48 -0
- package/dist/shared/chunk-rqe0prft.js +100 -0
- package/dist/shared/chunk-sfmyxz6r.js +306 -0
- package/dist/shared/chunk-ssga2xea.js +9 -0
- package/dist/shared/{chunk-hrfdj0rr.js → chunk-v2qm94qp.js} +12 -2
- package/dist/sql/index.d.ts +61 -61
- package/dist/sql/index.js +2 -2
- package/dist/sqlite/index.d.ts +221 -0
- package/dist/sqlite/index.js +845 -0
- package/package.json +32 -5
package/dist/index.d.ts
CHANGED
|
@@ -38,6 +38,28 @@ declare function formatDiagnostic(diag: DiagnosticResult): string;
|
|
|
38
38
|
* @returns Formatted diagnostic string, or a fallback message
|
|
39
39
|
*/
|
|
40
40
|
declare function explainError(message: string): string;
|
|
41
|
+
/**
|
|
42
|
+
* Database driver interface.
|
|
43
|
+
*
|
|
44
|
+
* Provides a unified interface for different database backends
|
|
45
|
+
* (PostgreSQL, SQLite/D1, etc.) with query and execute methods.
|
|
46
|
+
*/
|
|
47
|
+
interface DbDriver {
|
|
48
|
+
/**
|
|
49
|
+
* Execute a read query and return results.
|
|
50
|
+
*/
|
|
51
|
+
query<T = unknown>(sql: string, params?: unknown[]): Promise<T[]>;
|
|
52
|
+
/**
|
|
53
|
+
* Execute a write query and return affected row count.
|
|
54
|
+
*/
|
|
55
|
+
execute(sql: string, params?: unknown[]): Promise<{
|
|
56
|
+
rowsAffected: number;
|
|
57
|
+
}>;
|
|
58
|
+
/**
|
|
59
|
+
* Close the database connection.
|
|
60
|
+
*/
|
|
61
|
+
close(): Promise<void>;
|
|
62
|
+
}
|
|
41
63
|
interface JsonbValidator<T> {
|
|
42
64
|
parse(value: unknown): T;
|
|
43
65
|
}
|
|
@@ -47,8 +69,9 @@ interface ColumnMetadata {
|
|
|
47
69
|
readonly unique: boolean;
|
|
48
70
|
readonly nullable: boolean;
|
|
49
71
|
readonly hasDefault: boolean;
|
|
50
|
-
readonly
|
|
51
|
-
readonly
|
|
72
|
+
readonly _annotations: Record<string, true>;
|
|
73
|
+
readonly isReadOnly: boolean;
|
|
74
|
+
readonly isAutoUpdate: boolean;
|
|
52
75
|
readonly isTenant: boolean;
|
|
53
76
|
readonly references: {
|
|
54
77
|
readonly table: string;
|
|
@@ -63,6 +86,7 @@ interface ColumnMetadata {
|
|
|
63
86
|
readonly enumName?: string;
|
|
64
87
|
readonly enumValues?: readonly string[];
|
|
65
88
|
readonly validator?: JsonbValidator<unknown>;
|
|
89
|
+
readonly generate?: "cuid" | "uuid" | "nanoid";
|
|
66
90
|
}
|
|
67
91
|
/** Phantom symbol to carry the TypeScript type without a runtime value. */
|
|
68
92
|
declare const PhantomType: unique symbol;
|
|
@@ -73,9 +97,12 @@ interface ColumnBuilder<
|
|
|
73
97
|
/** Phantom field -- only exists at the type level for inference. Do not access at runtime. */
|
|
74
98
|
readonly [PhantomType]: TType;
|
|
75
99
|
readonly _meta: TMeta;
|
|
76
|
-
primary(
|
|
100
|
+
primary(options?: {
|
|
101
|
+
generate?: "cuid" | "uuid" | "nanoid";
|
|
102
|
+
}): ColumnBuilder<TType, Omit<TMeta, "primary" | "hasDefault" | "generate"> & {
|
|
77
103
|
readonly primary: true;
|
|
78
104
|
readonly hasDefault: true;
|
|
105
|
+
readonly generate?: "cuid" | "uuid" | "nanoid";
|
|
79
106
|
}>;
|
|
80
107
|
unique(): ColumnBuilder<TType, Omit<TMeta, "unique"> & {
|
|
81
108
|
readonly unique: true;
|
|
@@ -87,11 +114,15 @@ interface ColumnBuilder<
|
|
|
87
114
|
readonly hasDefault: true;
|
|
88
115
|
readonly defaultValue: TType | "now";
|
|
89
116
|
}>;
|
|
90
|
-
|
|
91
|
-
readonly
|
|
117
|
+
is<TFlag extends string>(flag: TFlag): ColumnBuilder<TType, Omit<TMeta, "_annotations"> & {
|
|
118
|
+
readonly _annotations: TMeta["_annotations"] & { readonly [K in TFlag] : true };
|
|
92
119
|
}>;
|
|
93
|
-
|
|
94
|
-
readonly
|
|
120
|
+
readOnly(): ColumnBuilder<TType, Omit<TMeta, "isReadOnly"> & {
|
|
121
|
+
readonly isReadOnly: true;
|
|
122
|
+
}>;
|
|
123
|
+
autoUpdate(): ColumnBuilder<TType, Omit<TMeta, "isAutoUpdate" | "isReadOnly"> & {
|
|
124
|
+
readonly isAutoUpdate: true;
|
|
125
|
+
readonly isReadOnly: true;
|
|
95
126
|
}>;
|
|
96
127
|
check(sql: string): ColumnBuilder<TType, Omit<TMeta, "check"> & {
|
|
97
128
|
readonly check: string;
|
|
@@ -110,8 +141,9 @@ type DefaultMeta<TSqlType extends string> = {
|
|
|
110
141
|
readonly unique: false;
|
|
111
142
|
readonly nullable: false;
|
|
112
143
|
readonly hasDefault: false;
|
|
113
|
-
readonly
|
|
114
|
-
readonly
|
|
144
|
+
readonly _annotations: {};
|
|
145
|
+
readonly isReadOnly: false;
|
|
146
|
+
readonly isAutoUpdate: false;
|
|
115
147
|
readonly isTenant: false;
|
|
116
148
|
readonly references: null;
|
|
117
149
|
readonly check: null;
|
|
@@ -149,8 +181,9 @@ type SerialMeta = {
|
|
|
149
181
|
readonly unique: false;
|
|
150
182
|
readonly nullable: false;
|
|
151
183
|
readonly hasDefault: true;
|
|
152
|
-
readonly
|
|
153
|
-
readonly
|
|
184
|
+
readonly _annotations: {};
|
|
185
|
+
readonly isReadOnly: false;
|
|
186
|
+
readonly isAutoUpdate: false;
|
|
154
187
|
readonly isTenant: false;
|
|
155
188
|
readonly references: null;
|
|
156
189
|
readonly check: null;
|
|
@@ -161,8 +194,9 @@ type TenantMeta = {
|
|
|
161
194
|
readonly unique: false;
|
|
162
195
|
readonly nullable: false;
|
|
163
196
|
readonly hasDefault: false;
|
|
164
|
-
readonly
|
|
165
|
-
readonly
|
|
197
|
+
readonly _annotations: {};
|
|
198
|
+
readonly isReadOnly: false;
|
|
199
|
+
readonly isAutoUpdate: false;
|
|
166
200
|
readonly isTenant: true;
|
|
167
201
|
readonly references: {
|
|
168
202
|
readonly table: string;
|
|
@@ -189,26 +223,35 @@ interface ManyRelationDef<TTarget extends TableDef<ColumnRecord> = TableDef<Colu
|
|
|
189
223
|
}
|
|
190
224
|
interface IndexDef {
|
|
191
225
|
readonly columns: readonly string[];
|
|
226
|
+
readonly name?: string;
|
|
227
|
+
readonly unique?: boolean;
|
|
192
228
|
}
|
|
193
229
|
/** A record of column builders -- the shape passed to d.table(). */
|
|
194
230
|
type ColumnRecord = Record<string, ColumnBuilder<unknown, ColumnMetadata>>;
|
|
195
231
|
/** Extract the TypeScript type from every column in a record. */
|
|
196
232
|
type InferColumns<T extends ColumnRecord> = { [K in keyof T] : InferColumnType<T[K]> };
|
|
197
|
-
/** Keys of columns where a given metadata
|
|
233
|
+
/** Keys of columns where a given metadata property is `true`. */
|
|
198
234
|
type ColumnKeysWhere<
|
|
199
235
|
T extends ColumnRecord,
|
|
200
236
|
Flag extends keyof ColumnMetadata
|
|
201
237
|
> = { [K in keyof T] : T[K] extends ColumnBuilder<unknown, infer M> ? M extends Record<Flag, true> ? K : never : never }[keyof T];
|
|
202
|
-
/** Keys of columns where a given metadata
|
|
238
|
+
/** Keys of columns where a given metadata property is NOT `true` (i.e., false). */
|
|
203
239
|
type ColumnKeysWhereNot<
|
|
204
240
|
T extends ColumnRecord,
|
|
205
241
|
Flag extends keyof ColumnMetadata
|
|
206
242
|
> = { [K in keyof T] : T[K] extends ColumnBuilder<unknown, infer M> ? M extends Record<Flag, true> ? never : K : never }[keyof T];
|
|
243
|
+
/** Keys of columns that do NOT have ANY of the specified annotations in `_annotations`. */
|
|
244
|
+
type ColumnKeysWithoutAnyAnnotation<
|
|
245
|
+
T extends ColumnRecord,
|
|
246
|
+
Annotations extends string
|
|
247
|
+
> = { [K in keyof T] : T[K] extends ColumnBuilder<unknown, infer M> ? M["_annotations"] extends Record<Annotations, true> ? never : K : never }[keyof T];
|
|
248
|
+
/** Extracts the union of all annotation names present across all columns in a record. */
|
|
249
|
+
type AllAnnotations<T extends ColumnRecord> = { [K in keyof T] : T[K] extends ColumnBuilder<unknown, infer M> ? keyof M["_annotations"] & string : never }[keyof T];
|
|
207
250
|
/**
|
|
208
251
|
* $infer -- default SELECT type.
|
|
209
|
-
* Excludes hidden
|
|
252
|
+
* Excludes columns annotated 'hidden'. Includes everything else.
|
|
210
253
|
*/
|
|
211
|
-
type Infer<T extends ColumnRecord> = { [K in
|
|
254
|
+
type Infer<T extends ColumnRecord> = { [K in ColumnKeysWithoutAnyAnnotation<T, "hidden">] : InferColumnType<T[K]> };
|
|
212
255
|
/**
|
|
213
256
|
* $infer_all -- all columns including hidden.
|
|
214
257
|
*/
|
|
@@ -224,21 +267,26 @@ type Insert<T extends ColumnRecord> = { [K in ColumnKeysWhereNot<T, "hasDefault"
|
|
|
224
267
|
*/
|
|
225
268
|
type Update<T extends ColumnRecord> = { [K in ColumnKeysWhereNot<T, "primary">]? : InferColumnType<T[K]> };
|
|
226
269
|
/**
|
|
227
|
-
* $
|
|
228
|
-
|
|
270
|
+
* $response -- API response shape. Excludes columns annotated 'hidden'.
|
|
271
|
+
*/
|
|
272
|
+
type Response<T extends ColumnRecord> = { [K in ColumnKeysWithoutAnyAnnotation<T, "hidden">] : InferColumnType<T[K]> };
|
|
273
|
+
/**
|
|
274
|
+
* $create_input -- API create input shape.
|
|
275
|
+
* Excludes readOnly and primary key columns.
|
|
276
|
+
* Columns with defaults are optional.
|
|
229
277
|
*/
|
|
230
|
-
type
|
|
278
|
+
type ApiCreateInput<T extends ColumnRecord> = { [K in ColumnKeysWhereNot<T, "isReadOnly"> & ColumnKeysWhereNot<T, "primary"> & ColumnKeysWhereNot<T, "hasDefault"> & string] : InferColumnType<T[K]> } & { [K in ColumnKeysWhereNot<T, "isReadOnly"> & ColumnKeysWhereNot<T, "primary"> & ColumnKeysWhere<T, "hasDefault"> & string]? : InferColumnType<T[K]> };
|
|
231
279
|
/**
|
|
232
|
-
* $
|
|
233
|
-
*
|
|
280
|
+
* $update_input -- API update input shape.
|
|
281
|
+
* Excludes readOnly and primary key columns. All fields optional (partial update).
|
|
234
282
|
*/
|
|
235
|
-
type
|
|
283
|
+
type ApiUpdateInput<T extends ColumnRecord> = { [K in ColumnKeysWhereNot<T, "isReadOnly"> & ColumnKeysWhereNot<T, "primary"> & string]? : InferColumnType<T[K]> };
|
|
236
284
|
interface TableDef<TColumns extends ColumnRecord = ColumnRecord> {
|
|
237
285
|
readonly _name: string;
|
|
238
286
|
readonly _columns: TColumns;
|
|
239
287
|
readonly _indexes: readonly IndexDef[];
|
|
240
288
|
readonly _shared: boolean;
|
|
241
|
-
/** Default SELECT type -- excludes hidden
|
|
289
|
+
/** Default SELECT type -- excludes columns annotated 'hidden'. */
|
|
242
290
|
readonly $infer: Infer<TColumns>;
|
|
243
291
|
/** All columns including hidden. */
|
|
244
292
|
readonly $infer_all: InferAll<TColumns>;
|
|
@@ -246,10 +294,12 @@ interface TableDef<TColumns extends ColumnRecord = ColumnRecord> {
|
|
|
246
294
|
readonly $insert: Insert<TColumns>;
|
|
247
295
|
/** Update type -- all non-PK columns optional. ALL columns included. */
|
|
248
296
|
readonly $update: Update<TColumns>;
|
|
249
|
-
/**
|
|
250
|
-
readonly $
|
|
251
|
-
/**
|
|
252
|
-
readonly $
|
|
297
|
+
/** API response shape — excludes columns annotated 'hidden'. */
|
|
298
|
+
readonly $response: Response<TColumns>;
|
|
299
|
+
/** API create input — excludes readOnly + PK; defaulted columns optional. */
|
|
300
|
+
readonly $create_input: ApiCreateInput<TColumns>;
|
|
301
|
+
/** API update input — excludes readOnly + PK; all fields optional. */
|
|
302
|
+
readonly $update_input: ApiUpdateInput<TColumns>;
|
|
253
303
|
/** Mark this table as shared / cross-tenant. */
|
|
254
304
|
shared(): TableDef<TColumns>;
|
|
255
305
|
}
|
|
@@ -257,185 +307,397 @@ interface TableOptions {
|
|
|
257
307
|
relations?: Record<string, RelationDef>;
|
|
258
308
|
indexes?: IndexDef[];
|
|
259
309
|
}
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
310
|
+
/**
|
|
311
|
+
* Database Adapter Types for @vertz/db
|
|
312
|
+
*
|
|
313
|
+
* Generic adapter interface that abstracts database operations.
|
|
314
|
+
* Implemented by SQLite, D1, and other database adapters.
|
|
315
|
+
*/
|
|
316
|
+
interface ListOptions {
|
|
317
|
+
where?: Record<string, unknown>;
|
|
318
|
+
orderBy?: Record<string, "asc" | "desc">;
|
|
319
|
+
limit?: number;
|
|
320
|
+
/** Cursor-based pagination: fetch records after this ID. */
|
|
321
|
+
after?: string;
|
|
268
322
|
}
|
|
269
|
-
interface
|
|
270
|
-
|
|
323
|
+
interface EntityDbAdapter {
|
|
324
|
+
get(id: string): Promise<Record<string, unknown> | null>;
|
|
325
|
+
list(options?: ListOptions): Promise<{
|
|
326
|
+
data: Record<string, unknown>[];
|
|
327
|
+
total: number;
|
|
328
|
+
}>;
|
|
329
|
+
create(data: Record<string, unknown>): Promise<Record<string, unknown>>;
|
|
330
|
+
update(id: string, data: Record<string, unknown>): Promise<Record<string, unknown>>;
|
|
331
|
+
delete(id: string): Promise<Record<string, unknown> | null>;
|
|
271
332
|
}
|
|
272
|
-
interface
|
|
273
|
-
|
|
274
|
-
targetTable: string;
|
|
275
|
-
targetColumn: string;
|
|
333
|
+
interface D1DatabaseBinding {
|
|
334
|
+
prepare(sql: string): D1PreparedStatement;
|
|
276
335
|
}
|
|
277
|
-
interface
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
336
|
+
interface D1PreparedStatement {
|
|
337
|
+
bind(...values: unknown[]): D1PreparedStatement;
|
|
338
|
+
all(): Promise<{
|
|
339
|
+
results: unknown[];
|
|
340
|
+
}>;
|
|
341
|
+
run(): Promise<{
|
|
342
|
+
meta: {
|
|
343
|
+
changes: number;
|
|
344
|
+
};
|
|
345
|
+
}>;
|
|
282
346
|
}
|
|
283
|
-
interface
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
347
|
+
interface D1AdapterOptions<T extends ColumnRecord> {
|
|
348
|
+
/** The table schema definition */
|
|
349
|
+
schema: TableDef<T>;
|
|
350
|
+
/** D1 database binding from Cloudflare env */
|
|
351
|
+
d1: D1DatabaseBinding;
|
|
352
|
+
/**
|
|
353
|
+
* Whether migrations should be applied at runtime.
|
|
354
|
+
* NOTE: For D1, migrations should typically be run via `wrangler d1 migrations apply`
|
|
355
|
+
* during deployment, not at runtime. Set to false for production use.
|
|
356
|
+
*/
|
|
357
|
+
migrations?: {
|
|
358
|
+
autoApply?: boolean;
|
|
359
|
+
};
|
|
287
360
|
}
|
|
288
361
|
/**
|
|
289
|
-
*
|
|
362
|
+
* Create a DbDriver from a D1 database binding.
|
|
290
363
|
*/
|
|
291
|
-
|
|
292
|
-
rows: readonly Record<string, unknown>[];
|
|
293
|
-
rowCount: number;
|
|
294
|
-
}>;
|
|
364
|
+
declare function createD1Driver(d1: D1DatabaseBinding): DbDriver;
|
|
295
365
|
/**
|
|
296
|
-
*
|
|
366
|
+
* Create a D1 EntityDbAdapter from a schema and D1 binding.
|
|
367
|
+
*
|
|
368
|
+
* NOTE: For production D1 deployments, migrations should be run via
|
|
369
|
+
* `wrangler d1 migrations apply` during deployment, NOT at runtime.
|
|
370
|
+
* Set `migrations.autoApply = false` or omit the migrations option for production.
|
|
297
371
|
*/
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
372
|
+
declare function createD1Adapter<T extends ColumnRecord>(options: D1AdapterOptions<T>): EntityDbAdapter;
|
|
373
|
+
import { Result } from "@vertz/schema";
|
|
374
|
+
type IdStrategy = "cuid" | "uuid" | "nanoid";
|
|
375
|
+
declare function generateId(strategy: IdStrategy): string;
|
|
376
|
+
interface Dialect {
|
|
377
|
+
/** Dialect name. */
|
|
378
|
+
readonly name: "postgres" | "sqlite";
|
|
379
|
+
/**
|
|
380
|
+
* Parameter placeholder: $1, $2 (postgres) or ? (sqlite).
|
|
381
|
+
* @param index - 1-based parameter index
|
|
382
|
+
*/
|
|
383
|
+
param(index: number): string;
|
|
384
|
+
/** SQL function for current timestamp. */
|
|
385
|
+
now(): string;
|
|
386
|
+
/**
|
|
387
|
+
* Map a vertz column sqlType to the dialect's SQL type.
|
|
388
|
+
* @param sqlType - The generic sqlType from column metadata
|
|
389
|
+
* @param meta - Additional metadata (enum values, length, precision)
|
|
390
|
+
*/
|
|
391
|
+
mapColumnType(sqlType: string, meta?: ColumnTypeMeta): string;
|
|
392
|
+
/** Whether the dialect supports RETURNING clause. */
|
|
393
|
+
readonly supportsReturning: boolean;
|
|
394
|
+
/** Whether the dialect supports array operators (@>, <@, &&). */
|
|
395
|
+
readonly supportsArrayOps: boolean;
|
|
396
|
+
/** Whether the dialect supports JSONB path operators (->>, ->). */
|
|
397
|
+
readonly supportsJsonbPath: boolean;
|
|
398
|
+
}
|
|
399
|
+
interface ColumnTypeMeta {
|
|
400
|
+
readonly enumName?: string;
|
|
401
|
+
readonly enumValues?: readonly string[];
|
|
402
|
+
readonly length?: number;
|
|
403
|
+
readonly precision?: number;
|
|
404
|
+
readonly scale?: number;
|
|
302
405
|
}
|
|
303
406
|
/**
|
|
304
|
-
*
|
|
407
|
+
* PostgreSQL dialect implementation.
|
|
408
|
+
*
|
|
409
|
+
* Extracted from existing behavior — no functional changes.
|
|
305
410
|
*/
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
dryRun: boolean;
|
|
315
|
-
/** The statements that were (or would be) executed, in order. */
|
|
316
|
-
statements: string[];
|
|
317
|
-
}
|
|
318
|
-
interface MigrateDeployOptions {
|
|
319
|
-
queryFn: MigrationQueryFn;
|
|
320
|
-
migrationFiles: MigrationFile[];
|
|
321
|
-
/** When true, return the SQL that would be executed without applying. */
|
|
322
|
-
dryRun?: boolean;
|
|
323
|
-
}
|
|
324
|
-
interface MigrateDeployResult {
|
|
325
|
-
applied: string[];
|
|
326
|
-
alreadyApplied: string[];
|
|
327
|
-
/** When dry-run is enabled, contains the details of each migration that would be applied. */
|
|
328
|
-
dryRun: boolean;
|
|
329
|
-
/** Detailed results for each migration that was (or would be) applied. */
|
|
330
|
-
migrations?: ApplyResult[];
|
|
411
|
+
declare class PostgresDialect implements Dialect {
|
|
412
|
+
readonly name: "postgres";
|
|
413
|
+
readonly supportsReturning: true;
|
|
414
|
+
readonly supportsArrayOps: true;
|
|
415
|
+
readonly supportsJsonbPath: true;
|
|
416
|
+
param(index: number): string;
|
|
417
|
+
now(): string;
|
|
418
|
+
mapColumnType(sqlType: string, meta?: ColumnTypeMeta): string;
|
|
331
419
|
}
|
|
420
|
+
/** Default Postgres dialect instance. */
|
|
421
|
+
declare const defaultPostgresDialect: PostgresDialect;
|
|
332
422
|
/**
|
|
333
|
-
*
|
|
423
|
+
* SQLite dialect implementation.
|
|
334
424
|
*
|
|
335
|
-
*
|
|
425
|
+
* SQLite 3.35+ supports RETURNING clause.
|
|
336
426
|
*/
|
|
337
|
-
declare
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
427
|
+
declare class SqliteDialect implements Dialect {
|
|
428
|
+
readonly name: "sqlite";
|
|
429
|
+
readonly supportsReturning: true;
|
|
430
|
+
readonly supportsArrayOps: false;
|
|
431
|
+
readonly supportsJsonbPath: false;
|
|
432
|
+
param(_index: number): string;
|
|
433
|
+
now(): string;
|
|
434
|
+
mapColumnType(sqlType: string, _meta?: ColumnTypeMeta): string;
|
|
343
435
|
}
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
dryRun: boolean;
|
|
436
|
+
/** Default SQLite dialect instance. */
|
|
437
|
+
declare const defaultSqliteDialect: SqliteDialect;
|
|
438
|
+
interface DbErrorJson {
|
|
439
|
+
readonly error: string;
|
|
440
|
+
readonly code: string;
|
|
441
|
+
readonly message: string;
|
|
442
|
+
readonly table?: string;
|
|
443
|
+
readonly column?: string;
|
|
353
444
|
}
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
445
|
+
declare abstract class DbError extends Error {
|
|
446
|
+
abstract readonly code: string;
|
|
447
|
+
/** Raw PostgreSQL SQLSTATE code, if applicable. */
|
|
448
|
+
readonly pgCode?: string | undefined;
|
|
449
|
+
readonly table?: string | undefined;
|
|
450
|
+
readonly query?: string | undefined;
|
|
451
|
+
constructor(message: string);
|
|
452
|
+
toJSON(): DbErrorJson;
|
|
361
453
|
}
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
declare function migrateDev(options: MigrateDevOptions): Promise<MigrateDevResult>;
|
|
368
|
-
interface PushOptions {
|
|
369
|
-
queryFn: MigrationQueryFn;
|
|
370
|
-
currentSnapshot: SchemaSnapshot;
|
|
371
|
-
previousSnapshot: SchemaSnapshot;
|
|
454
|
+
interface UniqueConstraintErrorOptions {
|
|
455
|
+
readonly table: string;
|
|
456
|
+
readonly column: string;
|
|
457
|
+
readonly value?: string;
|
|
458
|
+
readonly query?: string;
|
|
372
459
|
}
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
460
|
+
declare class UniqueConstraintError extends DbError {
|
|
461
|
+
readonly code: "UNIQUE_VIOLATION";
|
|
462
|
+
readonly pgCode: "23505";
|
|
463
|
+
readonly table: string;
|
|
464
|
+
readonly query: string | undefined;
|
|
465
|
+
readonly column: string;
|
|
466
|
+
readonly value: string | undefined;
|
|
467
|
+
constructor(options: UniqueConstraintErrorOptions);
|
|
468
|
+
toJSON(): DbErrorJson;
|
|
376
469
|
}
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
queryFn: MigrationQueryFn;
|
|
383
|
-
migrationFiles: MigrationFile[];
|
|
470
|
+
interface ForeignKeyErrorOptions {
|
|
471
|
+
readonly table: string;
|
|
472
|
+
readonly constraint: string;
|
|
473
|
+
readonly detail?: string;
|
|
474
|
+
readonly query?: string;
|
|
384
475
|
}
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
476
|
+
declare class ForeignKeyError extends DbError {
|
|
477
|
+
readonly code: "FOREIGN_KEY_VIOLATION";
|
|
478
|
+
readonly pgCode: "23503";
|
|
479
|
+
readonly table: string;
|
|
480
|
+
readonly query: string | undefined;
|
|
481
|
+
readonly constraint: string;
|
|
482
|
+
readonly detail: string | undefined;
|
|
483
|
+
constructor(options: ForeignKeyErrorOptions);
|
|
484
|
+
toJSON(): DbErrorJson;
|
|
389
485
|
}
|
|
390
|
-
interface
|
|
391
|
-
|
|
392
|
-
|
|
486
|
+
interface NotNullErrorOptions {
|
|
487
|
+
readonly table: string;
|
|
488
|
+
readonly column: string;
|
|
489
|
+
readonly query?: string;
|
|
393
490
|
}
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
* 1. Execute parameterized SQL
|
|
403
|
-
* 2. Map PG errors to typed DbError subclasses
|
|
404
|
-
* 3. Return typed QueryResult
|
|
405
|
-
*/
|
|
406
|
-
interface ExecutorResult<T> {
|
|
407
|
-
readonly rows: readonly T[];
|
|
408
|
-
readonly rowCount: number;
|
|
491
|
+
declare class NotNullError extends DbError {
|
|
492
|
+
readonly code: "NOT_NULL_VIOLATION";
|
|
493
|
+
readonly pgCode: "23502";
|
|
494
|
+
readonly table: string;
|
|
495
|
+
readonly query: string | undefined;
|
|
496
|
+
readonly column: string;
|
|
497
|
+
constructor(options: NotNullErrorOptions);
|
|
498
|
+
toJSON(): DbErrorJson;
|
|
409
499
|
}
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
readonly
|
|
414
|
-
readonly ne?: T;
|
|
415
|
-
readonly gt?: T;
|
|
416
|
-
readonly gte?: T;
|
|
417
|
-
readonly lt?: T;
|
|
418
|
-
readonly lte?: T;
|
|
419
|
-
readonly in?: readonly T[];
|
|
420
|
-
readonly notIn?: readonly T[];
|
|
500
|
+
interface CheckConstraintErrorOptions {
|
|
501
|
+
readonly table: string;
|
|
502
|
+
readonly constraint: string;
|
|
503
|
+
readonly query?: string;
|
|
421
504
|
}
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
readonly
|
|
425
|
-
readonly
|
|
426
|
-
readonly
|
|
505
|
+
declare class CheckConstraintError extends DbError {
|
|
506
|
+
readonly code: "CHECK_VIOLATION";
|
|
507
|
+
readonly pgCode: "23514";
|
|
508
|
+
readonly table: string;
|
|
509
|
+
readonly query: string | undefined;
|
|
510
|
+
readonly constraint: string;
|
|
511
|
+
constructor(options: CheckConstraintErrorOptions);
|
|
512
|
+
toJSON(): DbErrorJson;
|
|
427
513
|
}
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
readonly
|
|
514
|
+
declare class NotFoundError extends DbError {
|
|
515
|
+
readonly code: "NotFound";
|
|
516
|
+
readonly table: string;
|
|
517
|
+
readonly query: string | undefined;
|
|
518
|
+
constructor(table: string, query?: string);
|
|
519
|
+
toJSON(): DbErrorJson;
|
|
431
520
|
}
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
521
|
+
declare class ConnectionError extends DbError {
|
|
522
|
+
readonly code: string;
|
|
523
|
+
constructor(message: string);
|
|
524
|
+
}
|
|
525
|
+
declare class ConnectionPoolExhaustedError extends ConnectionError {
|
|
526
|
+
readonly code: "POOL_EXHAUSTED";
|
|
527
|
+
constructor(poolSize: number);
|
|
528
|
+
}
|
|
529
|
+
/**
|
|
530
|
+
* Maps semantic error names to their corresponding PostgreSQL SQLSTATE codes.
|
|
531
|
+
*
|
|
532
|
+
* Usage in switch statements:
|
|
533
|
+
* ```ts
|
|
534
|
+
* switch (error.code) {
|
|
535
|
+
* case 'UNIQUE_VIOLATION': // ...
|
|
536
|
+
* case 'FOREIGN_KEY_VIOLATION': // ...
|
|
537
|
+
* }
|
|
538
|
+
* ```
|
|
539
|
+
*
|
|
540
|
+
* Reverse lookup (semantic name -> PG code):
|
|
541
|
+
* ```ts
|
|
542
|
+
* DbErrorCode.UNIQUE_VIOLATION // '23505'
|
|
543
|
+
* ```
|
|
544
|
+
*/
|
|
545
|
+
declare const DbErrorCode: {
|
|
546
|
+
readonly UNIQUE_VIOLATION: "23505";
|
|
547
|
+
readonly FOREIGN_KEY_VIOLATION: "23503";
|
|
548
|
+
readonly NOT_NULL_VIOLATION: "23502";
|
|
549
|
+
readonly CHECK_VIOLATION: "23514";
|
|
550
|
+
readonly EXCLUSION_VIOLATION: "23P01";
|
|
551
|
+
readonly SERIALIZATION_FAILURE: "40001";
|
|
552
|
+
readonly DEADLOCK_DETECTED: "40P01";
|
|
553
|
+
readonly CONNECTION_EXCEPTION: "08000";
|
|
554
|
+
readonly CONNECTION_DOES_NOT_EXIST: "08003";
|
|
555
|
+
readonly CONNECTION_FAILURE: "08006";
|
|
556
|
+
readonly NotFound: "NotFound";
|
|
557
|
+
readonly CONNECTION_ERROR: "CONNECTION_ERROR";
|
|
558
|
+
readonly POOL_EXHAUSTED: "POOL_EXHAUSTED";
|
|
559
|
+
};
|
|
560
|
+
/** Union of all semantic error code keys (e.g., `'UNIQUE_VIOLATION' | 'FOREIGN_KEY_VIOLATION' | ...`). */
|
|
561
|
+
type DbErrorCodeName = keyof typeof DbErrorCode;
|
|
562
|
+
/** Union of all raw PG error code values (e.g., `'23505' | '23503' | ...`). */
|
|
563
|
+
type DbErrorCodeValue = (typeof DbErrorCode)[keyof typeof DbErrorCode];
|
|
564
|
+
/**
|
|
565
|
+
* Reverse map: raw PG code -> semantic name.
|
|
566
|
+
* Built at module load time from DbErrorCode.
|
|
567
|
+
*/
|
|
568
|
+
declare const PgCodeToName: Readonly<Record<string, DbErrorCodeName | undefined>>;
|
|
569
|
+
/**
|
|
570
|
+
* Look up the semantic name for a raw PG error code.
|
|
571
|
+
* Returns the key (e.g., `'UNIQUE_VIOLATION'`) or `undefined` if unmapped.
|
|
572
|
+
*/
|
|
573
|
+
declare function resolveErrorCode(pgCode: string): DbErrorCodeName | undefined;
|
|
574
|
+
interface HttpErrorResponse {
|
|
575
|
+
readonly status: number;
|
|
576
|
+
readonly body: DbErrorJson;
|
|
577
|
+
}
|
|
578
|
+
/**
|
|
579
|
+
* Maps a DbError to an HTTP error response with the appropriate status code.
|
|
580
|
+
*
|
|
581
|
+
* - UniqueConstraintError -> 409 Conflict
|
|
582
|
+
* - NotFoundError -> 404 Not Found
|
|
583
|
+
* - ForeignKeyError -> 422 Unprocessable Entity
|
|
584
|
+
* - NotNullError -> 422 Unprocessable Entity
|
|
585
|
+
* - CheckConstraintError -> 422 Unprocessable Entity
|
|
586
|
+
* - ConnectionError -> 503 Service Unavailable
|
|
587
|
+
* - Unknown DbError -> 500 Internal Server Error
|
|
588
|
+
*/
|
|
589
|
+
declare function dbErrorToHttpError(error: DbError): HttpErrorResponse;
|
|
590
|
+
interface PgErrorInput {
|
|
591
|
+
readonly code: string;
|
|
592
|
+
readonly message: string;
|
|
593
|
+
readonly table?: string;
|
|
594
|
+
readonly column?: string;
|
|
595
|
+
readonly constraint?: string;
|
|
596
|
+
readonly detail?: string;
|
|
597
|
+
}
|
|
598
|
+
/**
|
|
599
|
+
* Maps a raw PostgreSQL error object to a typed DbError subclass.
|
|
600
|
+
*
|
|
601
|
+
* Extracts structured metadata (column, constraint, value) from the
|
|
602
|
+
* PG error's `detail` and `message` fields.
|
|
603
|
+
*/
|
|
604
|
+
declare function parsePgError(pgError: PgErrorInput, query?: string): DbError;
|
|
605
|
+
/**
|
|
606
|
+
* Base interface for database errors with code, message, and optional cause.
|
|
607
|
+
*/
|
|
608
|
+
interface DbErrorBase {
|
|
609
|
+
readonly code: string;
|
|
610
|
+
readonly message: string;
|
|
611
|
+
readonly cause?: unknown;
|
|
612
|
+
}
|
|
613
|
+
/**
|
|
614
|
+
* Connection errors - failed to connect or connection lost.
|
|
615
|
+
*/
|
|
616
|
+
interface DbConnectionError extends DbErrorBase {
|
|
617
|
+
readonly code: "CONNECTION_ERROR";
|
|
618
|
+
}
|
|
619
|
+
/**
|
|
620
|
+
* Query execution errors - SQL syntax, timeout, etc.
|
|
621
|
+
*/
|
|
622
|
+
interface DbQueryError extends DbErrorBase {
|
|
623
|
+
readonly code: "QUERY_ERROR";
|
|
624
|
+
readonly sql?: string;
|
|
625
|
+
}
|
|
626
|
+
/**
|
|
627
|
+
* Constraint violations - unique, foreign key, not null, check.
|
|
628
|
+
*/
|
|
629
|
+
interface DbConstraintError extends DbErrorBase {
|
|
630
|
+
readonly code: "CONSTRAINT_ERROR";
|
|
631
|
+
readonly constraint?: string;
|
|
632
|
+
readonly table?: string;
|
|
633
|
+
readonly column?: string;
|
|
634
|
+
}
|
|
635
|
+
/**
|
|
636
|
+
* Record not found - for getOrThrow, update, delete operations.
|
|
637
|
+
*/
|
|
638
|
+
interface DbNotFoundError extends DbErrorBase {
|
|
639
|
+
readonly code: "NotFound";
|
|
640
|
+
readonly table: string;
|
|
641
|
+
}
|
|
642
|
+
/**
|
|
643
|
+
* Read operations can fail with connection errors, query errors, or not found.
|
|
644
|
+
*/
|
|
645
|
+
type ReadError = DbConnectionError | DbQueryError | DbNotFoundError;
|
|
646
|
+
/**
|
|
647
|
+
* Write operations can fail with connection errors, query errors, or constraint violations.
|
|
648
|
+
*/
|
|
649
|
+
type WriteError = DbConnectionError | DbQueryError | DbConstraintError;
|
|
650
|
+
/**
|
|
651
|
+
* Maps a raw error to a ReadError.
|
|
652
|
+
* Categorizes PostgreSQL errors into appropriate error types.
|
|
653
|
+
*/
|
|
654
|
+
declare function toReadError(error: unknown, query?: string): ReadError;
|
|
655
|
+
/**
|
|
656
|
+
* Maps a raw error to a WriteError.
|
|
657
|
+
* Categorizes PostgreSQL errors into appropriate error types.
|
|
658
|
+
*/
|
|
659
|
+
declare function toWriteError(error: unknown, query?: string): WriteError;
|
|
660
|
+
/**
|
|
661
|
+
* Query executor — wraps raw SQL execution with error mapping.
|
|
662
|
+
*
|
|
663
|
+
* Takes a query function (from the database driver) and wraps it to:
|
|
664
|
+
* 1. Execute parameterized SQL
|
|
665
|
+
* 2. Map PG errors to typed DbError subclasses
|
|
666
|
+
* 3. Return typed QueryResult
|
|
667
|
+
*/
|
|
668
|
+
interface ExecutorResult<T> {
|
|
669
|
+
readonly rows: readonly T[];
|
|
670
|
+
readonly rowCount: number;
|
|
671
|
+
}
|
|
672
|
+
type QueryFn = <T>(sql: string, params: readonly unknown[]) => Promise<ExecutorResult<T>>;
|
|
673
|
+
/** Operators available for comparable types (number, string, Date, bigint). */
|
|
674
|
+
interface ComparisonOperators<T> {
|
|
675
|
+
readonly eq?: T;
|
|
676
|
+
readonly ne?: T;
|
|
677
|
+
readonly gt?: T;
|
|
678
|
+
readonly gte?: T;
|
|
679
|
+
readonly lt?: T;
|
|
680
|
+
readonly lte?: T;
|
|
681
|
+
readonly in?: readonly T[];
|
|
682
|
+
readonly notIn?: readonly T[];
|
|
683
|
+
}
|
|
684
|
+
/** Additional operators for string columns. */
|
|
685
|
+
interface StringOperators {
|
|
686
|
+
readonly contains?: string;
|
|
687
|
+
readonly startsWith?: string;
|
|
688
|
+
readonly endsWith?: string;
|
|
689
|
+
}
|
|
690
|
+
/** The `isNull` operator — only available for nullable columns. */
|
|
691
|
+
interface NullOperator {
|
|
692
|
+
readonly isNull?: boolean;
|
|
693
|
+
}
|
|
694
|
+
/**
|
|
695
|
+
* Resolves the filter operators for a single column based on its inferred type
|
|
696
|
+
* and nullable metadata.
|
|
697
|
+
*
|
|
698
|
+
* - All types get comparison + in/notIn
|
|
699
|
+
* - String types additionally get contains, startsWith, endsWith
|
|
700
|
+
* - Nullable columns additionally get isNull
|
|
439
701
|
*
|
|
440
702
|
* Uses [T] extends [string] to prevent union distribution -- ensures that a
|
|
441
703
|
* union like 'admin' | 'editor' keeps the full union in each operator slot.
|
|
@@ -461,42 +723,41 @@ type OrderByType<TColumns extends ColumnRecord> = { [K in keyof TColumns]? : "as
|
|
|
461
723
|
* SelectOption<TColumns> — the `select` field in query options.
|
|
462
724
|
*
|
|
463
725
|
* Either:
|
|
464
|
-
* - `{ not:
|
|
726
|
+
* - `{ not: Annotation | Annotation[] }` — exclude columns by annotation(s)
|
|
465
727
|
* - `{ [column]: true }` — explicitly pick columns
|
|
466
728
|
*
|
|
467
729
|
* The two forms are mutually exclusive, enforced via `never` mapped keys.
|
|
468
730
|
*/
|
|
469
731
|
type SelectOption<TColumns extends ColumnRecord> = ({
|
|
470
|
-
readonly not:
|
|
732
|
+
readonly not: AllAnnotations<TColumns> | readonly AllAnnotations<TColumns>[];
|
|
471
733
|
} & { readonly [K in keyof TColumns]? : never }) | ({ readonly [K in keyof TColumns]? : true } & {
|
|
472
734
|
readonly not?: never;
|
|
473
735
|
});
|
|
474
|
-
/** Keys of columns where a given metadata flag is NOT `true`. */
|
|
475
|
-
type ColumnKeysWhereNot2<
|
|
476
|
-
T extends ColumnRecord,
|
|
477
|
-
Flag extends keyof ColumnMetadata
|
|
478
|
-
> = { [K in keyof T] : T[K] extends ColumnBuilder<unknown, infer M> ? M extends Record<Flag, true> ? never : K : never }[keyof T];
|
|
479
736
|
/** Extract selected keys from a select map (keys set to `true`). */
|
|
480
737
|
type SelectedKeys<
|
|
481
738
|
TColumns extends ColumnRecord,
|
|
482
739
|
TSelect
|
|
483
740
|
> = { [K in keyof TSelect] : K extends keyof TColumns ? (TSelect[K] extends true ? K : never) : never }[keyof TSelect];
|
|
484
741
|
/**
|
|
742
|
+
* Normalize `not` value to a union of annotation strings.
|
|
743
|
+
* - `'annotation'` → `'annotation'`
|
|
744
|
+
* - `readonly ['a', 'b']` → `'a' | 'b'`
|
|
745
|
+
*/
|
|
746
|
+
type NormalizeAnnotations<T> = T extends readonly (infer F)[] ? F extends string ? F : never : T extends string ? T : never;
|
|
747
|
+
/**
|
|
485
748
|
* SelectNarrow<TColumns, TSelect> — applies a select clause to narrow the result type.
|
|
486
749
|
*
|
|
487
|
-
* - `{ not: 'sensitive' }` → excludes sensitive AND hidden columns
|
|
488
|
-
* - `{ not: '
|
|
750
|
+
* - `{ not: 'sensitive' }` → excludes 'sensitive'-annotated AND 'hidden'-annotated columns
|
|
751
|
+
* - `{ not: ['sensitive', 'patchable'] }` → excludes columns with ANY listed annotation + 'hidden'
|
|
489
752
|
* - `{ id: true, name: true }` → picks only id and name
|
|
490
|
-
* - `undefined` → default: excludes hidden columns ($infer behavior)
|
|
753
|
+
* - `undefined` → default: excludes 'hidden'-annotated columns ($infer behavior)
|
|
491
754
|
*/
|
|
492
755
|
type SelectNarrow<
|
|
493
756
|
TColumns extends ColumnRecord,
|
|
494
757
|
TSelect
|
|
495
758
|
> = TSelect extends {
|
|
496
|
-
not:
|
|
497
|
-
} ? { [K in
|
|
498
|
-
not: "hidden";
|
|
499
|
-
} ? { [K in ColumnKeysWhereNot2<TColumns, "hidden"> & keyof TColumns] : InferColumnType<TColumns[K]> } : TSelect extends Record<string, true | undefined> ? { [K in SelectedKeys<TColumns, TSelect> & keyof TColumns] : InferColumnType<TColumns[K]> } : { [K in ColumnKeysWhereNot2<TColumns, "hidden"> & keyof TColumns] : InferColumnType<TColumns[K]> };
|
|
759
|
+
not: infer TNot;
|
|
760
|
+
} ? { [K in ColumnKeysWithoutAnyAnnotation<TColumns, NormalizeAnnotations<TNot> | "hidden"> & keyof TColumns] : InferColumnType<TColumns[K]> } : TSelect extends Record<string, true | undefined> ? { [K in SelectedKeys<TColumns, TSelect> & keyof TColumns] : InferColumnType<TColumns[K]> } : { [K in ColumnKeysWithoutAnyAnnotation<TColumns, "hidden"> & keyof TColumns] : InferColumnType<TColumns[K]> };
|
|
500
761
|
/** Relations record — maps relation names to RelationDef. */
|
|
501
762
|
type RelationsRecord = Record<string, RelationDef>;
|
|
502
763
|
/**
|
|
@@ -574,8 +835,8 @@ type InsertInput<TTable extends TableDef<ColumnRecord>> = TTable["$insert"];
|
|
|
574
835
|
* All non-PK columns, all optional.
|
|
575
836
|
*/
|
|
576
837
|
type UpdateInput<TTable extends TableDef<ColumnRecord>> = TTable["$update"];
|
|
577
|
-
/** A
|
|
578
|
-
interface
|
|
838
|
+
/** A model entry in the database registry, pairing a table with its relations. */
|
|
839
|
+
interface ModelEntry<
|
|
579
840
|
TTable extends TableDef<ColumnRecord> = TableDef<ColumnRecord>,
|
|
580
841
|
TRelations extends RelationsRecord = RelationsRecord
|
|
581
842
|
> {
|
|
@@ -583,13 +844,13 @@ interface TableEntry<
|
|
|
583
844
|
readonly relations: TRelations;
|
|
584
845
|
}
|
|
585
846
|
/**
|
|
586
|
-
* Database<
|
|
847
|
+
* Database<TModels> — type that carries the full model registry.
|
|
587
848
|
*
|
|
588
849
|
* Used as the foundation for typed query methods (implemented in later tickets).
|
|
589
850
|
* Provides type-safe access to table definitions and their relations.
|
|
590
851
|
*/
|
|
591
|
-
interface Database<
|
|
592
|
-
readonly
|
|
852
|
+
interface Database<TModels extends Record<string, ModelEntry> = Record<string, ModelEntry>> {
|
|
853
|
+
readonly _models: TModels;
|
|
593
854
|
}
|
|
594
855
|
/**
|
|
595
856
|
* SQL tagged template literal and escape hatch.
|
|
@@ -619,6 +880,26 @@ interface SqlFragment {
|
|
|
619
880
|
readonly sql: string;
|
|
620
881
|
readonly params: readonly unknown[];
|
|
621
882
|
}
|
|
883
|
+
/**
|
|
884
|
+
* D1 database binding interface.
|
|
885
|
+
*/
|
|
886
|
+
interface D1Database {
|
|
887
|
+
prepare(sql: string): D1PreparedStatement2;
|
|
888
|
+
}
|
|
889
|
+
/**
|
|
890
|
+
* D1 prepared statement interface.
|
|
891
|
+
*/
|
|
892
|
+
interface D1PreparedStatement2 {
|
|
893
|
+
bind(...values: unknown[]): D1PreparedStatement2;
|
|
894
|
+
all(): Promise<{
|
|
895
|
+
results: unknown[];
|
|
896
|
+
}>;
|
|
897
|
+
run(): Promise<{
|
|
898
|
+
meta: {
|
|
899
|
+
changes: number;
|
|
900
|
+
};
|
|
901
|
+
}>;
|
|
902
|
+
}
|
|
622
903
|
interface TenantGraph {
|
|
623
904
|
/** The tenant root table name (e.g., "organizations"). Null if no tenant columns exist. */
|
|
624
905
|
readonly root: string | null;
|
|
@@ -668,15 +949,26 @@ interface PoolConfig {
|
|
|
668
949
|
*/
|
|
669
950
|
readonly replicas?: readonly string[];
|
|
670
951
|
}
|
|
671
|
-
interface CreateDbOptions<
|
|
952
|
+
interface CreateDbOptions<TModels extends Record<string, ModelEntry>> {
|
|
953
|
+
/** Model registry mapping logical names to table definitions + relations. */
|
|
954
|
+
readonly models: TModels;
|
|
955
|
+
/** Database dialect to use. Defaults to 'postgres' if not specified. */
|
|
956
|
+
readonly dialect?: "postgres" | "sqlite";
|
|
957
|
+
/** D1 database binding (required when dialect is 'sqlite'). */
|
|
958
|
+
readonly d1?: D1Database;
|
|
672
959
|
/** PostgreSQL connection URL. */
|
|
673
|
-
readonly url
|
|
674
|
-
/** Table registry mapping logical names to table definitions + relations. */
|
|
675
|
-
readonly tables: TTables;
|
|
960
|
+
readonly url?: string;
|
|
676
961
|
/** Connection pool configuration. */
|
|
677
962
|
readonly pool?: PoolConfig;
|
|
678
963
|
/** Column name casing strategy. */
|
|
679
964
|
readonly casing?: "snake_case" | "camelCase";
|
|
965
|
+
/**
|
|
966
|
+
* Custom casing overrides for edge cases (e.g., OAuth, ID).
|
|
967
|
+
* Maps camelCase keys to snake_case column names.
|
|
968
|
+
* These overrides run BEFORE auto-casing logic.
|
|
969
|
+
* Example: { 'oAuthToken': 'oauth_token', 'userID': 'user_id' }
|
|
970
|
+
*/
|
|
971
|
+
readonly casingOverrides?: Record<string, string>;
|
|
680
972
|
/** Log function for notices (e.g., unscoped table warnings). */
|
|
681
973
|
readonly log?: (message: string) => void;
|
|
682
974
|
/**
|
|
@@ -690,21 +982,21 @@ interface QueryResult<T> {
|
|
|
690
982
|
readonly rows: readonly T[];
|
|
691
983
|
readonly rowCount: number;
|
|
692
984
|
}
|
|
693
|
-
/** Extract the TableDef from a
|
|
694
|
-
type EntryTable<TEntry extends
|
|
695
|
-
/** Extract the relations record from a
|
|
696
|
-
type EntryRelations<TEntry extends
|
|
697
|
-
/** Extract columns from a
|
|
698
|
-
type EntryColumns<TEntry extends
|
|
985
|
+
/** Extract the TableDef from a ModelEntry. */
|
|
986
|
+
type EntryTable<TEntry extends ModelEntry> = TEntry["table"];
|
|
987
|
+
/** Extract the relations record from a ModelEntry. */
|
|
988
|
+
type EntryRelations<TEntry extends ModelEntry> = TEntry["relations"];
|
|
989
|
+
/** Extract columns from a ModelEntry's table. */
|
|
990
|
+
type EntryColumns<TEntry extends ModelEntry> = EntryTable<TEntry>["_columns"];
|
|
699
991
|
/** Options for get / getOrThrow — typed per-table. */
|
|
700
|
-
type TypedGetOptions<TEntry extends
|
|
992
|
+
type TypedGetOptions<TEntry extends ModelEntry> = {
|
|
701
993
|
readonly where?: FilterType<EntryColumns<TEntry>>;
|
|
702
994
|
readonly select?: SelectOption<EntryColumns<TEntry>>;
|
|
703
995
|
readonly orderBy?: OrderByType<EntryColumns<TEntry>>;
|
|
704
996
|
readonly include?: IncludeOption<EntryRelations<TEntry>>;
|
|
705
997
|
};
|
|
706
998
|
/** Options for list / listAndCount — typed per-table. */
|
|
707
|
-
type TypedListOptions<TEntry extends
|
|
999
|
+
type TypedListOptions<TEntry extends ModelEntry> = {
|
|
708
1000
|
readonly where?: FilterType<EntryColumns<TEntry>>;
|
|
709
1001
|
readonly select?: SelectOption<EntryColumns<TEntry>>;
|
|
710
1002
|
readonly orderBy?: OrderByType<EntryColumns<TEntry>>;
|
|
@@ -717,174 +1009,115 @@ type TypedListOptions<TEntry extends TableEntry> = {
|
|
|
717
1009
|
readonly include?: IncludeOption<EntryRelations<TEntry>>;
|
|
718
1010
|
};
|
|
719
1011
|
/** Options for create — typed per-table. */
|
|
720
|
-
type TypedCreateOptions<TEntry extends
|
|
1012
|
+
type TypedCreateOptions<TEntry extends ModelEntry> = {
|
|
721
1013
|
readonly data: InsertInput<EntryTable<TEntry>>;
|
|
722
1014
|
readonly select?: SelectOption<EntryColumns<TEntry>>;
|
|
723
1015
|
};
|
|
724
1016
|
/** Options for createManyAndReturn — typed per-table. */
|
|
725
|
-
type TypedCreateManyAndReturnOptions<TEntry extends
|
|
1017
|
+
type TypedCreateManyAndReturnOptions<TEntry extends ModelEntry> = {
|
|
726
1018
|
readonly data: readonly InsertInput<EntryTable<TEntry>>[];
|
|
727
1019
|
readonly select?: SelectOption<EntryColumns<TEntry>>;
|
|
728
1020
|
};
|
|
729
1021
|
/** Options for createMany — typed per-table. */
|
|
730
|
-
type TypedCreateManyOptions<TEntry extends
|
|
1022
|
+
type TypedCreateManyOptions<TEntry extends ModelEntry> = {
|
|
731
1023
|
readonly data: readonly InsertInput<EntryTable<TEntry>>[];
|
|
732
1024
|
};
|
|
733
1025
|
/** Options for update — typed per-table. */
|
|
734
|
-
type TypedUpdateOptions<TEntry extends
|
|
1026
|
+
type TypedUpdateOptions<TEntry extends ModelEntry> = {
|
|
735
1027
|
readonly where: FilterType<EntryColumns<TEntry>>;
|
|
736
1028
|
readonly data: UpdateInput<EntryTable<TEntry>>;
|
|
737
1029
|
readonly select?: SelectOption<EntryColumns<TEntry>>;
|
|
738
1030
|
};
|
|
739
1031
|
/** Options for updateMany — typed per-table. */
|
|
740
|
-
type TypedUpdateManyOptions<TEntry extends
|
|
1032
|
+
type TypedUpdateManyOptions<TEntry extends ModelEntry> = {
|
|
741
1033
|
readonly where: FilterType<EntryColumns<TEntry>>;
|
|
742
1034
|
readonly data: UpdateInput<EntryTable<TEntry>>;
|
|
743
1035
|
};
|
|
744
1036
|
/** Options for upsert — typed per-table. */
|
|
745
|
-
type TypedUpsertOptions<TEntry extends
|
|
1037
|
+
type TypedUpsertOptions<TEntry extends ModelEntry> = {
|
|
746
1038
|
readonly where: FilterType<EntryColumns<TEntry>>;
|
|
747
1039
|
readonly create: InsertInput<EntryTable<TEntry>>;
|
|
748
1040
|
readonly update: UpdateInput<EntryTable<TEntry>>;
|
|
749
1041
|
readonly select?: SelectOption<EntryColumns<TEntry>>;
|
|
750
1042
|
};
|
|
751
1043
|
/** Options for delete — typed per-table. */
|
|
752
|
-
type TypedDeleteOptions<TEntry extends
|
|
1044
|
+
type TypedDeleteOptions<TEntry extends ModelEntry> = {
|
|
753
1045
|
readonly where: FilterType<EntryColumns<TEntry>>;
|
|
754
1046
|
readonly select?: SelectOption<EntryColumns<TEntry>>;
|
|
755
1047
|
};
|
|
756
1048
|
/** Options for deleteMany — typed per-table. */
|
|
757
|
-
type TypedDeleteManyOptions<TEntry extends
|
|
1049
|
+
type TypedDeleteManyOptions<TEntry extends ModelEntry> = {
|
|
758
1050
|
readonly where: FilterType<EntryColumns<TEntry>>;
|
|
759
1051
|
};
|
|
760
1052
|
/** Options for count — typed per-table. */
|
|
761
|
-
type TypedCountOptions<TEntry extends
|
|
1053
|
+
type TypedCountOptions<TEntry extends ModelEntry> = {
|
|
762
1054
|
readonly where?: FilterType<EntryColumns<TEntry>>;
|
|
763
1055
|
};
|
|
764
|
-
interface
|
|
765
|
-
/**
|
|
766
|
-
|
|
767
|
-
/**
|
|
768
|
-
|
|
769
|
-
/**
|
|
770
|
-
|
|
771
|
-
*/
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
* Close all pool connections.
|
|
775
|
-
*/
|
|
776
|
-
close(): Promise<void>;
|
|
777
|
-
/**
|
|
778
|
-
* Check if the database connection is healthy.
|
|
779
|
-
*/
|
|
780
|
-
isHealthy(): Promise<boolean>;
|
|
781
|
-
/**
|
|
782
|
-
* Get a single row or null.
|
|
783
|
-
*/
|
|
784
|
-
get<
|
|
785
|
-
TName extends keyof TTables & string,
|
|
786
|
-
TOptions extends TypedGetOptions<TTables[TName]>
|
|
787
|
-
>(table: TName, options?: TOptions): Promise<FindResult<EntryTable<TTables[TName]>, TOptions, EntryRelations<TTables[TName]>> | null>;
|
|
788
|
-
/**
|
|
789
|
-
* Get a single row or throw NotFoundError.
|
|
790
|
-
*/
|
|
791
|
-
getOrThrow<
|
|
792
|
-
TName extends keyof TTables & string,
|
|
793
|
-
TOptions extends TypedGetOptions<TTables[TName]>
|
|
794
|
-
>(table: TName, options?: TOptions): Promise<FindResult<EntryTable<TTables[TName]>, TOptions, EntryRelations<TTables[TName]>>>;
|
|
795
|
-
/**
|
|
796
|
-
* List multiple rows.
|
|
797
|
-
*/
|
|
798
|
-
list<
|
|
799
|
-
TName extends keyof TTables & string,
|
|
800
|
-
TOptions extends TypedListOptions<TTables[TName]>
|
|
801
|
-
>(table: TName, options?: TOptions): Promise<FindResult<EntryTable<TTables[TName]>, TOptions, EntryRelations<TTables[TName]>>[]>;
|
|
802
|
-
/**
|
|
803
|
-
* List multiple rows with total count.
|
|
804
|
-
*/
|
|
805
|
-
listAndCount<
|
|
806
|
-
TName extends keyof TTables & string,
|
|
807
|
-
TOptions extends TypedListOptions<TTables[TName]>
|
|
808
|
-
>(table: TName, options?: TOptions): Promise<{
|
|
809
|
-
data: FindResult<EntryTable<TTables[TName]>, TOptions, EntryRelations<TTables[TName]>>[];
|
|
1056
|
+
interface ModelDelegate<TEntry extends ModelEntry> {
|
|
1057
|
+
/** Get a single row or null. */
|
|
1058
|
+
get<TOptions extends TypedGetOptions<TEntry>>(options?: TOptions): Promise<Result<FindResult<EntryTable<TEntry>, TOptions, EntryRelations<TEntry>> | null, ReadError>>;
|
|
1059
|
+
/** Get a single row or return NotFoundError. */
|
|
1060
|
+
getOrThrow<TOptions extends TypedGetOptions<TEntry>>(options?: TOptions): Promise<Result<FindResult<EntryTable<TEntry>, TOptions, EntryRelations<TEntry>>, ReadError>>;
|
|
1061
|
+
/** List multiple rows. */
|
|
1062
|
+
list<TOptions extends TypedListOptions<TEntry>>(options?: TOptions): Promise<Result<FindResult<EntryTable<TEntry>, TOptions, EntryRelations<TEntry>>[], ReadError>>;
|
|
1063
|
+
/** List multiple rows with total count. */
|
|
1064
|
+
listAndCount<TOptions extends TypedListOptions<TEntry>>(options?: TOptions): Promise<Result<{
|
|
1065
|
+
data: FindResult<EntryTable<TEntry>, TOptions, EntryRelations<TEntry>>[];
|
|
810
1066
|
total: number;
|
|
811
|
-
}
|
|
812
|
-
/**
|
|
813
|
-
|
|
814
|
-
/**
|
|
815
|
-
|
|
816
|
-
/** @deprecated Use `list` instead */
|
|
817
|
-
findMany: DatabaseInstance<TTables>["list"];
|
|
818
|
-
/** @deprecated Use `listAndCount` instead */
|
|
819
|
-
findManyAndCount: DatabaseInstance<TTables>["listAndCount"];
|
|
820
|
-
/**
|
|
821
|
-
* Insert a single row and return it.
|
|
822
|
-
*/
|
|
823
|
-
create<
|
|
824
|
-
TName extends keyof TTables & string,
|
|
825
|
-
TOptions extends TypedCreateOptions<TTables[TName]>
|
|
826
|
-
>(table: TName, options: TOptions): Promise<FindResult<EntryTable<TTables[TName]>, TOptions, EntryRelations<TTables[TName]>>>;
|
|
827
|
-
/**
|
|
828
|
-
* Insert multiple rows and return the count.
|
|
829
|
-
*/
|
|
830
|
-
createMany<TName extends keyof TTables & string>(table: TName, options: TypedCreateManyOptions<TTables[TName]>): Promise<{
|
|
1067
|
+
}, ReadError>>;
|
|
1068
|
+
/** Insert a single row and return it. */
|
|
1069
|
+
create<TOptions extends TypedCreateOptions<TEntry>>(options: TOptions): Promise<Result<FindResult<EntryTable<TEntry>, TOptions, EntryRelations<TEntry>>, WriteError>>;
|
|
1070
|
+
/** Insert multiple rows and return the count. */
|
|
1071
|
+
createMany(options: TypedCreateManyOptions<TEntry>): Promise<Result<{
|
|
831
1072
|
count: number;
|
|
832
|
-
}
|
|
833
|
-
/**
|
|
834
|
-
|
|
835
|
-
*/
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
>(table: TName, options: TOptions): Promise<FindResult<EntryTable<TTables[TName]>, TOptions, EntryRelations<TTables[TName]>>[]>;
|
|
840
|
-
/**
|
|
841
|
-
* Update matching rows and return the first. Throws NotFoundError if none match.
|
|
842
|
-
*/
|
|
843
|
-
update<
|
|
844
|
-
TName extends keyof TTables & string,
|
|
845
|
-
TOptions extends TypedUpdateOptions<TTables[TName]>
|
|
846
|
-
>(table: TName, options: TOptions): Promise<FindResult<EntryTable<TTables[TName]>, TOptions, EntryRelations<TTables[TName]>>>;
|
|
847
|
-
/**
|
|
848
|
-
* Update matching rows and return the count.
|
|
849
|
-
*/
|
|
850
|
-
updateMany<TName extends keyof TTables & string>(table: TName, options: TypedUpdateManyOptions<TTables[TName]>): Promise<{
|
|
1073
|
+
}, WriteError>>;
|
|
1074
|
+
/** Insert multiple rows and return them. */
|
|
1075
|
+
createManyAndReturn<TOptions extends TypedCreateManyAndReturnOptions<TEntry>>(options: TOptions): Promise<Result<FindResult<EntryTable<TEntry>, TOptions, EntryRelations<TEntry>>[], WriteError>>;
|
|
1076
|
+
/** Update matching rows and return the first. */
|
|
1077
|
+
update<TOptions extends TypedUpdateOptions<TEntry>>(options: TOptions): Promise<Result<FindResult<EntryTable<TEntry>, TOptions, EntryRelations<TEntry>>, WriteError>>;
|
|
1078
|
+
/** Update matching rows and return the count. */
|
|
1079
|
+
updateMany(options: TypedUpdateManyOptions<TEntry>): Promise<Result<{
|
|
851
1080
|
count: number;
|
|
852
|
-
}
|
|
853
|
-
/**
|
|
854
|
-
|
|
855
|
-
*/
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
>(table: TName, options: TOptions): Promise<FindResult<EntryTable<TTables[TName]>, TOptions, EntryRelations<TTables[TName]>>>;
|
|
860
|
-
/**
|
|
861
|
-
* Delete a matching row and return it. Throws NotFoundError if none match.
|
|
862
|
-
*/
|
|
863
|
-
delete<
|
|
864
|
-
TName extends keyof TTables & string,
|
|
865
|
-
TOptions extends TypedDeleteOptions<TTables[TName]>
|
|
866
|
-
>(table: TName, options: TOptions): Promise<FindResult<EntryTable<TTables[TName]>, TOptions, EntryRelations<TTables[TName]>>>;
|
|
867
|
-
/**
|
|
868
|
-
* Delete matching rows and return the count.
|
|
869
|
-
*/
|
|
870
|
-
deleteMany<TName extends keyof TTables & string>(table: TName, options: TypedDeleteManyOptions<TTables[TName]>): Promise<{
|
|
1081
|
+
}, WriteError>>;
|
|
1082
|
+
/** Insert or update a row. */
|
|
1083
|
+
upsert<TOptions extends TypedUpsertOptions<TEntry>>(options: TOptions): Promise<Result<FindResult<EntryTable<TEntry>, TOptions, EntryRelations<TEntry>>, WriteError>>;
|
|
1084
|
+
/** Delete a matching row and return it. */
|
|
1085
|
+
delete<TOptions extends TypedDeleteOptions<TEntry>>(options: TOptions): Promise<Result<FindResult<EntryTable<TEntry>, TOptions, EntryRelations<TEntry>>, WriteError>>;
|
|
1086
|
+
/** Delete matching rows and return the count. */
|
|
1087
|
+
deleteMany(options: TypedDeleteManyOptions<TEntry>): Promise<Result<{
|
|
871
1088
|
count: number;
|
|
872
|
-
}
|
|
873
|
-
/**
|
|
874
|
-
|
|
875
|
-
*/
|
|
876
|
-
|
|
877
|
-
/**
|
|
878
|
-
|
|
879
|
-
*/
|
|
880
|
-
aggregate<TName extends keyof TTables & string>(table: TName, options: exports_aggregate.AggregateArgs): Promise<Record<string, unknown>>;
|
|
881
|
-
/**
|
|
882
|
-
* Group rows by columns and apply aggregation functions.
|
|
883
|
-
*/
|
|
884
|
-
groupBy<TName extends keyof TTables & string>(table: TName, options: exports_aggregate.GroupByArgs): Promise<Record<string, unknown>[]>;
|
|
1089
|
+
}, WriteError>>;
|
|
1090
|
+
/** Count rows matching an optional filter. */
|
|
1091
|
+
count(options?: TypedCountOptions<TEntry>): Promise<Result<number, ReadError>>;
|
|
1092
|
+
/** Run aggregation functions on a table. */
|
|
1093
|
+
aggregate(options: agg.AggregateArgs): Promise<Result<Record<string, unknown>, ReadError>>;
|
|
1094
|
+
/** Group rows by columns and apply aggregation functions. */
|
|
1095
|
+
groupBy(options: agg.GroupByArgs): Promise<Result<Record<string, unknown>[], ReadError>>;
|
|
885
1096
|
}
|
|
1097
|
+
interface DatabaseInternals<TModels extends Record<string, ModelEntry>> {
|
|
1098
|
+
/** The model registry. */
|
|
1099
|
+
readonly models: TModels;
|
|
1100
|
+
/** The SQL dialect used by this database instance. */
|
|
1101
|
+
readonly dialect: Dialect;
|
|
1102
|
+
/** The computed tenant scoping graph. */
|
|
1103
|
+
readonly tenantGraph: TenantGraph;
|
|
1104
|
+
}
|
|
1105
|
+
type DatabaseClient<TModels extends Record<string, ModelEntry>> = { readonly [K in keyof TModels] : ModelDelegate<TModels[K]> } & {
|
|
1106
|
+
/** Execute a raw SQL query via the sql tagged template. */
|
|
1107
|
+
query<T = Record<string, unknown>>(fragment: SqlFragment): Promise<Result<QueryResult<T>, ReadError>>;
|
|
1108
|
+
/** Close all pool connections. */
|
|
1109
|
+
close(): Promise<void>;
|
|
1110
|
+
/** Check if the database connection is healthy. */
|
|
1111
|
+
isHealthy(): Promise<boolean>;
|
|
1112
|
+
/** Internal properties — not part of the public API. */
|
|
1113
|
+
readonly _internals: DatabaseInternals<TModels>;
|
|
1114
|
+
};
|
|
886
1115
|
/**
|
|
887
|
-
* Creates a typed
|
|
1116
|
+
* Creates a typed database client with Prisma-style model delegates.
|
|
1117
|
+
*
|
|
1118
|
+
* Instead of `db.get('users', opts)`, use `db.users.get(opts)`.
|
|
1119
|
+
* Each model in the registry becomes a property on the returned client
|
|
1120
|
+
* with all CRUD methods typed for that specific model.
|
|
888
1121
|
*
|
|
889
1122
|
* Computes the tenant graph at creation time from d.tenant() metadata,
|
|
890
1123
|
* traversing references to find indirect tenant paths.
|
|
@@ -904,222 +1137,381 @@ interface DatabaseInstance<TTables extends Record<string, TableEntry>> {
|
|
|
904
1137
|
* idle connections are closed after 30 seconds. Set `idleTimeout` explicitly
|
|
905
1138
|
* to override (value in milliseconds, e.g., `60000` for 60s).
|
|
906
1139
|
*/
|
|
907
|
-
declare function createDb<
|
|
908
|
-
|
|
909
|
-
|
|
1140
|
+
declare function createDb<TModels extends Record<string, ModelEntry>>(options: CreateDbOptions<TModels>): DatabaseClient<TModels>;
|
|
1141
|
+
/**
|
|
1142
|
+
* Creates an EntityDbAdapter backed by a DatabaseClient for a specific table.
|
|
1143
|
+
*
|
|
1144
|
+
* Bridges the gap between the entity layer's simple adapter interface and the
|
|
1145
|
+
* query builder's rich, typed API. Unwraps Result<T, E> from the query builder
|
|
1146
|
+
* into the throw/return-null pattern expected by the entity pipeline.
|
|
1147
|
+
*/
|
|
1148
|
+
declare function createDatabaseBridgeAdapter<
|
|
1149
|
+
TModels extends Record<string, ModelEntry>,
|
|
1150
|
+
TName extends keyof TModels & string
|
|
1151
|
+
>(db: DatabaseClient<TModels>, tableName: TName): EntityDbAdapter;
|
|
1152
|
+
interface SqliteAdapterOptions<T extends ColumnRecord> {
|
|
1153
|
+
/** The table schema definition */
|
|
1154
|
+
schema: TableDef<T>;
|
|
1155
|
+
/** Path to the SQLite database file */
|
|
1156
|
+
dbPath?: string;
|
|
1157
|
+
/** Directory to store the database file (alternative to dbPath) */
|
|
1158
|
+
dataDir?: string;
|
|
1159
|
+
/** Auto-apply migrations on startup */
|
|
1160
|
+
migrations?: {
|
|
1161
|
+
autoApply?: boolean;
|
|
1162
|
+
};
|
|
910
1163
|
}
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
TName extends string,
|
|
936
|
-
const TValues extends readonly string[]
|
|
937
|
-
>(name: TName, values: TValues): ColumnBuilder<TValues[number], EnumMeta<TName, TValues>>;
|
|
938
|
-
enum<
|
|
939
|
-
TName extends string,
|
|
940
|
-
const TValues extends readonly [string, ...string[]]
|
|
941
|
-
>(name: TName, schema: EnumSchemaLike<TValues>): ColumnBuilder<TValues[number], EnumMeta<TName, TValues>>;
|
|
942
|
-
tenant(targetTable: TableDef<ColumnRecord>): ColumnBuilder<string, TenantMeta>;
|
|
943
|
-
table<TColumns extends ColumnRecord>(name: string, columns: TColumns, options?: TableOptions): TableDef<TColumns>;
|
|
944
|
-
index(columns: string | string[]): IndexDef;
|
|
945
|
-
ref: {
|
|
946
|
-
one<TTarget extends TableDef<ColumnRecord>>(target: () => TTarget, foreignKey: string): RelationDef<TTarget, "one">;
|
|
947
|
-
many<TTarget extends TableDef<ColumnRecord>>(target: () => TTarget, foreignKey: string): RelationDef<TTarget, "many">;
|
|
948
|
-
many<TTarget extends TableDef<ColumnRecord>>(target: () => TTarget): ManyRelationDef<TTarget>;
|
|
949
|
-
};
|
|
950
|
-
entry<TTable extends TableDef<ColumnRecord>>(table: TTable): TableEntry<TTable, {}>;
|
|
951
|
-
entry<
|
|
952
|
-
TTable extends TableDef<ColumnRecord>,
|
|
953
|
-
TRelations extends Record<string, RelationDef>
|
|
954
|
-
>(table: TTable, relations: TRelations): TableEntry<TTable, TRelations>;
|
|
955
|
-
};
|
|
956
|
-
interface DbErrorJson {
|
|
957
|
-
readonly error: string;
|
|
958
|
-
readonly code: string;
|
|
959
|
-
readonly message: string;
|
|
960
|
-
readonly table?: string;
|
|
961
|
-
readonly column?: string;
|
|
962
|
-
}
|
|
963
|
-
declare abstract class DbError extends Error {
|
|
964
|
-
abstract readonly code: string;
|
|
965
|
-
/** Raw PostgreSQL SQLSTATE code, if applicable. */
|
|
966
|
-
readonly pgCode?: string | undefined;
|
|
967
|
-
readonly table?: string | undefined;
|
|
968
|
-
readonly query?: string | undefined;
|
|
969
|
-
constructor(message: string);
|
|
970
|
-
toJSON(): DbErrorJson;
|
|
1164
|
+
/**
|
|
1165
|
+
* Create a SQLite driver using bun:sqlite or better-sqlite3.
|
|
1166
|
+
*/
|
|
1167
|
+
declare function createSqliteDriver2(dbPath: string): DbDriver;
|
|
1168
|
+
/**
|
|
1169
|
+
* Create a SQLite EntityDbAdapter from a schema.
|
|
1170
|
+
*/
|
|
1171
|
+
declare function createSqliteAdapter<T extends ColumnRecord>(options: SqliteAdapterOptions<T>): Promise<EntityDbAdapter>;
|
|
1172
|
+
import { Result as Result3 } from "@vertz/errors";
|
|
1173
|
+
import { MigrationError as MigrationError2 } from "@vertz/errors";
|
|
1174
|
+
/**
|
|
1175
|
+
* The query function type expected by the migration runner.
|
|
1176
|
+
*/
|
|
1177
|
+
type MigrationQueryFn = (sql: string, params: readonly unknown[]) => Promise<{
|
|
1178
|
+
rows: readonly Record<string, unknown>[];
|
|
1179
|
+
rowCount: number;
|
|
1180
|
+
}>;
|
|
1181
|
+
/**
|
|
1182
|
+
* Represents a migration file on disk.
|
|
1183
|
+
*/
|
|
1184
|
+
interface MigrationFile {
|
|
1185
|
+
name: string;
|
|
1186
|
+
sql: string;
|
|
1187
|
+
timestamp: number;
|
|
971
1188
|
}
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
1189
|
+
/**
|
|
1190
|
+
* Result of applying (or dry-running) a migration.
|
|
1191
|
+
*/
|
|
1192
|
+
interface ApplyResult {
|
|
1193
|
+
/** The migration name. */
|
|
1194
|
+
name: string;
|
|
1195
|
+
/** The SQL that was (or would be) executed. */
|
|
1196
|
+
sql: string;
|
|
1197
|
+
/** The computed checksum of the migration SQL. */
|
|
1198
|
+
checksum: string;
|
|
1199
|
+
/** Whether this was a dry run. */
|
|
1200
|
+
dryRun: boolean;
|
|
1201
|
+
/** The statements that were (or would be) executed, in order. */
|
|
1202
|
+
statements: string[];
|
|
977
1203
|
}
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
1204
|
+
/**
|
|
1205
|
+
* Parse a migration filename to extract its timestamp number.
|
|
1206
|
+
* Expected format: NNNN_description.sql
|
|
1207
|
+
*/
|
|
1208
|
+
declare function parseMigrationName(filename: string): {
|
|
1209
|
+
timestamp: number;
|
|
1210
|
+
name: string;
|
|
1211
|
+
} | null;
|
|
1212
|
+
interface ColumnSnapshot {
|
|
1213
|
+
type: string;
|
|
1214
|
+
nullable: boolean;
|
|
1215
|
+
primary: boolean;
|
|
1216
|
+
unique: boolean;
|
|
1217
|
+
default?: string;
|
|
1218
|
+
annotations?: string[];
|
|
987
1219
|
}
|
|
988
|
-
interface
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
readonly query?: string;
|
|
1220
|
+
interface IndexSnapshot {
|
|
1221
|
+
columns: string[];
|
|
1222
|
+
name?: string;
|
|
1223
|
+
unique?: boolean;
|
|
993
1224
|
}
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
readonly query: string | undefined;
|
|
999
|
-
readonly constraint: string;
|
|
1000
|
-
readonly detail: string | undefined;
|
|
1001
|
-
constructor(options: ForeignKeyErrorOptions);
|
|
1002
|
-
toJSON(): DbErrorJson;
|
|
1225
|
+
interface ForeignKeySnapshot {
|
|
1226
|
+
column: string;
|
|
1227
|
+
targetTable: string;
|
|
1228
|
+
targetColumn: string;
|
|
1003
1229
|
}
|
|
1004
|
-
interface
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1230
|
+
interface TableSnapshot {
|
|
1231
|
+
columns: Record<string, ColumnSnapshot>;
|
|
1232
|
+
indexes: IndexSnapshot[];
|
|
1233
|
+
foreignKeys: ForeignKeySnapshot[];
|
|
1234
|
+
_metadata: Record<string, unknown>;
|
|
1008
1235
|
}
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
readonly query: string | undefined;
|
|
1014
|
-
readonly column: string;
|
|
1015
|
-
constructor(options: NotNullErrorOptions);
|
|
1016
|
-
toJSON(): DbErrorJson;
|
|
1236
|
+
interface SchemaSnapshot {
|
|
1237
|
+
version: 1;
|
|
1238
|
+
tables: Record<string, TableSnapshot>;
|
|
1239
|
+
enums: Record<string, string[]>;
|
|
1017
1240
|
}
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1241
|
+
declare function createSnapshot(tables: TableDef<ColumnRecord>[]): SchemaSnapshot;
|
|
1242
|
+
type ChangeType = "table_added" | "table_removed" | "column_added" | "column_removed" | "column_altered" | "column_renamed" | "index_added" | "index_removed" | "enum_added" | "enum_removed" | "enum_altered";
|
|
1243
|
+
interface CollisionInfo {
|
|
1244
|
+
existingName: string;
|
|
1245
|
+
conflictingName: string;
|
|
1246
|
+
sequenceNumber: number;
|
|
1247
|
+
suggestedName: string;
|
|
1022
1248
|
}
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
readonly query: string | undefined;
|
|
1028
|
-
readonly constraint: string;
|
|
1029
|
-
constructor(options: CheckConstraintErrorOptions);
|
|
1030
|
-
toJSON(): DbErrorJson;
|
|
1249
|
+
interface BaselineOptions {
|
|
1250
|
+
queryFn: MigrationQueryFn;
|
|
1251
|
+
migrationFiles: MigrationFile[];
|
|
1252
|
+
dialect?: Dialect;
|
|
1031
1253
|
}
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
readonly table: string;
|
|
1035
|
-
readonly query: string | undefined;
|
|
1036
|
-
constructor(table: string, query?: string);
|
|
1037
|
-
toJSON(): DbErrorJson;
|
|
1254
|
+
interface BaselineResult {
|
|
1255
|
+
recorded: string[];
|
|
1038
1256
|
}
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1257
|
+
/**
|
|
1258
|
+
* Mark all existing migration files as applied without executing them.
|
|
1259
|
+
* Used when adopting vertz on a database that already has the schema.
|
|
1260
|
+
*/
|
|
1261
|
+
declare function baseline(options: BaselineOptions): Promise<Result3<BaselineResult, MigrationError2>>;
|
|
1262
|
+
import { Result as Result4 } from "@vertz/errors";
|
|
1263
|
+
interface MigrateDeployOptions {
|
|
1264
|
+
queryFn: MigrationQueryFn;
|
|
1265
|
+
migrationFiles: MigrationFile[];
|
|
1266
|
+
/** When true, return the SQL that would be executed without applying. */
|
|
1267
|
+
dryRun?: boolean;
|
|
1042
1268
|
}
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1269
|
+
interface MigrateDeployResult {
|
|
1270
|
+
applied: string[];
|
|
1271
|
+
alreadyApplied: string[];
|
|
1272
|
+
/** When dry-run is enabled, contains the details of each migration that would be applied. */
|
|
1273
|
+
dryRun: boolean;
|
|
1274
|
+
/** Detailed results for each migration that was (or would be) applied. */
|
|
1275
|
+
migrations?: ApplyResult[];
|
|
1046
1276
|
}
|
|
1047
1277
|
/**
|
|
1048
|
-
*
|
|
1278
|
+
* Apply all pending migrations in order.
|
|
1049
1279
|
*
|
|
1050
|
-
*
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1280
|
+
* In dry-run mode, returns the SQL that would be executed without modifying the database.
|
|
1281
|
+
*/
|
|
1282
|
+
declare function migrateDeploy(options: MigrateDeployOptions): Promise<Result4<MigrateDeployResult, MigrationError2>>;
|
|
1283
|
+
interface RenameSuggestion {
|
|
1284
|
+
table: string;
|
|
1285
|
+
oldColumn: string;
|
|
1286
|
+
newColumn: string;
|
|
1287
|
+
confidence: number;
|
|
1288
|
+
}
|
|
1289
|
+
interface MigrateDevOptions {
|
|
1290
|
+
queryFn: MigrationQueryFn;
|
|
1291
|
+
currentSnapshot: SchemaSnapshot;
|
|
1292
|
+
previousSnapshot: SchemaSnapshot;
|
|
1293
|
+
migrationName?: string;
|
|
1294
|
+
existingFiles: string[];
|
|
1295
|
+
migrationsDir: string;
|
|
1296
|
+
writeFile: (path: string, content: string) => Promise<void>;
|
|
1297
|
+
readFile?: (path: string) => Promise<string>;
|
|
1298
|
+
dryRun: boolean;
|
|
1299
|
+
}
|
|
1300
|
+
interface MigrateDevResult {
|
|
1301
|
+
migrationFile: string;
|
|
1302
|
+
sql: string;
|
|
1303
|
+
appliedAt?: Date;
|
|
1304
|
+
dryRun: boolean;
|
|
1305
|
+
renames?: RenameSuggestion[];
|
|
1306
|
+
collisions?: CollisionInfo[];
|
|
1307
|
+
snapshot: SchemaSnapshot;
|
|
1308
|
+
}
|
|
1309
|
+
/**
|
|
1310
|
+
* Generate a migration from schema diff, optionally apply it.
|
|
1057
1311
|
*
|
|
1058
|
-
*
|
|
1059
|
-
* ```ts
|
|
1060
|
-
* DbErrorCode.UNIQUE_VIOLATION // '23505'
|
|
1061
|
-
* ```
|
|
1312
|
+
* In dry-run mode, generates SQL and returns it WITHOUT applying or writing files.
|
|
1062
1313
|
*/
|
|
1063
|
-
declare
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
readonly CONNECTION_FAILURE: "08006";
|
|
1074
|
-
readonly NOT_FOUND: "NOT_FOUND";
|
|
1075
|
-
readonly CONNECTION_ERROR: "CONNECTION_ERROR";
|
|
1076
|
-
readonly POOL_EXHAUSTED: "POOL_EXHAUSTED";
|
|
1077
|
-
};
|
|
1078
|
-
/** Union of all semantic error code keys (e.g., `'UNIQUE_VIOLATION' | 'FOREIGN_KEY_VIOLATION' | ...`). */
|
|
1079
|
-
type DbErrorCodeName = keyof typeof DbErrorCode;
|
|
1080
|
-
/** Union of all raw PG error code values (e.g., `'23505' | '23503' | ...`). */
|
|
1081
|
-
type DbErrorCodeValue = (typeof DbErrorCode)[keyof typeof DbErrorCode];
|
|
1314
|
+
declare function migrateDev(options: MigrateDevOptions): Promise<MigrateDevResult>;
|
|
1315
|
+
interface PushOptions {
|
|
1316
|
+
queryFn: MigrationQueryFn;
|
|
1317
|
+
currentSnapshot: SchemaSnapshot;
|
|
1318
|
+
previousSnapshot: SchemaSnapshot;
|
|
1319
|
+
}
|
|
1320
|
+
interface PushResult {
|
|
1321
|
+
sql: string;
|
|
1322
|
+
tablesAffected: string[];
|
|
1323
|
+
}
|
|
1082
1324
|
/**
|
|
1083
|
-
*
|
|
1084
|
-
* Built at module load time from DbErrorCode.
|
|
1325
|
+
* Push schema changes directly to the database without creating a migration file.
|
|
1085
1326
|
*/
|
|
1086
|
-
declare
|
|
1327
|
+
declare function push(options: PushOptions): Promise<PushResult>;
|
|
1328
|
+
import { Result as Result5 } from "@vertz/errors";
|
|
1329
|
+
interface ResetOptions {
|
|
1330
|
+
queryFn: MigrationQueryFn;
|
|
1331
|
+
migrationFiles: MigrationFile[];
|
|
1332
|
+
dialect?: Dialect;
|
|
1333
|
+
}
|
|
1334
|
+
interface ResetResult {
|
|
1335
|
+
tablesDropped: string[];
|
|
1336
|
+
migrationsApplied: string[];
|
|
1337
|
+
}
|
|
1087
1338
|
/**
|
|
1088
|
-
*
|
|
1089
|
-
*
|
|
1339
|
+
* Drop all user tables and re-apply all migrations from scratch.
|
|
1340
|
+
* Development use only.
|
|
1090
1341
|
*/
|
|
1091
|
-
declare function
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1342
|
+
declare function reset(options: ResetOptions): Promise<Result5<ResetResult, MigrationError2>>;
|
|
1343
|
+
import { Result as Result6 } from "@vertz/errors";
|
|
1344
|
+
interface MigrateStatusOptions {
|
|
1345
|
+
queryFn: MigrationQueryFn;
|
|
1346
|
+
migrationFiles: MigrationFile[];
|
|
1347
|
+
currentSnapshot?: SchemaSnapshot;
|
|
1348
|
+
savedSnapshot?: SchemaSnapshot;
|
|
1349
|
+
dialect?: Dialect;
|
|
1350
|
+
}
|
|
1351
|
+
interface MigrationInfo {
|
|
1352
|
+
name: string;
|
|
1353
|
+
checksum: string;
|
|
1354
|
+
appliedAt: Date;
|
|
1355
|
+
}
|
|
1356
|
+
interface CodeChange {
|
|
1357
|
+
description: string;
|
|
1358
|
+
type: ChangeType;
|
|
1359
|
+
table?: string;
|
|
1360
|
+
column?: string;
|
|
1361
|
+
}
|
|
1362
|
+
interface DriftEntry {
|
|
1363
|
+
description: string;
|
|
1364
|
+
type: "extra_table" | "missing_table" | "extra_column" | "missing_column" | "column_type_mismatch";
|
|
1365
|
+
table: string;
|
|
1366
|
+
column?: string;
|
|
1095
1367
|
}
|
|
1368
|
+
interface MigrateStatusResult {
|
|
1369
|
+
applied: MigrationInfo[];
|
|
1370
|
+
pending: string[];
|
|
1371
|
+
codeChanges: CodeChange[];
|
|
1372
|
+
drift: DriftEntry[];
|
|
1373
|
+
}
|
|
1374
|
+
declare function detectSchemaDrift(expected: SchemaSnapshot, actual: SchemaSnapshot): DriftEntry[];
|
|
1096
1375
|
/**
|
|
1097
|
-
*
|
|
1376
|
+
* Report the status of migrations: which are applied and which are pending.
|
|
1377
|
+
* Optionally detects code changes and database drift.
|
|
1378
|
+
*/
|
|
1379
|
+
declare function migrateStatus(options: MigrateStatusOptions): Promise<Result6<MigrateStatusResult, MigrationError2>>;
|
|
1380
|
+
interface PostgresDriver extends DbDriver {
|
|
1381
|
+
/** The QueryFn adapter for use with createDb. */
|
|
1382
|
+
readonly queryFn: QueryFn;
|
|
1383
|
+
/** Check connection health with SELECT 1. */
|
|
1384
|
+
isHealthy(): Promise<boolean>;
|
|
1385
|
+
}
|
|
1386
|
+
/**
|
|
1387
|
+
* Create a PostgreSQL driver from a connection URL and optional pool config.
|
|
1098
1388
|
*
|
|
1099
|
-
*
|
|
1100
|
-
*
|
|
1101
|
-
*
|
|
1102
|
-
* -
|
|
1103
|
-
* -
|
|
1104
|
-
*
|
|
1105
|
-
* - Unknown DbError -> 500 Internal Server Error
|
|
1389
|
+
* Note: Query routing (to replicas) is handled at the database.ts layer (createDb).
|
|
1390
|
+
* This driver provides a simple connection to a single PostgreSQL instance.
|
|
1391
|
+
*
|
|
1392
|
+
* @param url - PostgreSQL connection URL (e.g., postgres://user:pass@host:5432/db)
|
|
1393
|
+
* @param pool - Optional pool configuration
|
|
1394
|
+
* @returns A PostgresDriver with queryFn, close(), and isHealthy()
|
|
1106
1395
|
*/
|
|
1107
|
-
declare function
|
|
1108
|
-
interface
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1396
|
+
declare function createPostgresDriver(url: string, pool?: PoolConfig): PostgresDriver;
|
|
1397
|
+
interface SchemaLike<T> {
|
|
1398
|
+
parse(value: unknown): {
|
|
1399
|
+
ok: true;
|
|
1400
|
+
data: T;
|
|
1401
|
+
} | {
|
|
1402
|
+
ok: false;
|
|
1403
|
+
error: Error;
|
|
1404
|
+
};
|
|
1405
|
+
}
|
|
1406
|
+
interface ModelSchemas<TTable extends TableDef<ColumnRecord>> {
|
|
1407
|
+
readonly response: SchemaLike<TTable["$response"]>;
|
|
1408
|
+
readonly createInput: SchemaLike<TTable["$create_input"]>;
|
|
1409
|
+
readonly updateInput: SchemaLike<TTable["$update_input"]>;
|
|
1410
|
+
}
|
|
1411
|
+
interface ModelDef<
|
|
1412
|
+
TTable extends TableDef<ColumnRecord> = TableDef<ColumnRecord>,
|
|
1413
|
+
TRelations extends Record<string, RelationDef> = {}
|
|
1414
|
+
> {
|
|
1415
|
+
readonly table: TTable;
|
|
1416
|
+
readonly relations: TRelations;
|
|
1417
|
+
readonly schemas: ModelSchemas<TTable>;
|
|
1418
|
+
}
|
|
1419
|
+
interface EnumSchemaLike<T extends readonly string[]> {
|
|
1420
|
+
readonly values: T;
|
|
1115
1421
|
}
|
|
1422
|
+
declare const d: {
|
|
1423
|
+
uuid(): ColumnBuilder<string, DefaultMeta<"uuid">>;
|
|
1424
|
+
text(): ColumnBuilder<string, DefaultMeta<"text">>;
|
|
1425
|
+
varchar<TLength extends number>(length: TLength): ColumnBuilder<string, VarcharMeta<TLength>>;
|
|
1426
|
+
email(): ColumnBuilder<string, FormatMeta<"text", "email">>;
|
|
1427
|
+
boolean(): ColumnBuilder<boolean, DefaultMeta<"boolean">>;
|
|
1428
|
+
integer(): ColumnBuilder<number, DefaultMeta<"integer">>;
|
|
1429
|
+
bigint(): ColumnBuilder<bigint, DefaultMeta<"bigint">>;
|
|
1430
|
+
decimal<
|
|
1431
|
+
TPrecision extends number,
|
|
1432
|
+
TScale extends number
|
|
1433
|
+
>(precision: TPrecision, scale: TScale): ColumnBuilder<string, DecimalMeta<TPrecision, TScale>>;
|
|
1434
|
+
real(): ColumnBuilder<number, DefaultMeta<"real">>;
|
|
1435
|
+
doublePrecision(): ColumnBuilder<number, DefaultMeta<"double precision">>;
|
|
1436
|
+
serial(): ColumnBuilder<number, SerialMeta>;
|
|
1437
|
+
timestamp(): ColumnBuilder<Date, DefaultMeta<"timestamp with time zone">>;
|
|
1438
|
+
date(): ColumnBuilder<string, DefaultMeta<"date">>;
|
|
1439
|
+
time(): ColumnBuilder<string, DefaultMeta<"time">>;
|
|
1440
|
+
jsonb<T = unknown>(schemaOrOpts?: SchemaLike<T> | {
|
|
1441
|
+
validator: JsonbValidator<T>;
|
|
1442
|
+
}): ColumnBuilder<T, DefaultMeta<"jsonb">>;
|
|
1443
|
+
textArray(): ColumnBuilder<string[], DefaultMeta<"text[]">>;
|
|
1444
|
+
integerArray(): ColumnBuilder<number[], DefaultMeta<"integer[]">>;
|
|
1445
|
+
enum<
|
|
1446
|
+
TName extends string,
|
|
1447
|
+
const TValues extends readonly string[]
|
|
1448
|
+
>(name: TName, values: TValues): ColumnBuilder<TValues[number], EnumMeta<TName, TValues>>;
|
|
1449
|
+
enum<
|
|
1450
|
+
TName extends string,
|
|
1451
|
+
const TValues extends readonly [string, ...string[]]
|
|
1452
|
+
>(name: TName, schema: EnumSchemaLike<TValues>): ColumnBuilder<TValues[number], EnumMeta<TName, TValues>>;
|
|
1453
|
+
tenant(targetTable: TableDef<ColumnRecord>): ColumnBuilder<string, TenantMeta>;
|
|
1454
|
+
table<TColumns extends ColumnRecord>(name: string, columns: TColumns, options?: TableOptions): TableDef<TColumns>;
|
|
1455
|
+
index(columns: string | string[]): IndexDef;
|
|
1456
|
+
ref: {
|
|
1457
|
+
one<TTarget extends TableDef<ColumnRecord>>(target: () => TTarget, foreignKey: string): RelationDef<TTarget, "one">;
|
|
1458
|
+
many<TTarget extends TableDef<ColumnRecord>>(target: () => TTarget, foreignKey: string): RelationDef<TTarget, "many">;
|
|
1459
|
+
many<TTarget extends TableDef<ColumnRecord>>(target: () => TTarget): ManyRelationDef<TTarget>;
|
|
1460
|
+
};
|
|
1461
|
+
entry<TTable extends TableDef<ColumnRecord>>(table: TTable): ModelEntry<TTable, {}>;
|
|
1462
|
+
entry<
|
|
1463
|
+
TTable extends TableDef<ColumnRecord>,
|
|
1464
|
+
TRelations extends Record<string, RelationDef>
|
|
1465
|
+
>(table: TTable, relations: TRelations): ModelEntry<TTable, TRelations>;
|
|
1466
|
+
model<TTable extends TableDef<ColumnRecord>>(table: TTable): ModelDef<TTable, {}>;
|
|
1467
|
+
model<
|
|
1468
|
+
TTable extends TableDef<ColumnRecord>,
|
|
1469
|
+
TRelations extends Record<string, RelationDef>
|
|
1470
|
+
>(table: TTable, relations: TRelations): ModelDef<TTable, TRelations>;
|
|
1471
|
+
};
|
|
1116
1472
|
/**
|
|
1117
|
-
*
|
|
1473
|
+
* Convenience utility for creating a frozen bag of annotation constants.
|
|
1118
1474
|
*
|
|
1119
|
-
*
|
|
1120
|
-
*
|
|
1475
|
+
* Usage:
|
|
1476
|
+
* ```typescript
|
|
1477
|
+
* const Annotation = defineAnnotations('sensitive', 'hidden', 'patchable');
|
|
1478
|
+
* // typeof Annotation = { readonly sensitive: 'sensitive'; readonly hidden: 'hidden'; readonly patchable: 'patchable' }
|
|
1479
|
+
*
|
|
1480
|
+
* d.text().is(Annotation.hidden);
|
|
1481
|
+
* ```
|
|
1121
1482
|
*/
|
|
1122
|
-
declare function
|
|
1483
|
+
declare function defineAnnotations<const T extends readonly string[]>(...annotations: T): { readonly [K in T[number]] : K };
|
|
1484
|
+
/**
|
|
1485
|
+
* Shared enum registry — define enums once, reuse across tables.
|
|
1486
|
+
*
|
|
1487
|
+
* @example
|
|
1488
|
+
* ```ts
|
|
1489
|
+
* const enums = createEnumRegistry({
|
|
1490
|
+
* status: ['active', 'inactive', 'pending'],
|
|
1491
|
+
* role: ['admin', 'editor', 'viewer'],
|
|
1492
|
+
* } as const);
|
|
1493
|
+
*
|
|
1494
|
+
* const orders = d.table('orders', {
|
|
1495
|
+
* status: d.enum('status', enums.status),
|
|
1496
|
+
* });
|
|
1497
|
+
* const users = d.table('users', {
|
|
1498
|
+
* role: d.enum('role', enums.role),
|
|
1499
|
+
* });
|
|
1500
|
+
* ```
|
|
1501
|
+
*/
|
|
1502
|
+
/** A registered enum entry with name and values accessible for d.enum(). */
|
|
1503
|
+
interface RegisteredEnum<TValues extends readonly string[]> {
|
|
1504
|
+
/** The enum name (same as the registry key). */
|
|
1505
|
+
readonly name: string;
|
|
1506
|
+
/** The enum values — compatible with d.enum()'s EnumSchemaLike interface. */
|
|
1507
|
+
readonly values: TValues;
|
|
1508
|
+
}
|
|
1509
|
+
type EnumRegistry<T extends Record<string, readonly string[]>> = { readonly [K in keyof T] : RegisteredEnum<T[K]> };
|
|
1510
|
+
/**
|
|
1511
|
+
* Creates a shared enum registry from a map of enum names to their values.
|
|
1512
|
+
* The returned object can be passed directly to `d.enum(name, enums.myEnum)`.
|
|
1513
|
+
*/
|
|
1514
|
+
declare function createEnumRegistry<T extends Record<string, readonly string[]>>(definitions: T): EnumRegistry<T>;
|
|
1123
1515
|
/**
|
|
1124
1516
|
* Extracts the string column keys from a TableDef's _columns record.
|
|
1125
1517
|
* Used to constrain FK arguments at the type level.
|
|
@@ -1132,34 +1524,34 @@ type ColumnKeys<T extends TableDef<ColumnRecord>> = T extends TableDef<infer C>
|
|
|
1132
1524
|
* - `many()` validates: target name is a registry key, FK is a column of the TARGET table
|
|
1133
1525
|
*/
|
|
1134
1526
|
interface TypedRef<
|
|
1135
|
-
|
|
1527
|
+
TModels extends Record<string, TableDef<ColumnRecord>>,
|
|
1136
1528
|
TSourceTable extends TableDef<ColumnRecord>
|
|
1137
1529
|
> {
|
|
1138
1530
|
/** belongsTo — FK lives on the source table */
|
|
1139
1531
|
one<
|
|
1140
|
-
TTargetName extends Extract<keyof
|
|
1532
|
+
TTargetName extends Extract<keyof TModels, string>,
|
|
1141
1533
|
TFK extends ColumnKeys<TSourceTable>
|
|
1142
|
-
>(target: TTargetName, foreignKey: TFK): RelationDef<
|
|
1534
|
+
>(target: TTargetName, foreignKey: TFK): RelationDef<TModels[TTargetName], "one">;
|
|
1143
1535
|
/** hasMany — FK lives on the target table */
|
|
1144
1536
|
many<
|
|
1145
|
-
TTargetName extends Extract<keyof
|
|
1146
|
-
TFK extends ColumnKeys<
|
|
1147
|
-
>(target: TTargetName, foreignKey: TFK): RelationDef<
|
|
1537
|
+
TTargetName extends Extract<keyof TModels, string>,
|
|
1538
|
+
TFK extends ColumnKeys<TModels[TTargetName]>
|
|
1539
|
+
>(target: TTargetName, foreignKey: TFK): RelationDef<TModels[TTargetName], "many">;
|
|
1148
1540
|
}
|
|
1149
1541
|
/**
|
|
1150
1542
|
* An object keyed by table name where each value is a TypedRef scoped
|
|
1151
1543
|
* to that table as the source. This enables `ref.posts.one('users', 'authorId')`
|
|
1152
1544
|
* where TypeScript knows 'authorId' must be a column of `posts`.
|
|
1153
1545
|
*/
|
|
1154
|
-
type PerTableRefFactory<
|
|
1546
|
+
type PerTableRefFactory<TModels extends Record<string, TableDef<ColumnRecord>>> = { [K in Extract<keyof TModels, string>] : TypedRef<TModels, TModels[K]> };
|
|
1155
1547
|
/**
|
|
1156
|
-
* Maps each table key to a
|
|
1548
|
+
* Maps each table key to a ModelEntry, merging the table with its relations
|
|
1157
1549
|
* from the callback (or empty relations if the table was omitted).
|
|
1158
1550
|
*/
|
|
1159
1551
|
type RegistryOutput<
|
|
1160
|
-
|
|
1161
|
-
TRelMap extends { [K in keyof
|
|
1162
|
-
> = { [K in keyof
|
|
1552
|
+
TModels extends Record<string, TableDef<ColumnRecord>>,
|
|
1553
|
+
TRelMap extends { [K in keyof TModels]? : Record<string, RelationDef> }
|
|
1554
|
+
> = { [K in keyof TModels] : ModelEntry<TModels[K], K extends keyof TRelMap ? TRelMap[K] extends Record<string, RelationDef> ? TRelMap[K] : {} : {}> };
|
|
1163
1555
|
/**
|
|
1164
1556
|
* Creates a typed table registry with compile-time validated relations.
|
|
1165
1557
|
*
|
|
@@ -1170,7 +1562,7 @@ type RegistryOutput<
|
|
|
1170
1562
|
*
|
|
1171
1563
|
* @example
|
|
1172
1564
|
* ```typescript
|
|
1173
|
-
* const
|
|
1565
|
+
* const models = createRegistry(
|
|
1174
1566
|
* { users, posts, comments },
|
|
1175
1567
|
* (ref) => ({
|
|
1176
1568
|
* posts: {
|
|
@@ -1186,40 +1578,9 @@ type RegistryOutput<
|
|
|
1186
1578
|
* ```
|
|
1187
1579
|
*/
|
|
1188
1580
|
declare function createRegistry<
|
|
1189
|
-
|
|
1190
|
-
TRelMap extends { [K in keyof
|
|
1191
|
-
>(tables:
|
|
1192
|
-
/**
|
|
1193
|
-
* Shared enum registry — define enums once, reuse across tables.
|
|
1194
|
-
*
|
|
1195
|
-
* @example
|
|
1196
|
-
* ```ts
|
|
1197
|
-
* const enums = createEnumRegistry({
|
|
1198
|
-
* status: ['active', 'inactive', 'pending'],
|
|
1199
|
-
* role: ['admin', 'editor', 'viewer'],
|
|
1200
|
-
* } as const);
|
|
1201
|
-
*
|
|
1202
|
-
* const orders = d.table('orders', {
|
|
1203
|
-
* status: d.enum('status', enums.status),
|
|
1204
|
-
* });
|
|
1205
|
-
* const users = d.table('users', {
|
|
1206
|
-
* role: d.enum('role', enums.role),
|
|
1207
|
-
* });
|
|
1208
|
-
* ```
|
|
1209
|
-
*/
|
|
1210
|
-
/** A registered enum entry with name and values accessible for d.enum(). */
|
|
1211
|
-
interface RegisteredEnum<TValues extends readonly string[]> {
|
|
1212
|
-
/** The enum name (same as the registry key). */
|
|
1213
|
-
readonly name: string;
|
|
1214
|
-
/** The enum values — compatible with d.enum()'s EnumSchemaLike interface. */
|
|
1215
|
-
readonly values: TValues;
|
|
1216
|
-
}
|
|
1217
|
-
type EnumRegistry<T extends Record<string, readonly string[]>> = { readonly [K in keyof T] : RegisteredEnum<T[K]> };
|
|
1218
|
-
/**
|
|
1219
|
-
* Creates a shared enum registry from a map of enum names to their values.
|
|
1220
|
-
* The returned object can be passed directly to `d.enum(name, enums.myEnum)`.
|
|
1221
|
-
*/
|
|
1222
|
-
declare function createEnumRegistry<T extends Record<string, readonly string[]>>(definitions: T): EnumRegistry<T>;
|
|
1581
|
+
TModels extends Record<string, TableDef<ColumnRecord>>,
|
|
1582
|
+
TRelMap extends { [K in keyof TModels]? : Record<string, RelationDef> }
|
|
1583
|
+
>(tables: TModels, relationsCallback: (ref: PerTableRefFactory<TModels>) => TRelMap): RegistryOutput<TModels, TRelMap>;
|
|
1223
1584
|
/**
|
|
1224
1585
|
* Branded error types for readable compiler messages.
|
|
1225
1586
|
*
|
|
@@ -1288,59 +1649,4 @@ type StrictKeys<
|
|
|
1288
1649
|
TAllowed extends string,
|
|
1289
1650
|
TTable extends string
|
|
1290
1651
|
> = TRecord extends Record<string, unknown> ? { [K in keyof TRecord] : K extends TAllowed ? TRecord[K] : InvalidColumn<K & string, TTable> } : TRecord;
|
|
1291
|
-
|
|
1292
|
-
* Type generation for DB client codegen.
|
|
1293
|
-
*
|
|
1294
|
-
* This module generates TypeScript types from domain definitions.
|
|
1295
|
-
*/
|
|
1296
|
-
interface DomainField {
|
|
1297
|
-
type: "string" | "number" | "boolean" | "date" | "json" | "uuid" | "enum";
|
|
1298
|
-
primary?: boolean;
|
|
1299
|
-
required?: boolean;
|
|
1300
|
-
references?: string;
|
|
1301
|
-
enumName?: string;
|
|
1302
|
-
enumValues?: string[];
|
|
1303
|
-
}
|
|
1304
|
-
interface DomainRelation {
|
|
1305
|
-
type: "belongsTo" | "hasMany";
|
|
1306
|
-
target: string;
|
|
1307
|
-
foreignKey: string;
|
|
1308
|
-
}
|
|
1309
|
-
interface DomainDefinition {
|
|
1310
|
-
name: string;
|
|
1311
|
-
fields: Record<string, DomainField>;
|
|
1312
|
-
relations?: Record<string, DomainRelation>;
|
|
1313
|
-
}
|
|
1314
|
-
/**
|
|
1315
|
-
* Generate TypeScript types from a domain definition.
|
|
1316
|
-
* This function should generate:
|
|
1317
|
-
* - Entity interface (e.g., interface User { ... })
|
|
1318
|
-
* - Create input type (required fields only)
|
|
1319
|
-
* - Update input type (all fields optional)
|
|
1320
|
-
* - Where/filter type
|
|
1321
|
-
* - OrderBy type
|
|
1322
|
-
* - CRUD method signatures
|
|
1323
|
-
*/
|
|
1324
|
-
declare function generateTypes(domain: DomainDefinition): string;
|
|
1325
|
-
/**
|
|
1326
|
-
* Generate the typed database client from domain definitions.
|
|
1327
|
-
* This function should generate:
|
|
1328
|
-
* - A db object with entity accessors
|
|
1329
|
-
* - Each entity has: list, get, create, update, delete methods
|
|
1330
|
-
* - Typed filter/where parameters
|
|
1331
|
-
* - Relation accessors
|
|
1332
|
-
*/
|
|
1333
|
-
declare function generateClient(domains: DomainDefinition[]): string;
|
|
1334
|
-
/**
|
|
1335
|
-
* Define a domain for DB client codegen.
|
|
1336
|
-
* This creates a domain definition that can be used to generate types and client.
|
|
1337
|
-
*/
|
|
1338
|
-
declare function defineDomain(name: string, config: {
|
|
1339
|
-
fields: Record<string, Omit<DomainField, "type"> & {
|
|
1340
|
-
type: DomainField["type"];
|
|
1341
|
-
}>;
|
|
1342
|
-
relations?: Record<string, Omit<DomainRelation, "type"> & {
|
|
1343
|
-
type: DomainRelation["type"];
|
|
1344
|
-
}>;
|
|
1345
|
-
}): DomainDefinition;
|
|
1346
|
-
export { resolveErrorCode, push, parsePgError, migrateStatus, migrateDev, migrateDeploy, generateTypes, generateClient, formatDiagnostic, explainError, diagnoseError, defineDomain, dbErrorToHttpError, d, createRegistry, createEnumRegistry, createDb, computeTenantGraph, VarcharMeta, ValidateKeys, UpdateInput, UniqueConstraintErrorOptions, UniqueConstraintError, TenantMeta, TenantGraph, TableEntry, TableDef, StrictKeys, SelectOption, SelectNarrow, RenameSuggestion, RelationDef, RegisteredEnum, QueryResult, PushResult, PushOptions, PoolConfig, PgErrorInput, PgCodeToName, OrderByType, NotNullErrorOptions, NotNullError, NotFoundError, MixedSelectError, MigrationInfo, MigrateStatusResult, MigrateStatusOptions, MigrateDevResult, MigrateDevOptions, MigrateDeployResult, MigrateDeployOptions, JsonbValidator, InvalidRelation, InvalidFilterType, InvalidColumn, InsertInput, InferColumnType, IndexDef, IncludeResolve, IncludeOption, HttpErrorResponse, FormatMeta, ForeignKeyErrorOptions, ForeignKeyError, FindResult, FindOptions, FilterType, EnumMeta, DomainRelation, DomainField, DomainDefinition, DiagnosticResult, DecimalMeta, DbErrorJson, DbErrorCodeValue, DbErrorCodeName, DbErrorCode, DbError, DatabaseInstance, Database, CreateDbOptions, ConnectionPoolExhaustedError, ConnectionError, ColumnMetadata, ColumnBuilder, CheckConstraintErrorOptions, CheckConstraintError };
|
|
1652
|
+
export { toWriteError, toReadError, resolveErrorCode, reset, push, parsePgError, parseMigrationName, migrateStatus, migrateDev, migrateDeploy, generateId, formatDiagnostic, explainError, diagnoseError, detectSchemaDrift, defineAnnotations, defaultSqliteDialect, defaultPostgresDialect, dbErrorToHttpError, d, createSqliteDriver2 as createSqliteDriver, createSqliteAdapter, createSnapshot, createRegistry, createPostgresDriver, createEnumRegistry, createDb, createDatabaseBridgeAdapter, createD1Driver, createD1Adapter, computeTenantGraph, baseline, WriteError, VarcharMeta, ValidateKeys, UpdateInput, UniqueConstraintErrorOptions, UniqueConstraintError, TenantMeta, TenantGraph, TableDef, StrictKeys, SqliteDialect, SqliteAdapterOptions, SelectOption, SelectNarrow, SchemaSnapshot, SchemaLike, ResetResult, ResetOptions, RenameSuggestion, RelationDef, RegisteredEnum, ReadError, QueryResult, PushResult, PushOptions, PostgresDriver, PostgresDialect, PoolConfig, PgErrorInput, PgCodeToName, OrderByType, NotNullErrorOptions, NotNullError, NotFoundError, ModelSchemas, ModelEntry, ModelDelegate, ModelDef, MixedSelectError, MigrationQueryFn, MigrationInfo, MigrationFile, MigrationError2 as MigrationError, MigrateStatusResult, MigrateStatusOptions, MigrateDevResult, MigrateDevOptions, MigrateDeployResult, MigrateDeployOptions, ListOptions, JsonbValidator, InvalidRelation, InvalidFilterType, InvalidColumn, InsertInput, InferColumnType, IndexDef, IncludeResolve, IncludeOption, HttpErrorResponse, FormatMeta, ForeignKeyErrorOptions, ForeignKeyError, FindResult, FindOptions, FilterType, EnumMeta, EntityDbAdapter, DriftEntry, Dialect, DiagnosticResult, DecimalMeta, DbQueryError, DbNotFoundError, DbErrorJson, DbErrorCodeValue, DbErrorCodeName, DbErrorCode, DbErrorBase, DbError, DbDriver, DbConstraintError, DbConnectionError, DatabaseInternals, DatabaseClient, Database, D1PreparedStatement, D1DatabaseBinding, D1AdapterOptions, CreateDbOptions, ConnectionPoolExhaustedError, ConnectionError, ColumnTypeMeta, ColumnMetadata, ColumnBuilder, CodeChange, CheckConstraintErrorOptions, CheckConstraintError, BaselineResult, BaselineOptions };
|