@kysera/dialects 0.8.2 → 0.8.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/dist/index.d.ts CHANGED
@@ -19,12 +19,54 @@ interface ConnectionConfig {
19
19
  password?: string | undefined;
20
20
  ssl?: boolean | undefined;
21
21
  }
22
+ /**
23
+ * Options for schema-aware database operations.
24
+ *
25
+ * @example
26
+ * // PostgreSQL: Query tables in a specific schema
27
+ * await adapter.tableExists(db, 'users', { schema: 'auth' })
28
+ *
29
+ * @example
30
+ * // Multi-tenant: Query tables in tenant-specific schema
31
+ * await adapter.getTables(db, { schema: `tenant_${tenantId}` })
32
+ */
33
+ interface SchemaOptions {
34
+ /**
35
+ * Schema name for the operation.
36
+ *
37
+ * - PostgreSQL: Defaults to 'public' if not specified
38
+ * - MySQL: Uses DATABASE() (schema = database in MySQL)
39
+ * - SQLite: Not supported (single schema only)
40
+ * - MSSQL: Defaults to 'dbo' if not specified
41
+ */
42
+ schema?: string;
43
+ }
44
+ /**
45
+ * Configuration options for creating dialect adapters
46
+ */
47
+ interface DialectAdapterOptions {
48
+ /**
49
+ * Default schema for all operations.
50
+ * Can be overridden per-call via SchemaOptions.
51
+ *
52
+ * - PostgreSQL: Defaults to 'public'
53
+ * - MySQL: Uses current database
54
+ * - SQLite: Not applicable
55
+ * - MSSQL: Defaults to 'dbo'
56
+ */
57
+ defaultSchema?: string;
58
+ }
22
59
  /**
23
60
  * Interface for dialect-specific operations
24
61
  */
25
62
  interface DialectAdapter {
26
63
  /** The dialect this adapter handles */
27
64
  readonly dialect: Dialect;
65
+ /**
66
+ * Default schema for this adapter.
67
+ * Used when SchemaOptions.schema is not specified.
68
+ */
69
+ readonly defaultSchema: string;
28
70
  /** Get default port for this dialect */
29
71
  getDefaultPort(): number | null;
30
72
  /** Get SQL expression for current timestamp */
@@ -39,22 +81,69 @@ interface DialectAdapter {
39
81
  isForeignKeyError(error: unknown): boolean;
40
82
  /** Check if error is a not-null constraint violation */
41
83
  isNotNullError(error: unknown): boolean;
42
- /** Check if a table exists in the database */
43
- tableExists(db: Kysely<any>, tableName: string): Promise<boolean>;
44
- /** Get column names for a table */
45
- getTableColumns(db: Kysely<any>, tableName: string): Promise<string[]>;
46
- /** Get all tables in the database */
47
- getTables(db: Kysely<any>): Promise<string[]>;
84
+ /**
85
+ * Check if a table exists in the database
86
+ *
87
+ * @param db - Kysely database instance
88
+ * @param tableName - Name of the table to check
89
+ * @param options - Optional schema configuration
90
+ * @returns true if table exists, false otherwise
91
+ *
92
+ * @example
93
+ * // Check in default schema (public)
94
+ * await adapter.tableExists(db, 'users')
95
+ *
96
+ * @example
97
+ * // Check in specific schema
98
+ * await adapter.tableExists(db, 'users', { schema: 'auth' })
99
+ */
100
+ tableExists(db: Kysely<any>, tableName: string, options?: SchemaOptions): Promise<boolean>;
101
+ /**
102
+ * Get column names for a table
103
+ *
104
+ * @param db - Kysely database instance
105
+ * @param tableName - Name of the table
106
+ * @param options - Optional schema configuration
107
+ * @returns Array of column names
108
+ *
109
+ * @example
110
+ * const columns = await adapter.getTableColumns(db, 'users', { schema: 'auth' })
111
+ * // ['id', 'email', 'password_hash', 'created_at']
112
+ */
113
+ getTableColumns(db: Kysely<any>, tableName: string, options?: SchemaOptions): Promise<string[]>;
114
+ /**
115
+ * Get all tables in the database/schema
116
+ *
117
+ * @param db - Kysely database instance
118
+ * @param options - Optional schema configuration
119
+ * @returns Array of table names
120
+ *
121
+ * @example
122
+ * // Get tables in auth schema
123
+ * const tables = await adapter.getTables(db, { schema: 'auth' })
124
+ * // ['users', 'sessions', 'tokens']
125
+ */
126
+ getTables(db: Kysely<any>, options?: SchemaOptions): Promise<string[]>;
48
127
  /** Get database size in bytes */
49
128
  getDatabaseSize(db: Kysely<any>, databaseName?: string): Promise<number>;
50
129
  /**
51
130
  * Truncate a single table
131
+ *
132
+ * @param db - Kysely database instance
133
+ * @param tableName - Name of the table to truncate
134
+ * @param options - Optional schema configuration
52
135
  * @returns true if table was truncated, false if table does not exist
53
136
  * @throws Error for other database errors
54
137
  */
55
- truncateTable(db: Kysely<any>, tableName: string): Promise<boolean>;
56
- /** Truncate all tables (for testing) */
57
- truncateAllTables(db: Kysely<any>, exclude?: string[]): Promise<void>;
138
+ truncateTable(db: Kysely<any>, tableName: string, options?: SchemaOptions): Promise<boolean>;
139
+ /**
140
+ * Truncate all tables in the database/schema (for testing)
141
+ *
142
+ * @param db - Kysely database instance
143
+ * @param exclude - Array of table names to exclude
144
+ * @param options - Optional schema configuration
145
+ */
146
+ truncateAllTables(db: Kysely<any>, exclude?: string[], options?: SchemaOptions): Promise<void>;
58
147
  }
59
148
  /**
60
149
  * Error object shape for database error detection
@@ -62,43 +151,29 @@ interface DialectAdapter {
62
151
  interface DatabaseErrorLike {
63
152
  message?: string;
64
153
  code?: string;
154
+ /** Error number (used by MSSQL for error codes like 2627, 547, 515) */
155
+ number?: number;
65
156
  }
