@kysera/dialects 0.7.3 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -10,11 +10,11 @@
10
10
 
11
11
  - ✅ **Zero Runtime Dependencies** - Only peer dependency on Kysely
12
12
  - ✅ **Unified Adapter Interface** - Consistent API across all dialects
13
- - ✅ **Multi-Database Support** - PostgreSQL, MySQL, and SQLite
13
+ - ✅ **Multi-Database Support** - PostgreSQL, MySQL, and SQLite with dialect-specific adapters
14
14
  - ✅ **Error Detection** - Detect unique, foreign key, and not-null constraint violations
15
15
  - ✅ **Connection Utilities** - Parse and build connection URLs
16
16
  - ✅ **Schema Introspection** - Table existence checks, column enumeration, database size
17
- - ✅ **Testing Helpers** - Truncate tables, clean databases
17
+ - ✅ **Testing Helpers** - Truncate tables with recoverable vs critical error handling
18
18
  - ✅ **100% Type Safe** - Full TypeScript support with strict mode
19
19
  - ✅ **Cross-Runtime** - Works on Node.js, Bun, and Deno
20
20
 
@@ -53,7 +53,11 @@ import { getAdapter } from '@kysera/dialects'
53
53
 
54
54
  // Create database connection
55
55
  const db = new Kysely({
56
- dialect: new PostgresDialect({ pool: new Pool({ /* config */ }) })
56
+ dialect: new PostgresDialect({
57
+ pool: new Pool({
58
+ /* config */
59
+ })
60
+ })
57
61
  })
58
62
 
59
63
  // Get dialect adapter
@@ -90,8 +94,8 @@ const exists = await tableExists(db, 'users', 'postgres')
90
94
  const columns = await getTableColumns(db, 'users', 'postgres')
91
95
 
92
96
  // Escape identifiers
93
- const escaped = escapeIdentifier('user-data', 'mysql') // `user-data`
94
- const pgEscaped = escapeIdentifier('user-data', 'postgres') // "user-data"
97
+ const escaped = escapeIdentifier('user-data', 'mysql') // `user-data`
98
+ const pgEscaped = escapeIdentifier('user-data', 'postgres') // "user-data"
95
99
 
96
100
  // Error detection
