@vertz/db 0.2.0 → 0.2.1

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/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 sensitive: boolean;
51
- readonly hidden: boolean;
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(): ColumnBuilder<TType, Omit<TMeta, "primary" | "hasDefault"> & {
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
- sensitive(): ColumnBuilder<TType, Omit<TMeta, "sensitive"> & {
91
- readonly sensitive: true;
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
- hidden(): ColumnBuilder<TType, Omit<TMeta, "hidden"> & {
94
- readonly hidden: true;
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 sensitive: false;
114
- readonly hidden: false;
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 sensitive: false;
153
- readonly hidden: false;
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 sensitive: false;
165
- readonly hidden: false;
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 flag is `true`. */
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 flag is NOT `true` (i.e., false). */
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 columns. Includes everything else (including sensitive).
252
+ * Excludes columns annotated 'hidden'. Includes everything else.
210
253
  */
211
- type Infer<T extends ColumnRecord> = { [K in ColumnKeysWhereNot<T, "hidden">] : InferColumnType<T[K]> };
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
- * $not_sensitive -- excludes columns marked .sensitive() OR .hidden().
228
- * (hidden implies sensitive for read purposes)
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 NotSensitive<T extends ColumnRecord> = { [K in ColumnKeysWhereNot<T, "sensitive"> & ColumnKeysWhereNot<T, "hidden"> & keyof T] : InferColumnType<T[K]> };
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
- * $not_hidden -- excludes columns marked .hidden().
233
- * Same as $infer (excludes hidden, keeps sensitive).
280
+ * $update_input -- API update input shape.
281
+ * Excludes readOnly and primary key columns. All fields optional (partial update).
234
282
  */
235
- type NotHidden<T extends ColumnRecord> = { [K in ColumnKeysWhereNot<T, "hidden">] : InferColumnType<T[K]> };
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 columns. */
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
- /** Excludes sensitive and hidden columns. */
250
- readonly $not_sensitive: NotSensitive<TColumns>;
251
- /** Excludes hidden columns. */
252
- readonly $not_hidden: NotHidden<TColumns>;
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
- interface ColumnSnapshot {
261
- type: string;
262
- nullable: boolean;
263
- primary: boolean;
264
- unique: boolean;
265
- default?: string;
266
- sensitive?: boolean;
267
- hidden?: boolean;
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 IndexSnapshot {
270
- columns: string[];
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 ForeignKeySnapshot {
273
- column: string;
274
- targetTable: string;
275
- targetColumn: string;
333
+ interface D1DatabaseBinding {
334
+ prepare(sql: string): D1PreparedStatement;
276
335
  }
277
- interface TableSnapshot {
278
- columns: Record<string, ColumnSnapshot>;
279
- indexes: IndexSnapshot[];
280
- foreignKeys: ForeignKeySnapshot[];
281
- _metadata: Record<string, unknown>;
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 SchemaSnapshot {
284
- version: 1;
285
- tables: Record<string, TableSnapshot>;
286
- enums: Record<string, string[]>;
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
- * The query function type expected by the migration runner.
362
+ * Create a DbDriver from a D1 database binding.
290
363
  */
291
- type MigrationQueryFn = (sql: string, params: readonly unknown[]) => Promise<{
292
- rows: readonly Record<string, unknown>[];
293
- rowCount: number;
294
- }>;
364
+ declare function createD1Driver(d1: D1DatabaseBinding): DbDriver;
295
365
  /**
296
- * Represents a migration file on disk.
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
- interface MigrationFile {
299
- name: string;
300
- sql: string;
301
- timestamp: number;
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
- * Result of applying (or dry-running) a migration.
407
+ * PostgreSQL dialect implementation.
408
+ *
409
+ * Extracted from existing behavior — no functional changes.
305
410
  */
306
- interface ApplyResult {
307
- /** The migration name. */
308
- name: string;
309
- /** The SQL that was (or would be) executed. */
310
- sql: string;
311
- /** The computed checksum of the migration SQL. */
312
- checksum: string;
313
- /** Whether this was a dry run. */
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
- * Apply all pending migrations in order.
423
+ * SQLite dialect implementation.
334
424
  *
335
- * In dry-run mode, returns the SQL that would be executed without modifying the database.
425
+ * SQLite 3.35+ supports RETURNING clause.
336
426
  */
337
- declare function migrateDeploy(options: MigrateDeployOptions): Promise<MigrateDeployResult>;
338
- interface RenameSuggestion {
339
- table: string;
340
- oldColumn: string;
341
- newColumn: string;
342
- confidence: number;
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
- interface MigrateDevOptions {
345
- queryFn: MigrationQueryFn;
346
- currentSnapshot: SchemaSnapshot;
347
- previousSnapshot: SchemaSnapshot;
348
- migrationName: string;
349
- existingFiles: string[];
350
- migrationsDir: string;
351
- writeFile: (path: string, content: string) => Promise<void>;
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
- interface MigrateDevResult {
355
- migrationFile: string;
356
- sql: string;
357
- appliedAt?: Date;
358
- dryRun: boolean;
359
- renames?: RenameSuggestion[];
360
- snapshot: SchemaSnapshot;
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
- * Generate a migration from schema diff, optionally apply it.
364
- *
365
- * In dry-run mode, generates SQL and returns it WITHOUT applying or writing files.
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
- interface PushResult {
374
- sql: string;
375
- tablesAffected: string[];
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
- * Push schema changes directly to the database without creating a migration file.
379
- */
380
- declare function push(options: PushOptions): Promise<PushResult>;
381
- interface MigrateStatusOptions {
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
- interface MigrationInfo {
386
- name: string;
387
- checksum: string;
388
- appliedAt: Date;
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 MigrateStatusResult {
391
- applied: MigrationInfo[];
392
- pending: string[];
486
+ interface NotNullErrorOptions {
487
+ readonly table: string;
488
+ readonly column: string;
489
+ readonly query?: string;
393
490
  }
394
- /**
395
- * Report the status of migrations: which are applied and which are pending.
396
- */
397
- declare function migrateStatus(options: MigrateStatusOptions): Promise<MigrateStatusResult>;
398
- /**
399
- * Query executor — wraps raw SQL execution with error mapping.
400
- *
401
- * Takes a query function (from the database driver) and wraps it to:
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
- type QueryFn = <T>(sql: string, params: readonly unknown[]) => Promise<ExecutorResult<T>>;
411
- /** Operators available for comparable types (number, string, Date, bigint). */
412
- interface ComparisonOperators<T> {
413
- readonly eq?: T;
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
- /** Additional operators for string columns. */
423
- interface StringOperators {
424
- readonly contains?: string;
425
- readonly startsWith?: string;
426
- readonly endsWith?: string;
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
- /** The `isNull` operator only available for nullable columns. */
429
- interface NullOperator {
430
- readonly isNull?: boolean;
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
- * Resolves the filter operators for a single column based on its inferred type
434
- * and nullable metadata.
435
- *
436
- * - All types get comparison + in/notIn
437
- * - String types additionally get contains, startsWith, endsWith
438
- * - Nullable columns additionally get isNull
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: 'sensitive' | 'hidden' }` — exclude columns by visibility category
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: "sensitive" | "hidden";
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: 'hidden' }` → excludes hidden columns
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: "sensitive";
497
- } ? { [K in ColumnKeysWhereNot2<TColumns, "sensitive"> & ColumnKeysWhereNot2<TColumns, "hidden"> & keyof TColumns] : InferColumnType<TColumns[K]> } : TSelect extends {
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 table entry in the database registry, pairing a table with its relations. */
578
- interface TableEntry<
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<TTables> — type that carries the full table registry.
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<TTables extends Record<string, TableEntry> = Record<string, TableEntry>> {
592
- readonly _tables: TTables;
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<TTables extends Record<string, TableEntry>> {
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: string;
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 TableEntry. */
694
- type EntryTable<TEntry extends TableEntry> = TEntry["table"];
695
- /** Extract the relations record from a TableEntry. */
696
- type EntryRelations<TEntry extends TableEntry> = TEntry["relations"];
697
- /** Extract columns from a TableEntry's table. */
698
- type EntryColumns<TEntry extends TableEntry> = EntryTable<TEntry>["_columns"];
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 TableEntry> = {
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 TableEntry> = {
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 TableEntry> = {
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 TableEntry> = {
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 TableEntry> = {
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 TableEntry> = {
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 TableEntry> = {
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 TableEntry> = {
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 TableEntry> = {
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 TableEntry> = {
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 TableEntry> = {
1053
+ type TypedCountOptions<TEntry extends ModelEntry> = {
762
1054
  readonly where?: FilterType<EntryColumns<TEntry>>;
763
1055
  };
764
- interface DatabaseInstance<TTables extends Record<string, TableEntry>> {
765
- /** The table registry for type-safe access. */
766
- readonly _tables: TTables;
767
- /** The computed tenant scoping graph. */
768
- readonly $tenantGraph: TenantGraph;
769
- /**
770
- * Execute a raw SQL query via the sql tagged template.
771
- */
772
- query<T = Record<string, unknown>>(fragment: SqlFragment): Promise<QueryResult<T>>;
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
- /** @deprecated Use `get` instead */
813
- findOne: DatabaseInstance<TTables>["get"];
814
- /** @deprecated Use `getOrThrow` instead */
815
- findOneOrThrow: DatabaseInstance<TTables>["getOrThrow"];
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
- * Insert multiple rows and return them.
835
- */
836
- createManyAndReturn<
837
- TName extends keyof TTables & string,
838
- TOptions extends TypedCreateManyAndReturnOptions<TTables[TName]>
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
- * Insert or update a row.
855
- */
856
- upsert<
857
- TName extends keyof TTables & string,
858
- TOptions extends TypedUpsertOptions<TTables[TName]>
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
- * Count rows matching an optional filter.
875
- */
876
- count<TName extends keyof TTables & string>(table: TName, options?: TypedCountOptions<TTables[TName]>): Promise<number>;
877
- /**
878
- * Run aggregation functions on a table.
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 Database instance.
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<TTables extends Record<string, TableEntry>>(options: CreateDbOptions<TTables>): DatabaseInstance<TTables>;
908
- interface EnumSchemaLike<T extends readonly string[]> {
909
- readonly values: T;
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
- declare const d: {
912
- uuid(): ColumnBuilder<string, DefaultMeta<"uuid">>;
913
- text(): ColumnBuilder<string, DefaultMeta<"text">>;
914
- varchar<TLength extends number>(length: TLength): ColumnBuilder<string, VarcharMeta<TLength>>;
915
- email(): ColumnBuilder<string, FormatMeta<"text", "email">>;
916
- boolean(): ColumnBuilder<boolean, DefaultMeta<"boolean">>;
917
- integer(): ColumnBuilder<number, DefaultMeta<"integer">>;
918
- bigint(): ColumnBuilder<bigint, DefaultMeta<"bigint">>;
919
- decimal<
920
- TPrecision extends number,
921
- TScale extends number
922
- >(precision: TPrecision, scale: TScale): ColumnBuilder<string, DecimalMeta<TPrecision, TScale>>;
923
- real(): ColumnBuilder<number, DefaultMeta<"real">>;
924
- doublePrecision(): ColumnBuilder<number, DefaultMeta<"double precision">>;
925
- serial(): ColumnBuilder<number, SerialMeta>;
926
- timestamp(): ColumnBuilder<Date, DefaultMeta<"timestamp with time zone">>;
927
- date(): ColumnBuilder<string, DefaultMeta<"date">>;
928
- time(): ColumnBuilder<string, DefaultMeta<"time">>;
929
- jsonb<T = unknown>(opts?: {
930
- validator: JsonbValidator<T>;
931
- }): ColumnBuilder<T, DefaultMeta<"jsonb">>;
932
- textArray(): ColumnBuilder<string[], DefaultMeta<"text[]">>;
933
- integerArray(): ColumnBuilder<number[], DefaultMeta<"integer[]">>;
934
- enum<
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
- interface UniqueConstraintErrorOptions {
973
- readonly table: string;
974
- readonly column: string;
975
- readonly value?: string;
976
- readonly query?: string;
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
- declare class UniqueConstraintError extends DbError {
979
- readonly code: "UNIQUE_VIOLATION";
980
- readonly pgCode: "23505";
981
- readonly table: string;
982
- readonly query: string | undefined;
983
- readonly column: string;
984
- readonly value: string | undefined;
985
- constructor(options: UniqueConstraintErrorOptions);
986
- toJSON(): DbErrorJson;
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 ForeignKeyErrorOptions {
989
- readonly table: string;
990
- readonly constraint: string;
991
- readonly detail?: string;
992
- readonly query?: string;
1220
+ interface IndexSnapshot {
1221
+ columns: string[];
1222
+ name?: string;
1223
+ unique?: boolean;
993
1224
  }
994
- declare class ForeignKeyError extends DbError {
995
- readonly code: "FOREIGN_KEY_VIOLATION";
996
- readonly pgCode: "23503";
997
- readonly table: string;
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 NotNullErrorOptions {
1005
- readonly table: string;
1006
- readonly column: string;
1007
- readonly query?: string;
1230
+ interface TableSnapshot {
1231
+ columns: Record<string, ColumnSnapshot>;
1232
+ indexes: IndexSnapshot[];
1233
+ foreignKeys: ForeignKeySnapshot[];
1234
+ _metadata: Record<string, unknown>;
1008
1235
  }
1009
- declare class NotNullError extends DbError {
1010
- readonly code: "NOT_NULL_VIOLATION";
1011
- readonly pgCode: "23502";
1012
- readonly table: string;
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
- interface CheckConstraintErrorOptions {
1019
- readonly table: string;
1020
- readonly constraint: string;
1021
- readonly query?: string;
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
- declare class CheckConstraintError extends DbError {
1024
- readonly code: "CHECK_VIOLATION";
1025
- readonly pgCode: "23514";
1026
- readonly table: string;
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
- declare class NotFoundError extends DbError {
1033
- readonly code: "NOT_FOUND";
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
- declare class ConnectionError extends DbError {
1040
- readonly code: string;
1041
- constructor(message: string);
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
- declare class ConnectionPoolExhaustedError extends ConnectionError {
1044
- readonly code: "POOL_EXHAUSTED";
1045
- constructor(poolSize: number);
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
- * Maps semantic error names to their corresponding PostgreSQL SQLSTATE codes.
1278
+ * Apply all pending migrations in order.
1049
1279
  *
1050
- * Usage in switch statements:
1051
- * ```ts
1052
- * switch (error.code) {
1053
- * case 'UNIQUE_VIOLATION': // ...
1054
- * case 'FOREIGN_KEY_VIOLATION': // ...
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
- * Reverse lookup (semantic name -> PG code):
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 const DbErrorCode: {
1064
- readonly UNIQUE_VIOLATION: "23505";
1065
- readonly FOREIGN_KEY_VIOLATION: "23503";
1066
- readonly NOT_NULL_VIOLATION: "23502";
1067
- readonly CHECK_VIOLATION: "23514";
1068
- readonly EXCLUSION_VIOLATION: "23P01";
1069
- readonly SERIALIZATION_FAILURE: "40001";
1070
- readonly DEADLOCK_DETECTED: "40P01";
1071
- readonly CONNECTION_EXCEPTION: "08000";
1072
- readonly CONNECTION_DOES_NOT_EXIST: "08003";
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
- * Reverse map: raw PG code -> semantic name.
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 const PgCodeToName: Readonly<Record<string, DbErrorCodeName | undefined>>;
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
- * Look up the semantic name for a raw PG error code.
1089
- * Returns the key (e.g., `'UNIQUE_VIOLATION'`) or `undefined` if unmapped.
1339
+ * Drop all user tables and re-apply all migrations from scratch.
1340
+ * Development use only.
1090
1341
  */
1091
- declare function resolveErrorCode(pgCode: string): DbErrorCodeName | undefined;
1092
- interface HttpErrorResponse {
1093
- readonly status: number;
1094
- readonly body: DbErrorJson;
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
- * Maps a DbError to an HTTP error response with the appropriate status code.
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
- * - UniqueConstraintError -> 409 Conflict
1100
- * - NotFoundError -> 404 Not Found
1101
- * - ForeignKeyError -> 422 Unprocessable Entity
1102
- * - NotNullError -> 422 Unprocessable Entity
1103
- * - CheckConstraintError -> 422 Unprocessable Entity
1104
- * - ConnectionError -> 503 Service Unavailable
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 dbErrorToHttpError(error: DbError): HttpErrorResponse;
1108
- interface PgErrorInput {
1109
- readonly code: string;
1110
- readonly message: string;
1111
- readonly table?: string;
1112
- readonly column?: string;
1113
- readonly constraint?: string;
1114
- readonly detail?: string;
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
- * Maps a raw PostgreSQL error object to a typed DbError subclass.
1473
+ * Convenience utility for creating a frozen bag of annotation constants.
1118
1474
  *
1119
- * Extracts structured metadata (column, constraint, value) from the
1120
- * PG error's `detail` and `message` fields.
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 parsePgError(pgError: PgErrorInput, query?: string): DbError;
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
- TTables extends Record<string, TableDef<ColumnRecord>>,
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 TTables, string>,
1532
+ TTargetName extends Extract<keyof TModels, string>,
1141
1533
  TFK extends ColumnKeys<TSourceTable>
1142
- >(target: TTargetName, foreignKey: TFK): RelationDef<TTables[TTargetName], "one">;
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 TTables, string>,
1146
- TFK extends ColumnKeys<TTables[TTargetName]>
1147
- >(target: TTargetName, foreignKey: TFK): RelationDef<TTables[TTargetName], "many">;
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<TTables extends Record<string, TableDef<ColumnRecord>>> = { [K in Extract<keyof TTables, string>] : TypedRef<TTables, TTables[K]> };
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 TableEntry, merging the table with its relations
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
- TTables extends Record<string, TableDef<ColumnRecord>>,
1161
- TRelMap extends { [K in keyof TTables]? : Record<string, RelationDef> }
1162
- > = { [K in keyof TTables] : TableEntry<TTables[K], K extends keyof TRelMap ? TRelMap[K] extends Record<string, RelationDef> ? TRelMap[K] : {} : {}> };
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 tables = createRegistry(
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
- TTables extends Record<string, TableDef<ColumnRecord>>,
1190
- TRelMap extends { [K in keyof TTables]? : Record<string, RelationDef> }
1191
- >(tables: TTables, relationsCallback: (ref: PerTableRefFactory<TTables>) => TRelMap): RegistryOutput<TTables, TRelMap>;
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 };