66
157
 
67
158
  /**
68
- * Dialect Adapter Factory
69
- */
70
-
71
- /**
72
- * Get a dialect adapter for the specified dialect
73
- *
74
- * @example
75
- * const adapter = getAdapter('postgres');
76
- * console.log(adapter.getDefaultPort()); // 5432
77
- */
78
- declare function getAdapter(dialect: Dialect): DialectAdapter;
79
- /**
80
- * Create a new dialect adapter instance
81
- *
82
- * @example
83
- * const adapter = createDialectAdapter('mysql');
84
- */
85
- declare function createDialectAdapter(dialect: Dialect): DialectAdapter;
86
- /**
87
- * Register a custom dialect adapter
159
+ * PostgreSQL Dialect Adapter
88
160
  *
89
- * @example
90
- * registerAdapter(customAdapter);
161
+ * Supports PostgreSQL 12+ with full schema support for multi-tenant
162
+ * and modular database architectures.
91
163
  */
92
- declare function registerAdapter(adapter: DialectAdapter): void;
93
164
 
94
165
  /**
95
- * PostgreSQL Dialect Adapter
166
+ * PostgreSQL-specific adapter options
96
167
  */
97
-
168
+ interface PostgresAdapterOptions extends DialectAdapterOptions {
169
+ /** Logger instance for error reporting */
170
+ logger?: KyseraLogger;
171
+ }
98
172
  declare class PostgresAdapter implements DialectAdapter {
99
173
  readonly dialect: "postgres";
174
+ readonly defaultSchema: string;
100
175
  private logger;
101
- constructor(logger?: KyseraLogger);
176
+ constructor(options?: PostgresAdapterOptions);
102
177
  getDefaultPort(): number;
103
178
  getCurrentTimestamp(): string;
104
179
  escapeIdentifier(identifier: string): string;
@@ -106,23 +181,241 @@ declare class PostgresAdapter implements DialectAdapter {
106
181
  isUniqueConstraintError(error: unknown): boolean;
107
182
  isForeignKeyError(error: unknown): boolean;
108
183
  isNotNullError(error: unknown): boolean;
109
- tableExists(db: Kysely<any>, tableName: string): Promise<boolean>;
110
- getTableColumns(db: Kysely<any>, tableName: string): Promise<string[]>;
111
- getTables(db: Kysely<any>): Promise<string[]>;
184
+ /**
185
+ * Resolve the schema to use for an operation.
186
+ * Uses the shared resolveSchema utility from helpers.ts.
187
+ */
188
+ private resolveSchema;
189
+ tableExists(db: Kysely<any>, tableName: string, options?: SchemaOptions): Promise<boolean>;
190
+ getTableColumns(db: Kysely<any>, tableName: string, options?: SchemaOptions): Promise<string[]>;
191
+ getTables(db: Kysely<any>, options?: SchemaOptions): Promise<string[]>;
112
192
  getDatabaseSize(db: Kysely<any>, databaseName?: string): Promise<number>;
113
- truncateTable(db: Kysely<any>, tableName: string): Promise<boolean>;
114
- truncateAllTables(db: Kysely<any>, exclude?: string[]): Promise<void>;
193
+ truncateTable(db: Kysely<any>, tableName: string, options?: SchemaOptions): Promise<boolean>;
194
+ truncateAllTables(db: Kysely<any>, exclude?: string[], options?: SchemaOptions): Promise<void>;
195
+ /**
196
+ * Check if a schema exists in the database
197
+ *
198
+ * @param db - Kysely database instance
199
+ * @param schemaName - Name of the schema to check
200
+ * @returns true if schema exists, false otherwise
201
+ *
202
+ * @example
203
+ * const exists = await adapter.schemaExists(db, 'auth')
204
+ */
205
+ schemaExists(db: Kysely<any>, schemaName: string): Promise<boolean>;
206
+ /**
207
+ * Get all schemas in the database (excluding system schemas)
208
+ *
209
+ * @param db - Kysely database instance
210
+ * @returns Array of schema names
211
+ *
212
+ * @example
213
+ * const schemas = await adapter.getSchemas(db)
214
+ * // ['public', 'auth', 'admin', 'tenant_1']
215
+ */
216
+ getSchemas(db: Kysely<any>): Promise<string[]>;
217
+ /**
218
+ * Create a new schema in the database
219
+ *
220
+ * @param db - Kysely database instance
221
+ * @param schemaName - Name of the schema to create
222
+ * @param options - Creation options
223
+ * @returns true if schema was created, false if it already exists
224
+ *
225
+ * @example
226
+ * await adapter.createSchema(db, 'tenant_123')
227
+ */
228
+ createSchema(db: Kysely<any>, schemaName: string, options?: {
229
+ ifNotExists?: boolean;
230
+ }): Promise<boolean>;
231
+ /**
232
+ * Drop a schema from the database
233
+ *
234
+ * @param db - Kysely database instance
235
+ * @param schemaName - Name of the schema to drop
236
+ * @param options - Drop options
237
+ * @returns true if schema was dropped, false if it doesn't exist
238
+ *
239
+ * @example
240
+ * await adapter.dropSchema(db, 'tenant_123', { cascade: true })
241
+ */
242
+ dropSchema(db: Kysely<any>, schemaName: string, options?: {
243
+ ifExists?: boolean;
244
+ cascade?: boolean;
245
+ }): Promise<boolean>;
246
+ /**
247
+ * Get detailed information about a schema
248
+ *
249
+ * @param db - Kysely database instance
250
+ * @param schemaName - Name of the schema
251
+ * @returns Schema information including table count, size, and owner
252
+ *
253
+ * @example
254
+ * const info = await adapter.getSchemaInfo(db, 'tenant_123')
255
+ * // { name: 'tenant_123', tableCount: 15, owner: 'app_user', sizeBytes: 1048576 }
256
+ */
257
+ getSchemaInfo(db: Kysely<any>, schemaName: string): Promise<{
258
+ name: string;
259
+ tableCount: number;
260
+ owner: string | null;
261
+ sizeBytes: number;
262
+ }>;
263
+ /**
264
+ * Get index information for all tables in a schema
265
+ *
266
+ * @param db - Kysely database instance
267
+ * @param options - Optional schema configuration
268
+ * @returns Array of index information
269
+ *
270
+ * @example
271
+ * const indexes = await adapter.getSchemaIndexes(db, { schema: 'auth' })
272
+ */
273
+ getSchemaIndexes(db: Kysely<any>, options?: SchemaOptions): Promise<{
274
+ tableName: string;
275
+ indexName: string;
276
+ indexType: string;
277
+ isUnique: boolean;
278
+ isPrimary: boolean;
279
+ columns: string[];
280
+ }[]>;
281
+ /**
282
+ * Get foreign key relationships in a schema
283
+ *
284
+ * @param db - Kysely database instance
285
+ * @param options - Optional schema configuration
286
+ * @returns Array of foreign key relationships
287
+ *
288
+ * @example
289
+ * const fks = await adapter.getSchemaForeignKeys(db, { schema: 'public' })
290
+ */
291
+ getSchemaForeignKeys(db: Kysely<any>, options?: SchemaOptions): Promise<{
292
+ constraintName: string;
293
+ tableName: string;
294
+ columnName: string;
295
+ referencedSchema: string;
296
+ referencedTable: string;
297
+ referencedColumn: string;
298
+ onDelete: string;
299
+ onUpdate: string;
300
+ }[]>;
301
+ /**
302
+ * Get the current search_path setting
303
+ *
304
+ * @param db - Kysely database instance
305
+ * @returns Array of schema names in the search path
306
+ *
307
+ * @example
308
+ * const path = await adapter.getSearchPath(db)
309
+ * // ['public', 'tenant_123']
310
+ */
311
+ getSearchPath(db: Kysely<any>): Promise<string[]>;
312
+ /**
313
+ * Set the search_path for the current session
314
+ *
315
+ * @param db - Kysely database instance
316
+ * @param schemas - Array of schema names to set in the search path
317
+ *
318
+ * @example
319
+ * // Set search path for multi-tenant query
320
+ * await adapter.setSearchPath(db, ['tenant_123', 'public'])
321
+ */
322
+ setSearchPath(db: Kysely<any>, schemas: string[]): Promise<void>;
323
+ /**
324
+ * Execute a function with a temporary search_path, then restore the original
325
+ *
326
+ * @param db - Kysely database instance
327
+ * @param schemas - Temporary search path
328
+ * @param fn - Function to execute with the temporary search path
329
+ * @returns The result of the function
330
+ *
331
+ * @example
332
+ * const result = await adapter.withSearchPath(db, ['tenant_123'], async () => {
333
+ * // All queries in here will use tenant_123 schema by default
334
+ * return await db.selectFrom('users').selectAll().execute()
335
+ * })
336
+ */
337
+ withSearchPath<T>(db: Kysely<any>, schemas: string[], fn: () => Promise<T>): Promise<T>;
338
+ /**
339
+ * Clone a schema's structure (tables, indexes, constraints) to a new schema
340
+ *
341
+ * @param db - Kysely database instance
342
+ * @param sourceSchema - Source schema to clone from
343
+ * @param targetSchema - Target schema name to create
344
+ * @param options - Clone options
345
+ * @returns true if successful
346
+ *
347
+ * @example
348
+ * // Clone 'template' schema to create new tenant schema
349
+ * await adapter.cloneSchema(db, 'template', 'tenant_456')
350
+ *
351
+ * @example
352
+ * // Clone with data included
353
+ * await adapter.cloneSchema(db, 'template', 'tenant_456', { includeData: true })
354
+ */
355
+ cloneSchema(db: Kysely<any>, sourceSchema: string, targetSchema: string, options?: {
356
+ includeData?: boolean;
357
+ excludeTables?: string[];
358
+ }): Promise<boolean>;
359
+ /**
360
+ * Compare two schemas and return the differences
361
+ *
362
+ * @param db - Kysely database instance
363
+ * @param schema1 - First schema name
364
+ * @param schema2 - Second schema name
365
+ * @returns Comparison result with tables unique to each schema
366
+ *
367
+ * @example
368
+ * const diff = await adapter.compareSchemas(db, 'template', 'tenant_123')
369
+ * // { onlyInFirst: ['archived_users'], onlyInSecond: ['custom_settings'], inBoth: ['users', 'posts'] }
370
+ */
371
+ compareSchemas(db: Kysely<any>, schema1: string, schema2: string): Promise<{
372
+ onlyInFirst: string[];
373
+ onlyInSecond: string[];
374
+ inBoth: string[];
375
+ }>;
115
376
  }
377
+ /**
378
+ * Default PostgreSQL adapter instance with 'public' schema
379
+ */
116
380
  declare const postgresAdapter: PostgresAdapter;
381
+ /**
382
+ * Create a new PostgreSQL adapter with custom configuration
383
+ *
384
+ * @param options - Adapter configuration options
385
+ * @returns Configured PostgresAdapter instance
386
+ *
387
+ * @example
388
+ * // Create adapter with custom default schema
389
+ * const adapter = createPostgresAdapter({ defaultSchema: 'auth' })
390
+ *
391
+ * @example
392
+ * // Create adapter with logger
393
+ * const adapter = createPostgresAdapter({
394
+ * defaultSchema: 'app',
395
+ * logger: myLogger
396
+ * })
397
+ */
398
+ declare function createPostgresAdapter(options?: PostgresAdapterOptions): PostgresAdapter;
117
399
 
118
400
  /**
119
401
  * MySQL Dialect Adapter
402
+ *
403
+ * Note: In MySQL, "schema" and "database" are synonymous.
404
+ * The schema option maps to the current database context.
120
405
  */
121
406
 
407
+ /**
408
+ * MySQL-specific adapter options
409
+ */
410
+ interface MySQLAdapterOptions extends DialectAdapterOptions {
411
+ /** Logger instance for error reporting */
412
+ logger?: KyseraLogger;
413
+ }
122
414
  declare class MySQLAdapter implements DialectAdapter {
123
415
  readonly dialect: "mysql";
416
+ readonly defaultSchema: string;
124
417
  private logger;
125
- constructor(logger?: KyseraLogger);
418
+ constructor(options?: MySQLAdapterOptions);
126
419
  getDefaultPort(): number;
127
420
  getCurrentTimestamp(): string;
128
421
  escapeIdentifier(identifier: string): string;
@@ -130,23 +423,57 @@ declare class MySQLAdapter implements DialectAdapter {
130
423
  isUniqueConstraintError(error: unknown): boolean;
131
424
  isForeignKeyError(error: unknown): boolean;
132
425
  isNotNullError(error: unknown): boolean;
133
- tableExists(db: Kysely<any>, tableName: string): Promise<boolean>;
134
- getTableColumns(db: Kysely<any>, tableName: string): Promise<string[]>;
135
- getTables(db: Kysely<any>): Promise<string[]>;
426
+ /**
427
+ * Get the schema (database) filter for queries.
428
+ * In MySQL, schema = database, so we use DATABASE() if not specified.
429
+ */
430
+ private getSchemaFilter;
431
+ tableExists(db: Kysely<any>, tableName: string, options?: SchemaOptions): Promise<boolean>;
432
+ getTableColumns(db: Kysely<any>, tableName: string, options?: SchemaOptions): Promise<string[]>;
433
+ getTables(db: Kysely<any>, options?: SchemaOptions): Promise<string[]>;
136
434
  getDatabaseSize(db: Kysely<any>, databaseName?: string): Promise<number>;
137
- truncateTable(db: Kysely<any>, tableName: string): Promise<boolean>;
138
- truncateAllTables(db: Kysely<any>, exclude?: string[]): Promise<void>;
435
+ truncateTable(db: Kysely<any>, tableName: string, options?: SchemaOptions): Promise<boolean>;
436
+ truncateAllTables(db: Kysely<any>, exclude?: string[], options?: SchemaOptions): Promise<void>;
139
437
  }
438
+ /**
439
+ * Default MySQL adapter instance
440
+ */
140
441
  declare const mysqlAdapter: MySQLAdapter;
442
+ /**
443
+ * Create a new MySQL adapter with custom configuration
444
+ *
445
+ * @param options - Adapter configuration options
446
+ * @returns Configured MySQLAdapter instance
447
+ *
448
+ * @example
449
+ * // Create adapter with specific database as default
450
+ * const adapter = createMySQLAdapter({ defaultSchema: 'my_database' })
451
+ */
452
+ declare function createMySQLAdapter(options?: MySQLAdapterOptions): MySQLAdapter;
141
453
 
142
454
  /**
143
455
  * SQLite Dialect Adapter
456
+ *
457
+ * Note: SQLite does not support schemas in the same way as PostgreSQL.
458
+ * Each SQLite database is a single schema. The schema option is accepted
459
+ * for interface compatibility but is ignored for most operations.
460
+ *
461
+ * SQLite does support ATTACH DATABASE for multiple schemas, but this
462
+ * requires special handling and is not currently implemented.
144
463
  */
145
464
 
465
+ /**
466
+ * SQLite-specific adapter options
467
+ */
468
+ interface SQLiteAdapterOptions extends DialectAdapterOptions {
469
+ /** Logger instance for error reporting */
470
+ logger?: KyseraLogger;
471
+ }
146
472
  declare class SQLiteAdapter implements DialectAdapter {
147
473
  readonly dialect: "sqlite";
474
+ readonly defaultSchema: string;
148
475
  private logger;
149
- constructor(logger?: KyseraLogger);
476
+ constructor(options?: SQLiteAdapterOptions);
150
477
  getDefaultPort(): null;
151
478
  getCurrentTimestamp(): string;
152
479
  escapeIdentifier(identifier: string): string;
@@ -154,23 +481,54 @@ declare class SQLiteAdapter implements DialectAdapter {
154
481
  isUniqueConstraintError(error: unknown): boolean;
155
482
  isForeignKeyError(error: unknown): boolean;
156
483
  isNotNullError(error: unknown): boolean;
157
- tableExists(db: Kysely<any>, tableName: string): Promise<boolean>;
158
- getTableColumns(db: Kysely<any>, tableName: string): Promise<string[]>;
159
- getTables(db: Kysely<any>): Promise<string[]>;
484
+ /**
485
+ * Resolve the schema to use. In SQLite, this is typically 'main'
486
+ * unless ATTACH DATABASE has been used.
487
+ * Uses the shared resolveSchema utility from helpers.ts.
488
+ */
489
+ private resolveSchema;
490
+ tableExists(db: Kysely<any>, tableName: string, options?: SchemaOptions): Promise<boolean>;
491
+ getTableColumns(db: Kysely<any>, tableName: string, options?: SchemaOptions): Promise<string[]>;
492
+ getTables(db: Kysely<any>, options?: SchemaOptions): Promise<string[]>;
160
493
  getDatabaseSize(_db: Kysely<any>, _databaseName?: string): Promise<number>;
161
- truncateTable(db: Kysely<any>, tableName: string): Promise<boolean>;
162
- truncateAllTables(db: Kysely<any>, exclude?: string[]): Promise<void>;
494
+ truncateTable(db: Kysely<any>, tableName: string, options?: SchemaOptions): Promise<boolean>;
495
+ truncateAllTables(db: Kysely<any>, exclude?: string[], options?: SchemaOptions): Promise<void>;
163
496
  }
497
+ /**
498
+ * Default SQLite adapter instance
499
+ */
164
500
  declare const sqliteAdapter: SQLiteAdapter;
501
+ /**
502
+ * Create a new SQLite adapter with custom configuration
503
+ *
504
+ * @param options - Adapter configuration options
505
+ * @returns Configured SQLiteAdapter instance
506
+ *
507
+ * @example
508
+ * // Create adapter (schema options have limited effect in SQLite)
509
+ * const adapter = createSQLiteAdapter()
510
+ */
511
+ declare function createSQLiteAdapter(options?: SQLiteAdapterOptions): SQLiteAdapter;
165
512
 
166
513
  /**
167
514
  * Microsoft SQL Server Dialect Adapter
168
515
  *
169
516
  * Supports SQL Server 2017+, Azure SQL Database, and Azure SQL Edge
517
+ * with full schema support (default: 'dbo')
170
518
  */
171
519
 
520
+ /**
521
+ * MSSQL-specific adapter options
522
+ */
523
+ interface MSSQLAdapterOptions extends DialectAdapterOptions {
524
+ /** Logger instance for error reporting */
525
+ logger?: KyseraLogger;
526
+ }
172
527
  declare class MSSQLAdapter implements DialectAdapter {
173
528
  readonly dialect: "mssql";
529
+ readonly defaultSchema: string;
530
+ private logger;
531
+ constructor(options?: MSSQLAdapterOptions);
174
532
  getDefaultPort(): number;
175
533
  getCurrentTimestamp(): string;
176
534
  escapeIdentifier(identifier: string): string;
@@ -178,14 +536,133 @@ declare class MSSQLAdapter implements DialectAdapter {
178
536
  isUniqueConstraintError(error: unknown): boolean;
179
537
  isForeignKeyError(error: unknown): boolean;
180
538
  isNotNullError(error: unknown): boolean;
181
- tableExists(db: Kysely<any>, tableName: string): Promise<boolean>;
182
- getTableColumns(db: Kysely<any>, tableName: string): Promise<string[]>;
183
- getTables(db: Kysely<any>): Promise<string[]>;
539
+ /**
540
+ * Resolve the schema to use for an operation.
541
+ * Uses the shared resolveSchema utility from helpers.ts.
542
+ */
543
+ private resolveSchema;
544
+ tableExists(db: Kysely<any>, tableName: string, options?: SchemaOptions): Promise<boolean>;
545
+ getTableColumns(db: Kysely<any>, tableName: string, options?: SchemaOptions): Promise<string[]>;
546
+ getTables(db: Kysely<any>, options?: SchemaOptions): Promise<string[]>;
184
547
  getDatabaseSize(db: Kysely<any>, _databaseName?: string): Promise<number>;
185
- truncateTable(db: Kysely<any>, tableName: string): Promise<boolean>;
186
- truncateAllTables(db: Kysely<any>, exclude?: string[]): Promise<void>;
548
+ truncateTable(db: Kysely<any>, tableName: string, options?: SchemaOptions): Promise<boolean>;
549
+ truncateAllTables(db: Kysely<any>, exclude?: string[], options?: SchemaOptions): Promise<void>;
550
+ /**
551
+ * Check if a schema exists in the database
552
+ *
553
+ * @param db - Kysely database instance
554
+ * @param schemaName - Name of the schema to check
555
+ * @returns true if schema exists, false otherwise
556
+ */
557
+ schemaExists(db: Kysely<any>, schemaName: string): Promise<boolean>;
558
+ /**
559
+ * Get all schemas in the database (excluding system schemas)
560
+ *
561
+ * @param db - Kysely database instance
562
+ * @returns Array of schema names
563
+ */
564
+ getSchemas(db: Kysely<any>): Promise<string[]>;
565
+ /**
566
+ * Create a new schema in the database
567
+ *
568
+ * @param db - Kysely database instance
569
+ * @param schemaName - Name of the schema to create
570
+ * @returns true if schema was created, false if it already exists
571
+ */
572
+ createSchema(db: Kysely<any>, schemaName: string): Promise<boolean>;
573
+ /**
574
+ * Drop a schema from the database
575
+ *
576
+ * @param db - Kysely database instance
577
+ * @param schemaName - Name of the schema to drop
578
+ * @returns true if schema was dropped, false if it doesn't exist
579
+ */
580
+ dropSchema(db: Kysely<any>, schemaName: string): Promise<boolean>;
187
581
  }
582
+ /**
583
+ * Default MSSQL adapter instance with 'dbo' schema
584
+ */
188
585
  declare const mssqlAdapter: MSSQLAdapter;
586
+ /**
587
+ * Create a new MSSQL adapter with custom configuration
588
+ *
589
+ * @param options - Adapter configuration options
590
+ * @returns Configured MSSQLAdapter instance
591
+ *
592
+ * @example
593
+ * // Create adapter with custom default schema
594
+ * const adapter = createMSSQLAdapter({ defaultSchema: 'app' })
595
+ */
596
+ declare function createMSSQLAdapter(options?: MSSQLAdapterOptions): MSSQLAdapter;
597
+
598
+ /**
599
+ * Dialect Adapter Factory
600
+ */
601
+
602
+ /**
603
+ * Get a dialect adapter for the specified dialect.
604
+ * Returns a shared singleton instance with default configuration.
605
+ *
606
+ * @param dialect - Database dialect
607
+ * @returns DialectAdapter instance
608
+ *
609
+ * @example
610
+ * const adapter = getAdapter('postgres')
611
+ * console.log(adapter.getDefaultPort()) // 5432
612
+ * console.log(adapter.defaultSchema) // 'public'
613
+ */
614
+ declare function getAdapter(dialect: Dialect): DialectAdapter;
615
+ /**
616
+ * Adapter options by dialect type
617
+ */
618
+ type AdapterOptions = {
619
+ dialect: 'postgres';
620
+ options?: PostgresAdapterOptions;
621
+ } | {
622
+ dialect: 'mysql';
623
+ options?: MySQLAdapterOptions;
624
+ } | {
625
+ dialect: 'sqlite';
626
+ options?: SQLiteAdapterOptions;
627
+ } | {
628
+ dialect: 'mssql';
629
+ options?: MSSQLAdapterOptions;
630
+ };
631
+ /**
632
+ * Create a new dialect adapter instance with custom options.
633
+ * Use this when you need a custom default schema or logger.
634
+ *
635
+ * @param dialect - Database dialect
636
+ * @param options - Dialect-specific adapter options
637
+ * @returns New DialectAdapter instance
638
+ *
639
+ * @example
640
+ * // Create adapter with custom default schema
641
+ * const adapter = createDialectAdapter('postgres', { defaultSchema: 'auth' })
642
+ *
643
+ * @example
644
+ * // Create adapter with logger
645
+ * const adapter = createDialectAdapter('postgres', {
646
+ * defaultSchema: 'app',
647
+ * logger: myLogger
648
+ * })
649
+ */
650
+ declare function createDialectAdapter(dialect: 'postgres', options?: PostgresAdapterOptions): PostgresAdapter;
651
+ declare function createDialectAdapter(dialect: 'mysql', options?: MySQLAdapterOptions): MySQLAdapter;
652
+ declare function createDialectAdapter(dialect: 'sqlite', options?: SQLiteAdapterOptions): SQLiteAdapter;
653
+ declare function createDialectAdapter(dialect: 'mssql', options?: MSSQLAdapterOptions): MSSQLAdapter;
654
+ declare function createDialectAdapter(dialect: Dialect, options?: DialectAdapterOptions): DialectAdapter;
655
+ /**
656
+ * Register a custom dialect adapter.
657
+ * This replaces the default adapter for the given dialect.
658
+ *
659
+ * @param adapter - DialectAdapter instance to register
660
+ *
661
+ * @example
662
+ * const customAdapter = new PostgresAdapter({ defaultSchema: 'custom' })
663
+ * registerAdapter(customAdapter)
664
+ */
665
+ declare function registerAdapter(adapter: DialectAdapter): void;
189
666
 
190
667
  /**
191
668
  * Connection URL utilities
@@ -225,7 +702,7 @@ declare function getDefaultPort(dialect: Dialect): number | null;
225
702
  */
226
703
 
227
704
  /**
228
- * Validate a SQL identifier (table name, column name, etc.)
705
+ * Validate a SQL identifier (table name, column name, schema name, etc.)
229
706
  *
230
707
  * @param name - The identifier to validate
231
708
  * @returns true if the identifier is valid, false otherwise
@@ -251,29 +728,263 @@ declare function validateIdentifier(name: string): boolean;
251
728
  * assertValidIdentifier('123bad', 'table name'); // throws Error: Invalid table name: 123bad
252
729
  */
253
730
  declare function assertValidIdentifier(name: string, context?: string): void;
731
+ /**
732
+ * Resolve schema name with validation
733
+ *
734
+ * This is the canonical implementation used by all dialect adapters.
735
+ * Eliminates code duplication across PostgreSQL, MySQL, SQLite, and MSSQL adapters.
736
+ *
737
+ * @param defaultSchema - The default schema to use if not specified in options
738
+ * @param options - Optional schema configuration
739
+ * @returns The resolved and validated schema name
740
+ * @throws Error if the schema name is invalid
741
+ *
742
+ * @example
743
+ * // Use with adapter's default schema
744
+ * const schema = resolveSchema('public', options)
745
+ *
746
+ * @example
747
+ * // Multi-tenant usage
748
+ * const schema = resolveSchema('public', { schema: `tenant_${tenantId}` })
749
+ */
750
+ declare function resolveSchema(defaultSchema: string, options?: SchemaOptions): string;
751
+ /**
752
+ * Configuration for multi-tenant schema operations
753
+ */
754
+ interface TenantSchemaConfig {
755
+ /** Prefix for tenant schema names (default: 'tenant_') */
756
+ prefix?: string;
757
+ }
758
+ /**
759
+ * Generate a tenant schema name from a tenant ID
760
+ *
761
+ * @param tenantId - The unique tenant identifier
762
+ * @param config - Optional configuration
763
+ * @returns The tenant schema name (validated)
764
+ * @throws Error if the resulting schema name is invalid
765
+ *
766
+ * @example
767
+ * getTenantSchemaName('123') // 'tenant_123'
768
+ * getTenantSchemaName('acme') // 'tenant_acme'
769
+ * getTenantSchemaName('corp', { prefix: 'org_' }) // 'org_corp'
770
+ */
771
+ declare function getTenantSchemaName(tenantId: string, config?: TenantSchemaConfig): string;
772
+ /**
773
+ * Extract tenant ID from a tenant schema name
774
+ *
775
+ * @param schemaName - The schema name to parse
776
+ * @param config - Optional configuration
777
+ * @returns The tenant ID if the schema matches the pattern, null otherwise
778
+ *
779
+ * @example
780
+ * parseTenantSchemaName('tenant_123') // '123'
781
+ * parseTenantSchemaName('tenant_acme') // 'acme'
782
+ * parseTenantSchemaName('public') // null
783
+ * parseTenantSchemaName('org_corp', { prefix: 'org_' }) // 'corp'
784
+ */
785
+ declare function parseTenantSchemaName(schemaName: string, config?: TenantSchemaConfig): string | null;
786
+ /**
787
+ * Check if a schema name matches the tenant schema pattern
788
+ *
789
+ * @param schemaName - The schema name to check
790
+ * @param config - Optional configuration
791
+ * @returns true if the schema matches the tenant pattern
792
+ *
793
+ * @example
794
+ * isTenantSchema('tenant_123') // true
795
+ * isTenantSchema('public') // false
796
+ * isTenantSchema('org_corp', { prefix: 'org_' }) // true
797
+ */
798
+ declare function isTenantSchema(schemaName: string, config?: TenantSchemaConfig): boolean;
799
+ /**
800
+ * Filter an array of schema names to only tenant schemas
801
+ *
802
+ * @param schemas - Array of schema names
803
+ * @param config - Optional configuration
804
+ * @returns Array of tenant schema names
805
+ *
806
+ * @example
807
+ * filterTenantSchemas(['public', 'tenant_1', 'tenant_2', 'auth'])
808
+ * // ['tenant_1', 'tenant_2']
809
+ */
810
+ declare function filterTenantSchemas(schemas: string[], config?: TenantSchemaConfig): string[];
811
+ /**
812
+ * Extract tenant IDs from an array of schema names
813
+ *
814
+ * @param schemas - Array of schema names
815
+ * @param config - Optional configuration
816
+ * @returns Array of tenant IDs (excluding non-tenant schemas)
817
+ *
818
+ * @example
819
+ * extractTenantIds(['public', 'tenant_1', 'tenant_2', 'auth'])
820
+ * // ['1', '2']
821
+ */
822
+ declare function extractTenantIds(schemas: string[], config?: TenantSchemaConfig): string[];
823
+ /**
824
+ * Options for schema copying operations
825
+ */
826
+ interface SchemaCopyOptions {
827
+ /** Include table data (default: false, structure only) */
828
+ includeData?: boolean;
829
+ /** Tables to exclude from copying */
830
+ excludeTables?: string[];
831
+ /** Tables to include (if specified, only these are copied) */
832
+ includeTables?: string[];
833
+ }
834
+ /**
835
+ * Create a qualified table name with schema prefix
836
+ *
837
+ * @param schema - The schema name
838
+ * @param tableName - The table name
839
+ * @param escapeIdentifierFn - Function to escape identifiers for the specific dialect
840
+ * @returns Fully qualified table name (e.g., "public"."users")
841
+ *
842
+ * @example
843
+ * qualifyTableName('auth', 'users', escapeIdentifier)
844
+ * // PostgreSQL: "auth"."users"
845
+ * // MySQL: `auth`.`users`
846
+ */
847
+ declare function qualifyTableName(schema: string, tableName: string, escapeIdentifierFn: (id: string) => string): string;
848
+ /**
849
+ * Error information extracted from a database error
850
+ */
851
+ interface ExtractedErrorInfo {
852
+ /** Error code (e.g., '23505' for PostgreSQL unique constraint) */
853
+ code: string;
854
+ /** Error message in lowercase for case-insensitive matching */
855
+ message: string;
856
+ /** Original error message */
857
+ originalMessage: string;
858
+ /** Error number (for MSSQL) - undefined if not present */
859
+ number: number | undefined;
860
+ }
861
+ /**
862
+ * Extract error information from an unknown database error
863
+ *
864
+ * This utility normalizes error information across different database drivers,
865
+ * eliminating the need for repeated type assertions in each adapter.
866
+ *
867
+ * @param error - The unknown error from a database operation
868
+ * @returns Normalized error information
869
+ *
870
+ * @example
871
+ * try {
872
+ * await db.insertInto('users').values(data).execute()
873
+ * } catch (error) {
874
+ * const info = extractErrorInfo(error)
875
+ * if (info.code === '23505') {
876
+ * // Handle unique constraint violation
877
+ * }
878
+ * }
879
+ */
880
+ declare function extractErrorInfo(error: unknown): ExtractedErrorInfo;
881
+ /**
882
+ * Error matcher configuration for a specific error type
883
+ */
884
+ interface ErrorMatcherConfig {
885
+ /** PostgreSQL error codes */
886
+ codes?: string[];
887
+ /** MSSQL error numbers */
888
+ numbers?: number[];
889
+ /** Message substrings to match (case-insensitive) */
890
+ messages?: string[];
891
+ }
892
+ /**
893
+ * Create an error matcher function for a specific constraint type
894
+ *
895
+ * This factory eliminates code duplication across dialect adapters by creating
896
+ * reusable error detection functions.
897
+ *
898
+ * @param config - Configuration for matching the error
899
+ * @returns A function that checks if an error matches the configured patterns
900
+ *
901
+ * @example
902
+ * // Create a unique constraint error matcher for PostgreSQL
903
+ * const isUniqueConstraint = createErrorMatcher({
904
+ * codes: ['23505'],
905
+ * messages: ['unique constraint']
906
+ * })
907
+ *
908
+ * @example
909
+ * // Create a foreign key error matcher for MSSQL
910
+ * const isForeignKey = createErrorMatcher({
911
+ * numbers: [547],
912
+ * messages: ['foreign key']
913
+ * })
914
+ */
915
+ declare function createErrorMatcher(config: ErrorMatcherConfig): (error: unknown) => boolean;
916
+ /**
917
+ * Pre-built error matchers for common constraint violations
918
+ * These can be used directly or as reference for custom matchers
919
+ */
920
+ declare const errorMatchers: {
921
+ readonly postgres: {
922
+ readonly uniqueConstraint: (error: unknown) => boolean;
923
+ readonly foreignKey: (error: unknown) => boolean;
924
+ readonly notNull: (error: unknown) => boolean;
925
+ };
926
+ readonly mysql: {
927
+ readonly uniqueConstraint: (error: unknown) => boolean;
928
+ readonly foreignKey: (error: unknown) => boolean;
929
+ readonly notNull: (error: unknown) => boolean;
930
+ };
931
+ readonly sqlite: {
932
+ readonly uniqueConstraint: (error: unknown) => boolean;
933
+ readonly foreignKey: (error: unknown) => boolean;
934
+ readonly notNull: (error: unknown) => boolean;
935
+ };
936
+ readonly mssql: {
937
+ readonly uniqueConstraint: (error: unknown) => boolean;
938
+ readonly foreignKey: (error: unknown) => boolean;
939
+ readonly notNull: (error: unknown) => boolean;
940
+ };
941
+ };
254
942
  /**
255
943
  * Check if table exists in the database
256
944
  *
945
+ * @param db - Kysely database instance
946
+ * @param tableName - Name of the table to check
947
+ * @param dialect - Database dialect
948
+ * @param options - Optional schema configuration
949
+ * @returns true if table exists, false otherwise
950
+ *
951
+ * @example
952
+ * // Check in default schema
953
+ * const exists = await tableExists(db, 'users', 'postgres')
954
+ *
257
955
  * @example
258
- * const exists = await tableExists(db, 'users', 'postgres');
956
+ * // Check in specific schema
957
+ * const exists = await tableExists(db, 'users', 'postgres', { schema: 'auth' })
259
958
  */
260
- declare function tableExists(db: Kysely<any>, tableName: string, dialect: Dialect): Promise<boolean>;
959
+ declare function tableExists(db: Kysely<any>, tableName: string, dialect: Dialect, options?: SchemaOptions): Promise<boolean>;
261
960
  /**
262
961
  * Get column names for a table
263
962
  *
963
+ * @param db - Kysely database instance
964
+ * @param tableName - Name of the table
965
+ * @param dialect - Database dialect
966
+ * @param options - Optional schema configuration
967
+ * @returns Array of column names
968
+ *
264
969
  * @example
265
- * const columns = await getTableColumns(db, 'users', 'postgres');
970
+ * const columns = await getTableColumns(db, 'users', 'postgres', { schema: 'auth' })
266
971
  * // ['id', 'name', 'email', 'created_at']
267
972
  */
268
- declare function getTableColumns(db: Kysely<any>, tableName: string, dialect: Dialect): Promise<string[]>;
973
+ declare function getTableColumns(db: Kysely<any>, tableName: string, dialect: Dialect, options?: SchemaOptions): Promise<string[]>;
269
974
  /**
270
- * Get all tables in the database
975
+ * Get all tables in the database/schema
976
+ *
977
+ * @param db - Kysely database instance
978
+ * @param dialect - Database dialect
979
+ * @param options - Optional schema configuration
980
+ * @returns Array of table names
271
981
  *
272
982
  * @example
273
- * const tables = await getTables(db, 'postgres');
274
- * // ['users', 'posts', 'comments']
983
+ * // Get tables in auth schema
984
+ * const tables = await getTables(db, 'postgres', { schema: 'auth' })
985
+ * // ['users', 'sessions', 'tokens']
275
986
  */
276
- declare function getTables(db: Kysely<any>, dialect: Dialect): Promise<string[]>;
987
+ declare function getTables(db: Kysely<any>, dialect: Dialect, options?: SchemaOptions): Promise<string[]>;
277
988
  /**
278
989
  * Escape identifier for SQL (table names, column names, etc.)
279
990
  *
@@ -338,12 +1049,17 @@ declare function isNotNullError(error: unknown, dialect: Dialect): boolean;
338
1049
  */
339
1050
  declare function getDatabaseSize(db: Kysely<any>, dialect: Dialect, databaseName?: string): Promise<number>;
340
1051
  /**
341
- * Truncate all tables in the database (useful for testing)
1052
+ * Truncate all tables in the database/schema (useful for testing)
1053
+ *
1054
+ * @param db - Kysely database instance
1055
+ * @param dialect - Database dialect
1056
+ * @param exclude - Array of table names to exclude
1057
+ * @param options - Optional schema configuration
342
1058
  *
343
1059
  * @example
344
- * // Truncate all tables except migrations
345
- * await truncateAllTables(db, 'postgres', ['kysely_migrations']);
1060
+ * // Truncate all tables in auth schema except migrations
1061
+ * await truncateAllTables(db, 'postgres', ['kysely_migrations'], { schema: 'auth' })
346
1062
  */
347
- declare function truncateAllTables(db: Kysely<any>, dialect: Dialect, exclude?: string[]): Promise<void>;
1063
+ declare function truncateAllTables(db: Kysely<any>, dialect: Dialect, exclude?: string[], options?: SchemaOptions): Promise<void>;
348
1064
 
349
- export { type ConnectionConfig, type DatabaseErrorLike, type DialectAdapter, MSSQLAdapter, MySQLAdapter, PostgresAdapter, SQLiteAdapter, assertValidIdentifier, buildConnectionUrl, createDialectAdapter, escapeIdentifier, formatDate, getAdapter, getCurrentTimestamp, getDatabaseSize, getDefaultPort, getTableColumns, getTables, isForeignKeyError, isNotNullError, isUniqueConstraintError, mssqlAdapter, mysqlAdapter, parseConnectionUrl, postgresAdapter, registerAdapter, sqliteAdapter, tableExists, truncateAllTables, validateIdentifier };
1065
+ export { type AdapterOptions, type ConnectionConfig, type DatabaseErrorLike, type DialectAdapter, type DialectAdapterOptions, type ErrorMatcherConfig, type ExtractedErrorInfo, MSSQLAdapter, type MSSQLAdapterOptions, MySQLAdapter, type MySQLAdapterOptions, PostgresAdapter, type PostgresAdapterOptions, SQLiteAdapter, type SQLiteAdapterOptions, type SchemaCopyOptions, type SchemaOptions, type TenantSchemaConfig, assertValidIdentifier, buildConnectionUrl, createDialectAdapter, createErrorMatcher, createMSSQLAdapter, createMySQLAdapter, createPostgresAdapter, createSQLiteAdapter, errorMatchers, escapeIdentifier, extractErrorInfo, extractTenantIds, filterTenantSchemas, formatDate, getAdapter, getCurrentTimestamp, getDatabaseSize, getDefaultPort, getTableColumns, getTables, getTenantSchemaName, isForeignKeyError, isNotNullError, isTenantSchema, isUniqueConstraintError, mssqlAdapter, mysqlAdapter, parseConnectionUrl, parseTenantSchemaName, postgresAdapter, qualifyTableName, registerAdapter, resolveSchema, sqliteAdapter, tableExists, truncateAllTables, validateIdentifier };