97
101
  try {
@@ -129,9 +133,9 @@ const url = buildConnectionUrl('postgres', {
129
133
  // 'postgresql://admin:secret@localhost:5432/mydb'
130
134
 
131
135
  // Get default ports
132
- getDefaultPort('postgres') // 5432
133
- getDefaultPort('mysql') // 3306
134
- getDefaultPort('sqlite') // null
136
+ getDefaultPort('postgres') // 5432
137
+ getDefaultPort('mysql') // 3306
138
+ getDefaultPort('sqlite') // null
135
139
  ```
136
140
 
137
141
  ---
@@ -188,18 +192,19 @@ const adapter = postgresAdapter
188
192
  const adapter = new PostgresAdapter()
189
193
 
190
194
  // Adapter methods
191
- adapter.getDefaultPort() // 5432
192
- adapter.getCurrentTimestamp() // 'CURRENT_TIMESTAMP'
193
- adapter.escapeIdentifier('col') // '"col"'
194
- adapter.formatDate(new Date()) // ISO 8601 string
195
+ adapter.getDefaultPort() // 5432
196
+ adapter.getCurrentTimestamp() // 'CURRENT_TIMESTAMP'
197
+ adapter.escapeIdentifier('col') // '"col"'
198
+ adapter.formatDate(new Date()) // ISO 8601 string
195
199
 
196
200
  // PostgreSQL error detection
197
- adapter.isUniqueConstraintError(error) // Code: 23505
198
- adapter.isForeignKeyError(error) // Code: 23503
199
- adapter.isNotNullError(error) // Code: 23502
201
+ adapter.isUniqueConstraintError(error) // Code: 23505
202
+ adapter.isForeignKeyError(error) // Code: 23503
203
+ adapter.isNotNullError(error) // Code: 23502
200
204
  ```
201
205
 
202
206
  **PostgreSQL-specific features:**
207
+
203
208
  - Uses `information_schema.tables` for schema introspection
204
209
  - Filters by `table_schema = 'public'` by default
205
210
  - Supports `pg_database_size()` for database size queries
@@ -212,21 +217,22 @@ import { MySQLAdapter, mysqlAdapter } from '@kysera/dialects'
212
217
 
213
218
  const adapter = mysqlAdapter
214
219
 
215
- adapter.getDefaultPort() // 3306
216
- adapter.getCurrentTimestamp() // 'CURRENT_TIMESTAMP'
217
- adapter.escapeIdentifier('col') // '`col`'
218
- adapter.formatDate(new Date()) // ISO 8601 string
220
+ adapter.getDefaultPort() // 3306
221
+ adapter.getCurrentTimestamp() // 'CURRENT_TIMESTAMP'
222
+ adapter.escapeIdentifier('col') // '`col`'
223
+ adapter.formatDate(new Date()) // ISO 8601 string
219
224
 
220
225
  // MySQL error detection
221
- adapter.isUniqueConstraintError(error) // ER_DUP_ENTRY, ER_DUP_KEY
222
- adapter.isForeignKeyError(error) // ER_NO_REFERENCED_ROW, ER_ROW_IS_REFERENCED
223
- adapter.isNotNullError(error) // ER_BAD_NULL_ERROR, ER_NO_DEFAULT_FOR_FIELD
226
+ adapter.isUniqueConstraintError(error) // ER_DUP_ENTRY, ER_DUP_KEY
227
+ adapter.isForeignKeyError(error) // ER_NO_REFERENCED_ROW, ER_ROW_IS_REFERENCED
228
+ adapter.isNotNullError(error) // ER_BAD_NULL_ERROR, ER_NO_DEFAULT_FOR_FIELD
224
229
  ```
225
230
 
226
231
  **MySQL-specific features:**
232
+
227
233
  - Uses `information_schema.tables` with `table_schema = database()`
228
234
  - Supports backtick identifier escaping
229
- - Error detection via MySQL error codes (ER_* constants)
235
+ - Error detection via MySQL error codes (ER\_\* constants)
230
236
  - Database size queries via `information_schema.tables`
231
237
 
232
238
  ### SQLite Adapter
@@ -236,18 +242,19 @@ import { SQLiteAdapter, sqliteAdapter } from '@kysera/dialects'
236
242
 
237
243
  const adapter = sqliteAdapter
238
244
 
239
- adapter.getDefaultPort() // null (file-based)
240
- adapter.getCurrentTimestamp() // "datetime('now')"
241
- adapter.escapeIdentifier('col') // '"col"'
242
- adapter.formatDate(new Date()) // ISO 8601 string
245
+ adapter.getDefaultPort() // null (file-based)
246
+ adapter.getCurrentTimestamp() // "datetime('now')"
247
+ adapter.escapeIdentifier('col') // '"col"'
248
+ adapter.formatDate(new Date()) // ISO 8601 string
243
249
 
244
250
  // SQLite error detection (message-based)
245
- adapter.isUniqueConstraintError(error) // "UNIQUE constraint failed"
246
- adapter.isForeignKeyError(error) // "FOREIGN KEY constraint failed"
247
- adapter.isNotNullError(error) // "NOT NULL constraint failed"
251
+ adapter.isUniqueConstraintError(error) // "UNIQUE constraint failed"
252
+ adapter.isForeignKeyError(error) // "FOREIGN KEY constraint failed"
253
+ adapter.isNotNullError(error) // "NOT NULL constraint failed"
248
254
  ```
249
255
 
250
256
  **SQLite-specific features:**
257
+
251
258
  - Uses `sqlite_master` for schema introspection
252
259
  - No default port (file-based database)
253
260
  - Error detection via message parsing
@@ -261,8 +268,12 @@ import { registerAdapter, type DialectAdapter } from '@kysera/dialects'
261
268
  class CustomDialectAdapter implements DialectAdapter {
262
269
  readonly dialect = 'custom' as any
263
270
 
264
- getDefaultPort() { return 9999 }
265
- getCurrentTimestamp() { return 'NOW()' }
271
+ getDefaultPort() {
272
+ return 9999
273
+ }
274
+ getCurrentTimestamp() {
275
+ return 'NOW()'
276
+ }
266
277
  // ... implement all required methods
267
278
  }
268
279
 
@@ -319,6 +330,7 @@ const sqliteConfig = parseConnectionUrl('sqlite:///path/to/database.db')
319
330
  ```
320
331
 
321
332
  **Supported URL formats:**
333
+
322
334
  - `postgresql://[user[:password]@][host][:port]/database[?ssl=true]`
323
335
  - `mysql://[user[:password]@][host][:port]/database[?ssl=true]`
324
336
  - `sqlite:///path/to/file.db`
@@ -358,6 +370,7 @@ const sslUrl = buildConnectionUrl('postgres', {
358
370
  ```
359
371
 
360
372
  **Default ports:**
373
+
361
374
  - PostgreSQL: 5432
362
375
  - MySQL: 3306
363
376
  - SQLite: null (file-based)
@@ -367,9 +380,9 @@ const sslUrl = buildConnectionUrl('postgres', {
367
380
  ```typescript
368
381
  import { getDefaultPort } from '@kysera/dialects'
369
382
 
370
- getDefaultPort('postgres') // 5432
371
- getDefaultPort('mysql') // 3306
372
- getDefaultPort('sqlite') // null
383
+ getDefaultPort('postgres') // 5432
384
+ getDefaultPort('mysql') // 3306
385
+ getDefaultPort('sqlite') // null
373
386
  ```
374
387
 
375
388
  ---
@@ -384,10 +397,7 @@ Detect database constraint violations across different dialects with a unified A
384
397
  import { isUniqueConstraintError } from '@kysera/dialects'
385
398
 
386
399
  try {
387
- await db
388
- .insertInto('users')
389
- .values({ email: 'existing@example.com', name: 'John' })
390
- .execute()
400
+ await db.insertInto('users').values({ email: 'existing@example.com', name: 'John' }).execute()
391
401
  } catch (error) {
392
402
  if (isUniqueConstraintError(error, 'postgres')) {
393
403
  console.error('Email already exists')
@@ -398,11 +408,11 @@ try {
398
408
 
399
409
  **Detection criteria:**
400
410
 
401
- | Dialect | Detection Method |
402
- |---------|------------------|
411
+ | Dialect | Detection Method |
412
+ | ---------- | ---------------------------------------------------------- |
403
413
  | PostgreSQL | Error code `23505` or message contains "unique constraint" |
404
- | MySQL | Error code `ER_DUP_ENTRY` or `ER_DUP_KEY` |
405
- | SQLite | Message contains "UNIQUE constraint failed" |
414
+ | MySQL | Error code `ER_DUP_ENTRY` or `ER_DUP_KEY` |
415
+ | SQLite | Message contains "UNIQUE constraint failed" |
406
416
 
407
417
  ### Foreign Key Errors
408
418
 
@@ -410,10 +420,7 @@ try {
410
420
  import { isForeignKeyError } from '@kysera/dialects'
411
421
 
412
422
  try {
413
- await db
414
- .insertInto('posts')
415
- .values({ user_id: 999, title: 'Post', content: '...' })
416
- .execute()
423
+ await db.insertInto('posts').values({ user_id: 999, title: 'Post', content: '...' }).execute()
417
424
  } catch (error) {
418
425
  if (isForeignKeyError(error, 'postgres')) {
419
426
  console.error('User does not exist')
@@ -424,11 +431,11 @@ try {
424
431
 
425
432
  **Detection criteria:**
426
433
 
427
- | Dialect | Detection Method |
428
- |---------|------------------|
434
+ | Dialect | Detection Method |
435
+ | ---------- | --------------------------------------------------------------- |
429
436
  | PostgreSQL | Error code `23503` or message contains "foreign key constraint" |
430
- | MySQL | Error code `ER_NO_REFERENCED_ROW` or `ER_ROW_IS_REFERENCED` |
431
- | SQLite | Message contains "FOREIGN KEY constraint failed" |
437
+ | MySQL | Error code `ER_NO_REFERENCED_ROW` or `ER_ROW_IS_REFERENCED` |
438
+ | SQLite | Message contains "FOREIGN KEY constraint failed" |
432
439
 
433
440
  ### Not-Null Errors
434
441
 
@@ -450,11 +457,11 @@ try {
450
457
 
451
458
  **Detection criteria:**
452
459
 
453
- | Dialect | Detection Method |
454
- |---------|------------------|
460
+ | Dialect | Detection Method |
461
+ | ---------- | ------------------------------------------------------------ |
455
462
  | PostgreSQL | Error code `23502` or message contains "not-null constraint" |
456
- | MySQL | Error code `ER_BAD_NULL_ERROR` or `ER_NO_DEFAULT_FOR_FIELD` |
457
- | SQLite | Message contains "NOT NULL constraint failed" |
463
+ | MySQL | Error code `ER_BAD_NULL_ERROR` or `ER_NO_DEFAULT_FOR_FIELD` |
464
+ | SQLite | Message contains "NOT NULL constraint failed" |
458
465
 
459
466
  ### Adapter-based Error Detection
460
467
 
@@ -525,19 +532,19 @@ console.log(`Database has ${tables.length} tables`)
525
532
  import { escapeIdentifier } from '@kysera/dialects'
526
533
 
527
534
  // PostgreSQL (double quotes)
528
- escapeIdentifier('user-data', 'postgres') // "user-data"
529
- escapeIdentifier('select', 'postgres') // "select"
535
+ escapeIdentifier('user-data', 'postgres') // "user-data"
536
+ escapeIdentifier('select', 'postgres') // "select"
530
537
 
531
538
  // MySQL (backticks)
532
- escapeIdentifier('user-data', 'mysql') // `user-data`
533
- escapeIdentifier('order', 'mysql') // `order`
539
+ escapeIdentifier('user-data', 'mysql') // `user-data`
540
+ escapeIdentifier('order', 'mysql') // `order`
534
541
 
535
542
  // SQLite (double quotes)
536
- escapeIdentifier('user-data', 'sqlite') // "user-data"
543
+ escapeIdentifier('user-data', 'sqlite') // "user-data"
537
544
 
538
545
  // Handles quotes in identifiers
539
- escapeIdentifier('user"data', 'postgres') // "user""data"
540
- escapeIdentifier('user`data', 'mysql') // `user``data`
546
+ escapeIdentifier('user"data', 'postgres') // "user""data"
547
+ escapeIdentifier('user`data', 'mysql') // `user``data`
541
548
  ```
542
549
 
543
550
  ### Timestamp Utilities
@@ -548,13 +555,13 @@ escapeIdentifier('user`data', 'mysql') // `user``data`
548
555
  import { getCurrentTimestamp } from '@kysera/dialects'
549
556
 
550
557
  // PostgreSQL
551
- getCurrentTimestamp('postgres') // 'CURRENT_TIMESTAMP'
558
+ getCurrentTimestamp('postgres') // 'CURRENT_TIMESTAMP'
552
559
 
553
560
  // MySQL
554
- getCurrentTimestamp('mysql') // 'CURRENT_TIMESTAMP'
561
+ getCurrentTimestamp('mysql') // 'CURRENT_TIMESTAMP'
555
562
 
556
563
  // SQLite
557
- getCurrentTimestamp('sqlite') // "datetime('now')"
564
+ getCurrentTimestamp('sqlite') // "datetime('now')"
558
565
 
559
566
  // Usage in queries
560
567
  const timestamp = getCurrentTimestamp('postgres')
@@ -572,9 +579,9 @@ import { formatDate } from '@kysera/dialects'
572
579
  const date = new Date('2024-01-15T10:30:00Z')
573
580
 
574
581
  // All dialects return ISO 8601 format
575
- formatDate(date, 'postgres') // '2024-01-15T10:30:00.000Z'
576
- formatDate(date, 'mysql') // '2024-01-15T10:30:00.000Z'
577
- formatDate(date, 'sqlite') // '2024-01-15T10:30:00.000Z'
582
+ formatDate(date, 'postgres') // '2024-01-15T10:30:00.000Z'
583
+ formatDate(date, 'mysql') // '2024-01-15T10:30:00.000Z'
584
+ formatDate(date, 'sqlite') // '2024-01-15T10:30:00.000Z'
578
585
  ```
579
586
 
580
587
  ### Database Management
@@ -611,7 +618,13 @@ await truncateAllTables(db, 'postgres', ['migrations', 'schema_version'])
611
618
 
612
619
  **Warning:** This permanently deletes all data. Use only in test environments.
613
620
 
621
+ **Error Handling:** The function uses sophisticated error classification:
622
+ - **Recoverable errors:** Table not found, already truncated → Logged as warnings, execution continues
623
+ - **Critical errors:** Permission denied, foreign key violations → Thrown immediately
624
+ - **Unknown errors:** All other errors → Thrown with full error context
625
+
614
626
  **Behavior:**
627
+
615
628
  - PostgreSQL: `TRUNCATE TABLE ... CASCADE`
616
629
  - MySQL: `TRUNCATE TABLE ...`
617
630
  - SQLite: `DELETE FROM ...` (no TRUNCATE support)
@@ -622,11 +635,12 @@ await truncateAllTables(db, 'postgres', ['migrations', 'schema_version'])
622
635
 
623
636
  ### Factory Functions
624
637
 
625
- #### `getAdapter(dialect: DatabaseDialect): DialectAdapter`
638
+ #### `getAdapter(dialect: Dialect): DialectAdapter`
626
639
 
627
640
  Get singleton adapter for specified dialect.
628
641
 
629
642
  **Parameters:**
643
+
630
644
  - `dialect` - `'postgres' | 'mysql' | 'sqlite'`
631
645
 
632
646
  **Returns:** Dialect adapter instance
@@ -635,11 +649,12 @@ Get singleton adapter for specified dialect.
635
649
 
636
650
  ---
637
651
 
638
- #### `createDialectAdapter(dialect: DatabaseDialect): DialectAdapter`
652
+ #### `createDialectAdapter(dialect: Dialect): DialectAdapter`
639
653
 
640
654
  Create new adapter instance.
641
655
 
642
656
  **Parameters:**
657
+
643
658
  - `dialect` - `'postgres' | 'mysql' | 'sqlite'`
644
659
 
645
660
  **Returns:** New dialect adapter instance
@@ -653,6 +668,7 @@ Create new adapter instance.
653
668
  Register custom dialect adapter.
654
669
 
655
670
  **Parameters:**
671
+
656
672
  - `adapter` - Custom adapter implementing `DialectAdapter` interface
657
673
 
658
674
  **Use Case:** Extend with custom database support.
@@ -666,9 +682,11 @@ Register custom dialect adapter.
666
682
  Interface for dialect-specific operations.
667
683
 
668
684
  **Properties:**
669
- - `dialect: DatabaseDialect` - The dialect this adapter handles
685
+
686
+ - `dialect: Dialect` - The dialect this adapter handles
670
687
 
671
688
  **Methods:**
689
+
672
690
  - `getDefaultPort(): number | null` - Get default port for this dialect
673
691
  - `getCurrentTimestamp(): string` - Get SQL expression for current timestamp
674
692
  - `escapeIdentifier(identifier: string): string` - Escape identifier for this dialect
@@ -692,17 +710,19 @@ Interface for dialect-specific operations.
692
710
  Parse connection URL into configuration object.
693
711
 
694
712
  **Parameters:**
713
+
695
714
  - `url` - Database connection URL
696
715
 
697
716
  **Returns:** `ConnectionConfig` object
698
717
 
699
718
  ---
700
719
 
701
- #### `buildConnectionUrl(dialect: DatabaseDialect, config: ConnectionConfig): string`
720
+ #### `buildConnectionUrl(dialect: Dialect, config: ConnectionConfig): string`
702
721
 
703
722
  Build connection URL from configuration.
704
723
 
705
724
  **Parameters:**
725
+
706
726
  - `dialect` - Database dialect
707
727
  - `config` - Connection configuration
708
728
 
@@ -710,11 +730,12 @@ Build connection URL from configuration.
710
730
 
711
731
  ---
712
732
 
713
- #### `getDefaultPort(dialect: DatabaseDialect): number | null`
733
+ #### `getDefaultPort(dialect: Dialect): number | null`
714
734
 
715
735
  Get default port for dialect.
716
736
 
717
737
  **Parameters:**
738
+
718
739
  - `dialect` - Database dialect
719
740
 
720
741
  **Returns:** Port number or null for SQLite
@@ -723,67 +744,67 @@ Get default port for dialect.
723
744
 
724
745
  ### Helper Functions
725
746
 
726
- #### `tableExists(db: Kysely<any>, tableName: string, dialect: DatabaseDialect): Promise<boolean>`
747
+ #### `tableExists(db: Kysely<any>, tableName: string, dialect: Dialect): Promise<boolean>`
727
748
 
728
749
  Check if table exists.
729
750
 
730
751
  ---
731
752
 
732
- #### `getTableColumns(db: Kysely<any>, tableName: string, dialect: DatabaseDialect): Promise<string[]>`
753
+ #### `getTableColumns(db: Kysely<any>, tableName: string, dialect: Dialect): Promise<string[]>`
733
754
 
734
755
  Get column names for a table.
735
756
 
736
757
  ---
737
758
 
738
- #### `getTables(db: Kysely<any>, dialect: DatabaseDialect): Promise<string[]>`
759
+ #### `getTables(db: Kysely<any>, dialect: Dialect): Promise<string[]>`
739
760
 
740
761
  Get all tables in database.
741
762
 
742
763
  ---
743
764
 
744
- #### `escapeIdentifier(identifier: string, dialect: DatabaseDialect): string`
765
+ #### `escapeIdentifier(identifier: string, dialect: Dialect): string`
745
766
 
746
767
  Escape identifier for SQL.
747
768
 
748
769
  ---
749
770
 
750
- #### `getCurrentTimestamp(dialect: DatabaseDialect): string`
771
+ #### `getCurrentTimestamp(dialect: Dialect): string`
751
772
 
752
773
  Get SQL expression for current timestamp.
753
774
 
754
775
  ---
755
776
 
756
- #### `formatDate(date: Date, dialect: DatabaseDialect): string`
777
+ #### `formatDate(date: Date, dialect: Dialect): string`
757
778
 
758
779
  Format date for SQL.
759
780
 
760
781
  ---
761
782
 
762
- #### `isUniqueConstraintError(error: unknown, dialect: DatabaseDialect): boolean`
783
+ #### `isUniqueConstraintError(error: unknown, dialect: Dialect): boolean`
763
784
 
764
785
  Check if error is unique constraint violation.
765
786
 
766
787
  ---
767
788
 
768
- #### `isForeignKeyError(error: unknown, dialect: DatabaseDialect): boolean`
789
+ #### `isForeignKeyError(error: unknown, dialect: Dialect): boolean`
769
790
 
770
791
  Check if error is foreign key violation.
771
792
 
772
793
  ---
773
794
 
774
- #### `isNotNullError(error: unknown, dialect: DatabaseDialect): boolean`
795
+ #### `isNotNullError(error: unknown, dialect: Dialect): boolean`
775
796
 
776
797
  Check if error is not-null violation.
777
798
 
778
799
  ---
779
800
 
780
- #### `getDatabaseSize(db: Kysely<any>, databaseName: string | undefined, dialect: DatabaseDialect): Promise<number>`
801
+ #### `getDatabaseSize(db: Kysely<any>, databaseName: string | undefined, dialect: Dialect): Promise<number>`
781
802
 
782
803
  Get database size in bytes.
783
804
 
784
805
  ---
785
806
 
786
- #### `truncateAllTables(db: Kysely<any>, dialect: DatabaseDialect, exclude?: string[]): Promise<void>`
807
+ #### `truncateAllTables(db: Kysely<any>, dialect: Dialect, exclude?: string[]): Promise<void>`
787
808
 
788
809
  Truncate all tables in database.
789
810
 
@@ -791,9 +812,9 @@ Truncate all tables in database.
791
812
 
792
813
  ### Types
793
814
 
794
- #### `type DatabaseDialect = 'postgres' | 'mysql' | 'sqlite'`
815
+ #### `type Dialect = 'postgres' | 'mysql' | 'sqlite' | 'mssql'`
795
816
 
796
- Supported database dialects.
817
+ Supported database dialects. Re-exported from `@kysera/core`.
797
818
 
798
819
  ---
799
820
 
@@ -833,16 +854,17 @@ interface DatabaseErrorLike {
833
854
 
834
855
  ```typescript
835
856
  // ✅ Good: Works with any dialect
836
- import { getAdapter } from '@kysera/dialects'
857
+ import { getAdapter, type Dialect } from '@kysera/dialects'
837
858
 
838
- function checkSchema(db: Kysely<any>, dialect: DatabaseDialect) {
859
+ function checkSchema(db: Kysely<any>, dialect: Dialect) {
839
860
  const adapter = getAdapter(dialect)
840
861
  return adapter.tableExists(db, 'users')
841
862
  }
842
863
 
843
864
  // ❌ Bad: Hard-coded dialect logic
844
865
  function checkSchema(db: Kysely<any>) {
845
- return db.selectFrom('information_schema.tables')
866
+ return db
867
+ .selectFrom('information_schema.tables')
846
868
  .where('table_name', '=', 'users')
847
869
  .executeTakeFirst()
848
870
  }
@@ -862,10 +884,10 @@ const exists = await adapter.tableExists(db, 'users')
862
884
  ### 3. Centralize Error Handling
863
885
 
864
886
  ```typescript
865
- import { getAdapter } from '@kysera/dialects'
887
+ import { getAdapter, type Dialect } from '@kysera/dialects'
866
888
  import { parseDatabaseError } from '@kysera/core'
867
889
 
868
- async function handleDatabaseError(error: unknown, dialect: DatabaseDialect) {
890
+ async function handleDatabaseError(error: unknown, dialect: Dialect) {
869
891
  const adapter = getAdapter(dialect)
870
892
 
871
893
  if (adapter.isUniqueConstraintError(error)) {
@@ -929,11 +951,11 @@ try {
929
951
  ### 6. Escape Dynamic Identifiers
930
952
 
931
953
  ```typescript
932
- import { escapeIdentifier } from '@kysera/dialects'
954
+ import { escapeIdentifier, type Dialect } from '@kysera/dialects'
933
955
  import { sql } from 'kysely'
934
956
 
935
957
  // ✅ Good: Escape dynamic table/column names
936
- function selectFromTable(tableName: string, dialect: DatabaseDialect) {
958
+ function selectFromTable(tableName: string, dialect: Dialect) {
937
959
  const escaped = escapeIdentifier(tableName, dialect)
938
960
  return db.selectFrom(sql.raw(escaped)).selectAll()
939
961
  }