@kysera/dialects 0.7.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.
@@ -0,0 +1,290 @@
1
+ import { Kysely } from 'kysely';
2
+
3
+ /**
4
+ * @kysera/dialects - Type Definitions
5
+ *
6
+ * Dialect-specific types and interfaces for database operations
7
+ */
8
+
9
+ /**
10
+ * Supported database dialects
11
+ */
12
+ type DatabaseDialect = 'postgres' | 'mysql' | 'sqlite';
13
+ /**
14
+ * Database connection configuration
15
+ */
16
+ interface ConnectionConfig {
17
+ host?: string | undefined;
18
+ port?: number | undefined;
19
+ database: string;
20
+ user?: string | undefined;
21
+ password?: string | undefined;
22
+ ssl?: boolean | undefined;
23
+ }
24
+ /**
25
+ * Interface for dialect-specific operations
26
+ */
27
+ interface DialectAdapter {
28
+ /** The dialect this adapter handles */
29
+ readonly dialect: DatabaseDialect;
30
+ /** Get default port for this dialect */
31
+ getDefaultPort(): number | null;
32
+ /** Get SQL expression for current timestamp */
33
+ getCurrentTimestamp(): string;
34
+ /** Escape identifier for this dialect */
35
+ escapeIdentifier(identifier: string): string;
36
+ /** Format date for this dialect */
37
+ formatDate(date: Date): string;
38
+ /** Check if error is a unique constraint violation */
39
+ isUniqueConstraintError(error: unknown): boolean;
40
+ /** Check if error is a foreign key constraint violation */
41
+ isForeignKeyError(error: unknown): boolean;
42
+ /** Check if error is a not-null constraint violation */
43
+ isNotNullError(error: unknown): boolean;
44
+ /** Check if a table exists in the database */
45
+ tableExists(db: Kysely<any>, tableName: string): Promise<boolean>;
46
+ /** Get column names for a table */
47
+ getTableColumns(db: Kysely<any>, tableName: string): Promise<string[]>;
48
+ /** Get all tables in the database */
49
+ getTables(db: Kysely<any>): Promise<string[]>;
50
+ /** Get database size in bytes */
51
+ getDatabaseSize(db: Kysely<any>, databaseName?: string): Promise<number>;
52
+ /** Truncate a single table */
53
+ truncateTable(db: Kysely<any>, tableName: string): Promise<void>;
54
+ /** Truncate all tables (for testing) */
55
+ truncateAllTables(db: Kysely<any>, exclude?: string[]): Promise<void>;
56
+ }
57
+ /**
58
+ * Error object shape for database error detection
59
+ */
60
+ interface DatabaseErrorLike {
61
+ message?: string;
62
+ code?: string;
63
+ }
64
+
65
+ /**
66
+ * Dialect Adapter Factory
67
+ */
68
+
69
+ /**
70
+ * Get a dialect adapter for the specified dialect
71
+ *
72
+ * @example
73
+ * const adapter = getAdapter('postgres');
74
+ * console.log(adapter.getDefaultPort()); // 5432
75
+ */
76
+ declare function getAdapter(dialect: DatabaseDialect): DialectAdapter;
77
+ /**
78
+ * Create a new dialect adapter instance
79
+ *
80
+ * @example
81
+ * const adapter = createDialectAdapter('mysql');
82
+ */
83
+ declare function createDialectAdapter(dialect: DatabaseDialect): DialectAdapter;
84
+ /**
85
+ * Register a custom dialect adapter
86
+ *
87
+ * @example
88
+ * registerAdapter(customAdapter);
89
+ */
90
+ declare function registerAdapter(adapter: DialectAdapter): void;
91
+
92
+ /**
93
+ * PostgreSQL Dialect Adapter
94
+ */
95
+
96
+ declare class PostgresAdapter implements DialectAdapter {
97
+ readonly dialect: "postgres";
98
+ getDefaultPort(): number;
99
+ getCurrentTimestamp(): string;
100
+ escapeIdentifier(identifier: string): string;
101
+ formatDate(date: Date): string;
102
+ isUniqueConstraintError(error: unknown): boolean;
103
+ isForeignKeyError(error: unknown): boolean;
104
+ isNotNullError(error: unknown): boolean;
105
+ tableExists(db: Kysely<any>, tableName: string): Promise<boolean>;
106
+ getTableColumns(db: Kysely<any>, tableName: string): Promise<string[]>;
107
+ getTables(db: Kysely<any>): Promise<string[]>;
108
+ getDatabaseSize(db: Kysely<any>, databaseName?: string): Promise<number>;
109
+ truncateTable(db: Kysely<any>, tableName: string): Promise<void>;
110
+ truncateAllTables(db: Kysely<any>, exclude?: string[]): Promise<void>;
111
+ }
112
+ declare const postgresAdapter: PostgresAdapter;
113
+
114
+ /**
115
+ * MySQL Dialect Adapter
116
+ */
117
+
118
+ declare class MySQLAdapter implements DialectAdapter {
119
+ readonly dialect: "mysql";
120
+ getDefaultPort(): number;
121
+ getCurrentTimestamp(): string;
122
+ escapeIdentifier(identifier: string): string;
123
+ formatDate(date: Date): string;
124
+ isUniqueConstraintError(error: unknown): boolean;
125
+ isForeignKeyError(error: unknown): boolean;
126
+ isNotNullError(error: unknown): boolean;
127
+ tableExists(db: Kysely<any>, tableName: string): Promise<boolean>;
128
+ getTableColumns(db: Kysely<any>, tableName: string): Promise<string[]>;
129
+ getTables(db: Kysely<any>): Promise<string[]>;
130
+ getDatabaseSize(db: Kysely<any>, databaseName?: string): Promise<number>;
131
+ truncateTable(db: Kysely<any>, tableName: string): Promise<void>;
132
+ truncateAllTables(db: Kysely<any>, exclude?: string[]): Promise<void>;
133
+ }
134
+ declare const mysqlAdapter: MySQLAdapter;
135
+
136
+ /**
137
+ * SQLite Dialect Adapter
138
+ */
139
+
140
+ declare class SQLiteAdapter implements DialectAdapter {
141
+ readonly dialect: "sqlite";
142
+ getDefaultPort(): null;
143
+ getCurrentTimestamp(): string;
144
+ escapeIdentifier(identifier: string): string;
145
+ formatDate(date: Date): string;
146
+ isUniqueConstraintError(error: unknown): boolean;
147
+ isForeignKeyError(error: unknown): boolean;
148
+ isNotNullError(error: unknown): boolean;
149
+ tableExists(db: Kysely<any>, tableName: string): Promise<boolean>;
150
+ getTableColumns(db: Kysely<any>, tableName: string): Promise<string[]>;
151
+ getTables(db: Kysely<any>): Promise<string[]>;
152
+ getDatabaseSize(_db: Kysely<any>, _databaseName?: string): Promise<number>;
153
+ truncateTable(db: Kysely<any>, tableName: string): Promise<void>;
154
+ truncateAllTables(db: Kysely<any>, exclude?: string[]): Promise<void>;
155
+ }
156
+ declare const sqliteAdapter: SQLiteAdapter;
157
+
158
+ /**
159
+ * Connection URL utilities
160
+ */
161
+
162
+ /**
163
+ * Parse database connection URL into ConnectionConfig
164
+ *
165
+ * @example
166
+ * const config = parseConnectionUrl('postgresql://user:pass@localhost:5432/mydb?ssl=true');
167
+ * // { host: 'localhost', port: 5432, database: 'mydb', user: 'user', password: 'pass', ssl: true }
168
+ */
169
+ declare function parseConnectionUrl(url: string): ConnectionConfig;
170
+ /**
171
+ * Build connection URL from config
172
+ *
173
+ * @example
174
+ * const url = buildConnectionUrl('postgres', { host: 'localhost', database: 'mydb' });
175
+ * // 'postgresql://localhost:5432/mydb'
176
+ */
177
+ declare function buildConnectionUrl(dialect: DatabaseDialect, config: ConnectionConfig): string;
178
+ /**
179
+ * Get default port for a dialect
180
+ *
181
+ * @example
182
+ * getDefaultPort('postgres') // 5432
183
+ * getDefaultPort('mysql') // 3306
184
+ * getDefaultPort('sqlite') // null
185
+ */
186
+ declare function getDefaultPort(dialect: DatabaseDialect): number | null;
187
+
188
+ /**
189
+ * Dialect Helper Functions
190
+ *
191
+ * Standalone helper functions that accept dialect as parameter
192
+ * for backward compatibility with existing code.
193
+ */
194
+
195
+ /**
196
+ * Check if table exists in the database
197
+ *
198
+ * @example
199
+ * const exists = await tableExists(db, 'users', 'postgres');
200
+ */
201
+ declare function tableExists(db: Kysely<any>, tableName: string, dialect: DatabaseDialect): Promise<boolean>;
202
+ /**
203
+ * Get column names for a table
204
+ *
205
+ * @example
206
+ * const columns = await getTableColumns(db, 'users', 'postgres');
207
+ * // ['id', 'name', 'email', 'created_at']
208
+ */
209
+ declare function getTableColumns(db: Kysely<any>, tableName: string, dialect: DatabaseDialect): Promise<string[]>;
210
+ /**
211
+ * Get all tables in the database
212
+ *
213
+ * @example
214
+ * const tables = await getTables(db, 'postgres');
215
+ * // ['users', 'posts', 'comments']
216
+ */
217
+ declare function getTables(db: Kysely<any>, dialect: DatabaseDialect): Promise<string[]>;
218
+ /**
219
+ * Escape identifier for SQL (table names, column names, etc.)
220
+ *
221
+ * @example
222
+ * escapeIdentifier('my-table', 'postgres') // '"my-table"'
223
+ * escapeIdentifier('my-table', 'mysql') // '`my-table`'
224
+ */
225
+ declare function escapeIdentifier(identifier: string, dialect: DatabaseDialect): string;
226
+ /**
227
+ * Get SQL expression for current timestamp
228
+ *
229
+ * @example
230
+ * getCurrentTimestamp('postgres') // 'CURRENT_TIMESTAMP'
231
+ * getCurrentTimestamp('sqlite') // "datetime('now')"
232
+ */
233
+ declare function getCurrentTimestamp(dialect: DatabaseDialect): string;
234
+ /**
235
+ * Format date for database insertion
236
+ *
237
+ * @example
238
+ * formatDate(new Date(), 'postgres') // '2024-01-15T10:30:00.000Z'
239
+ * formatDate(new Date(), 'mysql') // '2024-01-15 10:30:00'
240
+ */
241
+ declare function formatDate(date: Date, dialect: DatabaseDialect): string;
242
+ /**
243
+ * Check if error is a unique constraint violation
244
+ *
245
+ * @example
246
+ * try {
247
+ * await db.insertInto('users').values({ email: 'duplicate@example.com' }).execute();
248
+ * } catch (error) {
249
+ * if (isUniqueConstraintError(error, 'postgres')) {
250
+ * console.log('Email already exists');
251
+ * }
252
+ * }
253
+ */
254
+ declare function isUniqueConstraintError(error: unknown, dialect: DatabaseDialect): boolean;
255
+ /**
256
+ * Check if error is a foreign key constraint violation
257
+ *
258
+ * @example
259
+ * if (isForeignKeyError(error, 'mysql')) {
260
+ * console.log('Referenced row does not exist');
261
+ * }
262
+ */
263
+ declare function isForeignKeyError(error: unknown, dialect: DatabaseDialect): boolean;
264
+ /**
265
+ * Check if error is a not-null constraint violation
266
+ *
267
+ * @example
268
+ * if (isNotNullError(error, 'sqlite')) {
269
+ * console.log('Required field is missing');
270
+ * }
271
+ */
272
+ declare function isNotNullError(error: unknown, dialect: DatabaseDialect): boolean;
273
+ /**
274
+ * Get database size in bytes
275
+ *
276
+ * @example
277
+ * const size = await getDatabaseSize(db, 'postgres');
278
+ * console.log(`Database size: ${size} bytes`);
279
+ */
280
+ declare function getDatabaseSize(db: Kysely<any>, dialect: DatabaseDialect, databaseName?: string): Promise<number>;
281
+ /**
282
+ * Truncate all tables in the database (useful for testing)
283
+ *
284
+ * @example
285
+ * // Truncate all tables except migrations
286
+ * await truncateAllTables(db, 'postgres', ['kysely_migrations']);
287
+ */
288
+ declare function truncateAllTables(db: Kysely<any>, dialect: DatabaseDialect, exclude?: string[]): Promise<void>;
289
+
290
+ export { type ConnectionConfig, type DatabaseDialect, type DatabaseErrorLike, type DialectAdapter, MySQLAdapter, PostgresAdapter, SQLiteAdapter, buildConnectionUrl, createDialectAdapter, escapeIdentifier, formatDate, getAdapter, getCurrentTimestamp, getDatabaseSize, getDefaultPort, getTableColumns, getTables, isForeignKeyError, isNotNullError, isUniqueConstraintError, mysqlAdapter, parseConnectionUrl, postgresAdapter, registerAdapter, sqliteAdapter, tableExists, truncateAllTables };
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ import {sql}from'kysely';var l=class{dialect="postgres";getDefaultPort(){return 5432}getCurrentTimestamp(){return "CURRENT_TIMESTAMP"}escapeIdentifier(e){return `"${e.replace(/"/g,'""')}"`}formatDate(e){return e.toISOString()}isUniqueConstraintError(e){let t=e,r=t.message?.toLowerCase()||"";return (t.code||"")==="23505"||r.includes("unique constraint")}isForeignKeyError(e){let t=e,r=t.message?.toLowerCase()||"";return (t.code||"")==="23503"||r.includes("foreign key constraint")}isNotNullError(e){let t=e,r=t.message?.toLowerCase()||"";return (t.code||"")==="23502"||r.includes("not-null constraint")}async tableExists(e,t){try{return !!await e.selectFrom("information_schema.tables").select("table_name").where("table_name","=",t).where("table_schema","=","public").executeTakeFirst()}catch{return false}}async getTableColumns(e,t){try{return (await e.selectFrom("information_schema.columns").select("column_name").where("table_name","=",t).where("table_schema","=","public").execute()).map(s=>s.column_name)}catch{return []}}async getTables(e){try{return (await e.selectFrom("information_schema.tables").select("table_name").where("table_schema","=","public").where("table_type","=","BASE TABLE").execute()).map(r=>r.table_name)}catch{return []}}async getDatabaseSize(e,t){try{return (await sql.raw(`SELECT pg_database_size(${t?`'${t}'`:"current_database()"}) as size`).execute(e).then(s=>s.rows?.[0]))?.size||0}catch{return 0}}async truncateTable(e,t){try{await sql.raw(`TRUNCATE TABLE ${this.escapeIdentifier(t)} RESTART IDENTITY CASCADE`).execute(e);}catch{}}async truncateAllTables(e,t=[]){let r=await this.getTables(e);for(let s of r)t.includes(s)||await this.truncateTable(e,s);}},m=new l;var c=class{dialect="mysql";getDefaultPort(){return 3306}getCurrentTimestamp(){return "CURRENT_TIMESTAMP"}escapeIdentifier(e){return `\`${e.replace(/`/g,"``")}\``}formatDate(e){return e.toISOString().slice(0,19).replace("T"," ")}isUniqueConstraintError(e){let t=e,r=t.message?.toLowerCase()||"",s=t.code||"";return s==="ER_DUP_ENTRY"||s==="1062"||r.includes("duplicate entry")}isForeignKeyError(e){let r=e.code||"";return r==="ER_ROW_IS_REFERENCED"||r==="1451"||r==="ER_NO_REFERENCED_ROW"||r==="1452"}isNotNullError(e){let r=e.code||"";return r==="ER_BAD_NULL_ERROR"||r==="1048"}async tableExists(e,t){try{return !!await e.selectFrom("information_schema.tables").select("table_name").where("table_name","=",t).where("table_schema","=",sql`DATABASE()`).executeTakeFirst()}catch{return false}}async getTableColumns(e,t){try{return (await e.selectFrom("information_schema.columns").select("column_name").where("table_name","=",t).where("table_schema","=",sql`DATABASE()`).execute()).map(s=>s.column_name)}catch{return []}}async getTables(e){try{return (await e.selectFrom("information_schema.tables").select("table_name").where("table_schema","=",sql`DATABASE()`).where("table_type","=","BASE TABLE").execute()).map(r=>r.table_name)}catch{return []}}async getDatabaseSize(e,t){try{let r=t||await sql.raw("SELECT DATABASE() as name").execute(e).then(i=>i.rows?.[0]?.name);return (await sql.raw(`SELECT SUM(data_length + index_length) as size FROM information_schema.tables WHERE table_schema = '${r}'`).execute(e).then(i=>i.rows?.[0]))?.size||0}catch{return 0}}async truncateTable(e,t){try{await sql.raw("SET FOREIGN_KEY_CHECKS = 0").execute(e),await sql.raw(`TRUNCATE TABLE ${this.escapeIdentifier(t)}`).execute(e),await sql.raw("SET FOREIGN_KEY_CHECKS = 1").execute(e);}catch{try{await sql.raw("SET FOREIGN_KEY_CHECKS = 1").execute(e);}catch{}}}async truncateAllTables(e,t=[]){let r=await this.getTables(e);for(let s of r)t.includes(s)||await this.truncateTable(e,s);}},y=new c;var u=class{dialect="sqlite";getDefaultPort(){return null}getCurrentTimestamp(){return "datetime('now')"}escapeIdentifier(e){return `"${e.replace(/"/g,'""')}"`}formatDate(e){return e.toISOString()}isUniqueConstraintError(e){return (e.message?.toLowerCase()||"").includes("unique constraint failed")}isForeignKeyError(e){return (e.message?.toLowerCase()||"").includes("foreign key constraint failed")}isNotNullError(e){return (e.message?.toLowerCase()||"").includes("not null constraint failed")}async tableExists(e,t){try{return !!await e.selectFrom("sqlite_master").select("name").where("type","=","table").where("name","=",t).executeTakeFirst()}catch{return false}}async getTableColumns(e,t){try{return (await sql.raw(`PRAGMA table_info(${t})`).execute(e)).rows.map(s=>s.name)}catch{return []}}async getTables(e){try{return (await e.selectFrom("sqlite_master").select("name").where("type","=","table").where("name","not like","sqlite_%").execute()).map(r=>r.name)}catch{return []}}async getDatabaseSize(e,t){return 0}async truncateTable(e,t){try{await e.deleteFrom(t).execute();}catch{}}async truncateAllTables(e,t=[]){let r=await this.getTables(e);for(let s of r)t.includes(s)||await this.truncateTable(e,s);}},p=new u;var D={postgres:m,mysql:y,sqlite:p};function n(a){let e=D[a];if(!e)throw new Error(`Unknown dialect: ${a}. Supported: postgres, mysql, sqlite`);return e}function w(a){switch(a){case "postgres":return new l;case "mysql":return new c;case "sqlite":return new u;default:throw new Error(`Unknown dialect: ${a}. Supported: postgres, mysql, sqlite`)}}function f(a){D[a.dialect]=a;}function h(a){let e=new URL(a);return {host:e.hostname,port:e.port?parseInt(e.port):void 0,database:e.pathname.slice(1),user:e.username||void 0,password:e.password||void 0,ssl:e.searchParams.get("ssl")==="true"||e.searchParams.get("sslmode")==="require"}}function A(a,e){let t=a==="postgres"?"postgresql":a,r=e.user?e.password?`${e.user}:${e.password}@`:`${e.user}@`:"",s=e.host||"localhost",i=e.port||n(a).getDefaultPort(),b=e.database,g=i?`${t}://${r}${s}:${i}/${b}`:`${t}://${r}${s}/${b}`;return e.ssl&&(g+="?ssl=true"),g}function T(a){return n(a).getDefaultPort()}async function _(a,e,t){return n(t).tableExists(a,e)}async function x(a,e,t){return n(t).getTableColumns(a,e)}async function C(a,e){return n(e).getTables(a)}function K(a,e){return n(e).escapeIdentifier(a)}function k(a){return n(a).getCurrentTimestamp()}function P(a,e){return n(e).formatDate(a)}function S(a,e){return n(e).isUniqueConstraintError(a)}function q(a,e){return n(e).isForeignKeyError(a)}function L(a,e){return n(e).isNotNullError(a)}async function R(a,e,t){return n(e).getDatabaseSize(a,t)}async function N(a,e,t=[]){return n(e).truncateAllTables(a,t)}
2
+ export{c as MySQLAdapter,l as PostgresAdapter,u as SQLiteAdapter,A as buildConnectionUrl,w as createDialectAdapter,K as escapeIdentifier,P as formatDate,n as getAdapter,k as getCurrentTimestamp,R as getDatabaseSize,T as getDefaultPort,x as getTableColumns,C as getTables,q as isForeignKeyError,L as isNotNullError,S as isUniqueConstraintError,y as mysqlAdapter,h as parseConnectionUrl,m as postgresAdapter,f as registerAdapter,p as sqliteAdapter,_ as tableExists,N as truncateAllTables};//# sourceMappingURL=index.js.map
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/adapters/postgres.ts","../src/adapters/mysql.ts","../src/adapters/sqlite.ts","../src/factory.ts","../src/connection.ts","../src/helpers.ts"],"names":["PostgresAdapter","identifier","date","error","e","message","db","tableName","r","databaseName","sql","exclude","tables","table","postgresAdapter","MySQLAdapter","code","dbName","mysqlAdapter","SQLiteAdapter","_db","_databaseName","sqliteAdapter","adapters","getAdapter","dialect","adapter","createDialectAdapter","registerAdapter","parseConnectionUrl","url","parsed","buildConnectionUrl","config","protocol","auth","host","port","database","getDefaultPort","tableExists","getTableColumns","getTables","escapeIdentifier","getCurrentTimestamp","formatDate","isUniqueConstraintError","isForeignKeyError","isNotNullError","getDatabaseSize","truncateAllTables"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * PostgreSQL Dialect Adapter\n */\n\nimport type { Kysely } from 'kysely';\nimport { sql } from 'kysely';\nimport type { DialectAdapter, DatabaseErrorLike } from '../types.js';\n\nexport class PostgresAdapter implements DialectAdapter {\n readonly dialect = 'postgres' as const;\n\n getDefaultPort(): number {\n return 5432;\n }\n\n getCurrentTimestamp(): string {\n return 'CURRENT_TIMESTAMP';\n }\n\n escapeIdentifier(identifier: string): string {\n return `\"${identifier.replace(/\"/g, '\"\"')}\"`;\n }\n\n formatDate(date: Date): string {\n return date.toISOString();\n }\n\n isUniqueConstraintError(error: unknown): boolean {\n const e = error as DatabaseErrorLike;\n const message = e.message?.toLowerCase() || '';\n const code = e.code || '';\n return code === '23505' || message.includes('unique constraint');\n }\n\n isForeignKeyError(error: unknown): boolean {\n const e = error as DatabaseErrorLike;\n const message = e.message?.toLowerCase() || '';\n const code = e.code || '';\n return code === '23503' || message.includes('foreign key constraint');\n }\n\n isNotNullError(error: unknown): boolean {\n const e = error as DatabaseErrorLike;\n const message = e.message?.toLowerCase() || '';\n const code = e.code || '';\n return code === '23502' || message.includes('not-null constraint');\n }\n\n async tableExists(db: Kysely<any>, tableName: string): Promise<boolean> {\n try {\n const result = await db\n .selectFrom('information_schema.tables')\n .select('table_name')\n .where('table_name', '=', tableName)\n .where('table_schema', '=', 'public')\n .executeTakeFirst();\n return !!result;\n } catch {\n return false;\n }\n }\n\n async getTableColumns(db: Kysely<any>, tableName: string): Promise<string[]> {\n try {\n const results = await db\n .selectFrom('information_schema.columns')\n .select('column_name')\n .where('table_name', '=', tableName)\n .where('table_schema', '=', 'public')\n .execute();\n return results.map((r) => r.column_name as string);\n } catch {\n return [];\n }\n }\n\n async getTables(db: Kysely<any>): Promise<string[]> {\n try {\n const results = await db\n .selectFrom('information_schema.tables')\n .select('table_name')\n .where('table_schema', '=', 'public')\n .where('table_type', '=', 'BASE TABLE')\n .execute();\n return results.map((r) => r.table_name as string);\n } catch {\n return [];\n }\n }\n\n async getDatabaseSize(db: Kysely<any>, databaseName?: string): Promise<number> {\n try {\n const result = await sql\n .raw(`SELECT pg_database_size(${databaseName ? `'${databaseName}'` : 'current_database()'}) as size`)\n .execute(db)\n .then((r) => r.rows?.[0]);\n return (result as { size?: number })?.size || 0;\n } catch {\n return 0;\n }\n }\n\n async truncateTable(db: Kysely<any>, tableName: string): Promise<void> {\n try {\n await sql.raw(`TRUNCATE TABLE ${this.escapeIdentifier(tableName)} RESTART IDENTITY CASCADE`).execute(db);\n } catch {\n // Ignore errors for tables that might not exist or have constraints\n }\n }\n\n async truncateAllTables(db: Kysely<any>, exclude: string[] = []): Promise<void> {\n const tables = await this.getTables(db);\n for (const table of tables) {\n if (!exclude.includes(table)) {\n await this.truncateTable(db, table);\n }\n }\n }\n}\n\nexport const postgresAdapter = new PostgresAdapter();\n","/**\n * MySQL Dialect Adapter\n */\n\nimport type { Kysely } from 'kysely';\nimport { sql } from 'kysely';\nimport type { DialectAdapter, DatabaseErrorLike } from '../types.js';\n\nexport class MySQLAdapter implements DialectAdapter {\n readonly dialect = 'mysql' as const;\n\n getDefaultPort(): number {\n return 3306;\n }\n\n getCurrentTimestamp(): string {\n return 'CURRENT_TIMESTAMP';\n }\n\n escapeIdentifier(identifier: string): string {\n return `\\`${identifier.replace(/`/g, '``')}\\``;\n }\n\n formatDate(date: Date): string {\n // MySQL datetime format: YYYY-MM-DD HH:MM:SS\n return date.toISOString().slice(0, 19).replace('T', ' ');\n }\n\n isUniqueConstraintError(error: unknown): boolean {\n const e = error as DatabaseErrorLike;\n const message = e.message?.toLowerCase() || '';\n const code = e.code || '';\n return code === 'ER_DUP_ENTRY' || code === '1062' || message.includes('duplicate entry');\n }\n\n isForeignKeyError(error: unknown): boolean {\n const e = error as DatabaseErrorLike;\n const code = e.code || '';\n return (\n code === 'ER_ROW_IS_REFERENCED' ||\n code === '1451' ||\n code === 'ER_NO_REFERENCED_ROW' ||\n code === '1452'\n );\n }\n\n isNotNullError(error: unknown): boolean {\n const e = error as DatabaseErrorLike;\n const code = e.code || '';\n return code === 'ER_BAD_NULL_ERROR' || code === '1048';\n }\n\n async tableExists(db: Kysely<any>, tableName: string): Promise<boolean> {\n try {\n const result = await db\n .selectFrom('information_schema.tables')\n .select('table_name')\n .where('table_name', '=', tableName)\n .where('table_schema', '=', sql`DATABASE()`)\n .executeTakeFirst();\n return !!result;\n } catch {\n return false;\n }\n }\n\n async getTableColumns(db: Kysely<any>, tableName: string): Promise<string[]> {\n try {\n const results = await db\n .selectFrom('information_schema.columns')\n .select('column_name')\n .where('table_name', '=', tableName)\n .where('table_schema', '=', sql`DATABASE()`)\n .execute();\n return results.map((r) => r.column_name as string);\n } catch {\n return [];\n }\n }\n\n async getTables(db: Kysely<any>): Promise<string[]> {\n try {\n const results = await db\n .selectFrom('information_schema.tables')\n .select('table_name')\n .where('table_schema', '=', sql`DATABASE()`)\n .where('table_type', '=', 'BASE TABLE')\n .execute();\n return results.map((r) => r.table_name as string);\n } catch {\n return [];\n }\n }\n\n async getDatabaseSize(db: Kysely<any>, databaseName?: string): Promise<number> {\n try {\n const dbName =\n databaseName ||\n (await sql\n .raw('SELECT DATABASE() as name')\n .execute(db)\n .then((r) => (r.rows?.[0] as { name?: string })?.name));\n\n const result = await sql\n .raw(\n `SELECT SUM(data_length + index_length) as size FROM information_schema.tables WHERE table_schema = '${dbName}'`\n )\n .execute(db)\n .then((r) => r.rows?.[0]);\n\n return (result as { size?: number })?.size || 0;\n } catch {\n return 0;\n }\n }\n\n async truncateTable(db: Kysely<any>, tableName: string): Promise<void> {\n try {\n // Temporarily disable foreign key checks\n await sql.raw('SET FOREIGN_KEY_CHECKS = 0').execute(db);\n await sql.raw(`TRUNCATE TABLE ${this.escapeIdentifier(tableName)}`).execute(db);\n await sql.raw('SET FOREIGN_KEY_CHECKS = 1').execute(db);\n } catch {\n // Re-enable foreign key checks even on error\n try {\n await sql.raw('SET FOREIGN_KEY_CHECKS = 1').execute(db);\n } catch {\n // Ignore\n }\n }\n }\n\n async truncateAllTables(db: Kysely<any>, exclude: string[] = []): Promise<void> {\n const tables = await this.getTables(db);\n for (const table of tables) {\n if (!exclude.includes(table)) {\n await this.truncateTable(db, table);\n }\n }\n }\n}\n\nexport const mysqlAdapter = new MySQLAdapter();\n","/**\n * SQLite Dialect Adapter\n */\n\nimport type { Kysely } from 'kysely';\nimport { sql } from 'kysely';\nimport type { DialectAdapter, DatabaseErrorLike } from '../types.js';\n\nexport class SQLiteAdapter implements DialectAdapter {\n readonly dialect = 'sqlite' as const;\n\n getDefaultPort(): null {\n // SQLite is file-based, no port\n return null;\n }\n\n getCurrentTimestamp(): string {\n return \"datetime('now')\";\n }\n\n escapeIdentifier(identifier: string): string {\n return `\"${identifier.replace(/\"/g, '\"\"')}\"`;\n }\n\n formatDate(date: Date): string {\n return date.toISOString();\n }\n\n isUniqueConstraintError(error: unknown): boolean {\n const e = error as DatabaseErrorLike;\n const message = e.message?.toLowerCase() || '';\n return message.includes('unique constraint failed');\n }\n\n isForeignKeyError(error: unknown): boolean {\n const e = error as DatabaseErrorLike;\n const message = e.message?.toLowerCase() || '';\n return message.includes('foreign key constraint failed');\n }\n\n isNotNullError(error: unknown): boolean {\n const e = error as DatabaseErrorLike;\n const message = e.message?.toLowerCase() || '';\n return message.includes('not null constraint failed');\n }\n\n async tableExists(db: Kysely<any>, tableName: string): Promise<boolean> {\n try {\n const result = await db\n .selectFrom('sqlite_master')\n .select('name')\n .where('type', '=', 'table')\n .where('name', '=', tableName)\n .executeTakeFirst();\n return !!result;\n } catch {\n return false;\n }\n }\n\n async getTableColumns(db: Kysely<any>, tableName: string): Promise<string[]> {\n try {\n const results = await sql.raw(`PRAGMA table_info(${tableName})`).execute(db);\n return (results.rows as Array<{ name: string }>).map((r) => r.name);\n } catch {\n return [];\n }\n }\n\n async getTables(db: Kysely<any>): Promise<string[]> {\n try {\n const results = await db\n .selectFrom('sqlite_master')\n .select('name')\n .where('type', '=', 'table')\n .where('name', 'not like', 'sqlite_%')\n .execute();\n return results.map((r) => r.name as string);\n } catch {\n return [];\n }\n }\n\n async getDatabaseSize(_db: Kysely<any>, _databaseName?: string): Promise<number> {\n // SQLite database size requires file system access\n // which is not available in a cross-runtime way\n return 0;\n }\n\n async truncateTable(db: Kysely<any>, tableName: string): Promise<void> {\n try {\n // SQLite doesn't support TRUNCATE, use DELETE instead\n await db.deleteFrom(tableName as any).execute();\n } catch {\n // Ignore errors for tables that might not exist\n }\n }\n\n async truncateAllTables(db: Kysely<any>, exclude: string[] = []): Promise<void> {\n const tables = await this.getTables(db);\n for (const table of tables) {\n if (!exclude.includes(table)) {\n await this.truncateTable(db, table);\n }\n }\n }\n}\n\nexport const sqliteAdapter = new SQLiteAdapter();\n","/**\n * Dialect Adapter Factory\n */\n\nimport type { DatabaseDialect, DialectAdapter } from './types.js';\nimport { PostgresAdapter, postgresAdapter } from './adapters/postgres.js';\nimport { MySQLAdapter, mysqlAdapter } from './adapters/mysql.js';\nimport { SQLiteAdapter, sqliteAdapter } from './adapters/sqlite.js';\n\nconst adapters: Record<DatabaseDialect, DialectAdapter> = {\n postgres: postgresAdapter,\n mysql: mysqlAdapter,\n sqlite: sqliteAdapter,\n};\n\n/**\n * Get a dialect adapter for the specified dialect\n *\n * @example\n * const adapter = getAdapter('postgres');\n * console.log(adapter.getDefaultPort()); // 5432\n */\nexport function getAdapter(dialect: DatabaseDialect): DialectAdapter {\n const adapter = adapters[dialect];\n if (!adapter) {\n throw new Error(`Unknown dialect: ${dialect}. Supported: postgres, mysql, sqlite`);\n }\n return adapter;\n}\n\n/**\n * Create a new dialect adapter instance\n *\n * @example\n * const adapter = createDialectAdapter('mysql');\n */\nexport function createDialectAdapter(dialect: DatabaseDialect): DialectAdapter {\n switch (dialect) {\n case 'postgres':\n return new PostgresAdapter();\n case 'mysql':\n return new MySQLAdapter();\n case 'sqlite':\n return new SQLiteAdapter();\n default:\n throw new Error(`Unknown dialect: ${dialect}. Supported: postgres, mysql, sqlite`);\n }\n}\n\n/**\n * Register a custom dialect adapter\n *\n * @example\n * registerAdapter(customAdapter);\n */\nexport function registerAdapter(adapter: DialectAdapter): void {\n adapters[adapter.dialect] = adapter;\n}\n","/**\n * Connection URL utilities\n */\n\nimport type { DatabaseDialect, ConnectionConfig } from './types.js';\nimport { getAdapter } from './factory.js';\n\n/**\n * Parse database connection URL into ConnectionConfig\n *\n * @example\n * const config = parseConnectionUrl('postgresql://user:pass@localhost:5432/mydb?ssl=true');\n * // { host: 'localhost', port: 5432, database: 'mydb', user: 'user', password: 'pass', ssl: true }\n */\nexport function parseConnectionUrl(url: string): ConnectionConfig {\n const parsed = new URL(url);\n\n return {\n host: parsed.hostname,\n port: parsed.port ? parseInt(parsed.port) : undefined,\n database: parsed.pathname.slice(1),\n user: parsed.username || undefined,\n password: parsed.password || undefined,\n ssl: parsed.searchParams.get('ssl') === 'true' || parsed.searchParams.get('sslmode') === 'require',\n };\n}\n\n/**\n * Build connection URL from config\n *\n * @example\n * const url = buildConnectionUrl('postgres', { host: 'localhost', database: 'mydb' });\n * // 'postgresql://localhost:5432/mydb'\n */\nexport function buildConnectionUrl(dialect: DatabaseDialect, config: ConnectionConfig): string {\n const protocol = dialect === 'postgres' ? 'postgresql' : dialect;\n const auth = config.user\n ? config.password\n ? `${config.user}:${config.password}@`\n : `${config.user}@`\n : '';\n\n const host = config.host || 'localhost';\n const port = config.port || getAdapter(dialect).getDefaultPort();\n const database = config.database;\n\n let url = port ? `${protocol}://${auth}${host}:${port}/${database}` : `${protocol}://${auth}${host}/${database}`;\n\n if (config.ssl) {\n url += '?ssl=true';\n }\n\n return url;\n}\n\n/**\n * Get default port for a dialect\n *\n * @example\n * getDefaultPort('postgres') // 5432\n * getDefaultPort('mysql') // 3306\n * getDefaultPort('sqlite') // null\n */\nexport function getDefaultPort(dialect: DatabaseDialect): number | null {\n return getAdapter(dialect).getDefaultPort();\n}\n","/**\n * Dialect Helper Functions\n *\n * Standalone helper functions that accept dialect as parameter\n * for backward compatibility with existing code.\n */\n\nimport type { Kysely } from 'kysely';\nimport type { DatabaseDialect } from './types.js';\nimport { getAdapter } from './factory.js';\n\n/**\n * Check if table exists in the database\n *\n * @example\n * const exists = await tableExists(db, 'users', 'postgres');\n */\nexport async function tableExists(db: Kysely<any>, tableName: string, dialect: DatabaseDialect): Promise<boolean> {\n return getAdapter(dialect).tableExists(db, tableName);\n}\n\n/**\n * Get column names for a table\n *\n * @example\n * const columns = await getTableColumns(db, 'users', 'postgres');\n * // ['id', 'name', 'email', 'created_at']\n */\nexport async function getTableColumns(\n db: Kysely<any>,\n tableName: string,\n dialect: DatabaseDialect\n): Promise<string[]> {\n return getAdapter(dialect).getTableColumns(db, tableName);\n}\n\n/**\n * Get all tables in the database\n *\n * @example\n * const tables = await getTables(db, 'postgres');\n * // ['users', 'posts', 'comments']\n */\nexport async function getTables(db: Kysely<any>, dialect: DatabaseDialect): Promise<string[]> {\n return getAdapter(dialect).getTables(db);\n}\n\n/**\n * Escape identifier for SQL (table names, column names, etc.)\n *\n * @example\n * escapeIdentifier('my-table', 'postgres') // '\"my-table\"'\n * escapeIdentifier('my-table', 'mysql') // '`my-table`'\n */\nexport function escapeIdentifier(identifier: string, dialect: DatabaseDialect): string {\n return getAdapter(dialect).escapeIdentifier(identifier);\n}\n\n/**\n * Get SQL expression for current timestamp\n *\n * @example\n * getCurrentTimestamp('postgres') // 'CURRENT_TIMESTAMP'\n * getCurrentTimestamp('sqlite') // \"datetime('now')\"\n */\nexport function getCurrentTimestamp(dialect: DatabaseDialect): string {\n return getAdapter(dialect).getCurrentTimestamp();\n}\n\n/**\n * Format date for database insertion\n *\n * @example\n * formatDate(new Date(), 'postgres') // '2024-01-15T10:30:00.000Z'\n * formatDate(new Date(), 'mysql') // '2024-01-15 10:30:00'\n */\nexport function formatDate(date: Date, dialect: DatabaseDialect): string {\n return getAdapter(dialect).formatDate(date);\n}\n\n/**\n * Check if error is a unique constraint violation\n *\n * @example\n * try {\n * await db.insertInto('users').values({ email: 'duplicate@example.com' }).execute();\n * } catch (error) {\n * if (isUniqueConstraintError(error, 'postgres')) {\n * console.log('Email already exists');\n * }\n * }\n */\nexport function isUniqueConstraintError(error: unknown, dialect: DatabaseDialect): boolean {\n return getAdapter(dialect).isUniqueConstraintError(error);\n}\n\n/**\n * Check if error is a foreign key constraint violation\n *\n * @example\n * if (isForeignKeyError(error, 'mysql')) {\n * console.log('Referenced row does not exist');\n * }\n */\nexport function isForeignKeyError(error: unknown, dialect: DatabaseDialect): boolean {\n return getAdapter(dialect).isForeignKeyError(error);\n}\n\n/**\n * Check if error is a not-null constraint violation\n *\n * @example\n * if (isNotNullError(error, 'sqlite')) {\n * console.log('Required field is missing');\n * }\n */\nexport function isNotNullError(error: unknown, dialect: DatabaseDialect): boolean {\n return getAdapter(dialect).isNotNullError(error);\n}\n\n/**\n * Get database size in bytes\n *\n * @example\n * const size = await getDatabaseSize(db, 'postgres');\n * console.log(`Database size: ${size} bytes`);\n */\nexport async function getDatabaseSize(\n db: Kysely<any>,\n dialect: DatabaseDialect,\n databaseName?: string\n): Promise<number> {\n return getAdapter(dialect).getDatabaseSize(db, databaseName);\n}\n\n/**\n * Truncate all tables in the database (useful for testing)\n *\n * @example\n * // Truncate all tables except migrations\n * await truncateAllTables(db, 'postgres', ['kysely_migrations']);\n */\nexport async function truncateAllTables(\n db: Kysely<any>,\n dialect: DatabaseDialect,\n exclude: string[] = []\n): Promise<void> {\n return getAdapter(dialect).truncateAllTables(db, exclude);\n}\n"]}
package/package.json ADDED
@@ -0,0 +1,71 @@
1
+ {
2
+ "name": "@kysera/dialects",
3
+ "version": "0.7.3",
4
+ "description": "Dialect-specific utilities for Kysely - PostgreSQL, MySQL, SQLite support",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ }
13
+ },
14
+ "files": [
15
+ "dist",
16
+ "src"
17
+ ],
18
+ "peerDependencies": {
19
+ "kysely": ">=0.28.8"
20
+ },
21
+ "devDependencies": {
22
+ "@types/better-sqlite3": "^7.6.13",
23
+ "@types/node": "^25.0.3",
24
+ "@types/pg": "^8.16.0",
25
+ "@vitest/coverage-v8": "^4.0.16",
26
+ "better-sqlite3": "^12.5.0",
27
+ "kysely": "^0.28.9",
28
+ "mysql2": "^3.16.0",
29
+ "pg": "^8.16.3",
30
+ "tsup": "^8.5.1",
31
+ "typescript": "^5.9.3",
32
+ "vitest": "^4.0.16"
33
+ },
34
+ "keywords": [
35
+ "kysely",
36
+ "dialect",
37
+ "postgres",
38
+ "mysql",
39
+ "sqlite",
40
+ "database",
41
+ "sql"
42
+ ],
43
+ "author": "Kysera Team",
44
+ "license": "MIT",
45
+ "repository": {
46
+ "type": "git",
47
+ "url": "git+https://github.com/kysera-dev/kysera.git",
48
+ "directory": "packages/dialects"
49
+ },
50
+ "bugs": {
51
+ "url": "https://github.com/kysera-dev/kysera/issues"
52
+ },
53
+ "homepage": "https://github.com/kysera-dev/kysera#readme",
54
+ "publishConfig": {
55
+ "access": "public"
56
+ },
57
+ "sideEffects": false,
58
+ "engines": {
59
+ "node": ">=20.0.0",
60
+ "bun": ">=1.0.0"
61
+ },
62
+ "scripts": {
63
+ "build": "tsup",
64
+ "dev": "tsup --watch",
65
+ "test": "vitest run",
66
+ "test:watch": "vitest watch",
67
+ "test:coverage": "vitest run --coverage",
68
+ "typecheck": "tsc --noEmit",
69
+ "lint": "eslint ."
70
+ }
71
+ }
@@ -0,0 +1,143 @@
1
+ /**
2
+ * MySQL Dialect Adapter
3
+ */
4
+
5
+ import type { Kysely } from 'kysely';
6
+ import { sql } from 'kysely';
7
+ import type { DialectAdapter, DatabaseErrorLike } from '../types.js';
8
+
9
+ export class MySQLAdapter implements DialectAdapter {
10
+ readonly dialect = 'mysql' as const;
11
+
12
+ getDefaultPort(): number {
13
+ return 3306;
14
+ }
15
+
16
+ getCurrentTimestamp(): string {
17
+ return 'CURRENT_TIMESTAMP';
18
+ }
19
+
20
+ escapeIdentifier(identifier: string): string {
21
+ return `\`${identifier.replace(/`/g, '``')}\``;
22
+ }
23
+
24
+ formatDate(date: Date): string {
25
+ // MySQL datetime format: YYYY-MM-DD HH:MM:SS
26
+ return date.toISOString().slice(0, 19).replace('T', ' ');
27
+ }
28
+
29
+ isUniqueConstraintError(error: unknown): boolean {
30
+ const e = error as DatabaseErrorLike;
31
+ const message = e.message?.toLowerCase() || '';
32
+ const code = e.code || '';
33
+ return code === 'ER_DUP_ENTRY' || code === '1062' || message.includes('duplicate entry');
34
+ }
35
+
36
+ isForeignKeyError(error: unknown): boolean {
37
+ const e = error as DatabaseErrorLike;
38
+ const code = e.code || '';
39
+ return (
40
+ code === 'ER_ROW_IS_REFERENCED' ||
41
+ code === '1451' ||
42
+ code === 'ER_NO_REFERENCED_ROW' ||
43
+ code === '1452'
44
+ );
45
+ }
46
+
47
+ isNotNullError(error: unknown): boolean {
48
+ const e = error as DatabaseErrorLike;
49
+ const code = e.code || '';
50
+ return code === 'ER_BAD_NULL_ERROR' || code === '1048';
51
+ }
52
+
53
+ async tableExists(db: Kysely<any>, tableName: string): Promise<boolean> {
54
+ try {
55
+ const result = await db
56
+ .selectFrom('information_schema.tables')
57
+ .select('table_name')
58
+ .where('table_name', '=', tableName)
59
+ .where('table_schema', '=', sql`DATABASE()`)
60
+ .executeTakeFirst();
61
+ return !!result;
62
+ } catch {
63
+ return false;
64
+ }
65
+ }
66
+
67
+ async getTableColumns(db: Kysely<any>, tableName: string): Promise<string[]> {
68
+ try {
69
+ const results = await db
70
+ .selectFrom('information_schema.columns')
71
+ .select('column_name')
72
+ .where('table_name', '=', tableName)
73
+ .where('table_schema', '=', sql`DATABASE()`)
74
+ .execute();
75
+ return results.map((r) => r.column_name as string);
76
+ } catch {
77
+ return [];
78
+ }
79
+ }
80
+
81
+ async getTables(db: Kysely<any>): Promise<string[]> {
82
+ try {
83
+ const results = await db
84
+ .selectFrom('information_schema.tables')
85
+ .select('table_name')
86
+ .where('table_schema', '=', sql`DATABASE()`)
87
+ .where('table_type', '=', 'BASE TABLE')
88
+ .execute();
89
+ return results.map((r) => r.table_name as string);
90
+ } catch {
91
+ return [];
92
+ }
93
+ }
94
+
95
+ async getDatabaseSize(db: Kysely<any>, databaseName?: string): Promise<number> {
96
+ try {
97
+ const dbName =
98
+ databaseName ||
99
+ (await sql
100
+ .raw('SELECT DATABASE() as name')
101
+ .execute(db)
102
+ .then((r) => (r.rows?.[0] as { name?: string })?.name));
103
+
104
+ const result = await sql
105
+ .raw(
106
+ `SELECT SUM(data_length + index_length) as size FROM information_schema.tables WHERE table_schema = '${dbName}'`
107
+ )
108
+ .execute(db)
109
+ .then((r) => r.rows?.[0]);
110
+
111
+ return (result as { size?: number })?.size || 0;
112
+ } catch {
113
+ return 0;
114
+ }
115
+ }
116
+
117
+ async truncateTable(db: Kysely<any>, tableName: string): Promise<void> {
118
+ try {
119
+ // Temporarily disable foreign key checks
120
+ await sql.raw('SET FOREIGN_KEY_CHECKS = 0').execute(db);
121
+ await sql.raw(`TRUNCATE TABLE ${this.escapeIdentifier(tableName)}`).execute(db);
122
+ await sql.raw('SET FOREIGN_KEY_CHECKS = 1').execute(db);
123
+ } catch {
124
+ // Re-enable foreign key checks even on error
125
+ try {
126
+ await sql.raw('SET FOREIGN_KEY_CHECKS = 1').execute(db);
127
+ } catch {
128
+ // Ignore
129
+ }
130
+ }
131
+ }
132
+
133
+ async truncateAllTables(db: Kysely<any>, exclude: string[] = []): Promise<void> {
134
+ const tables = await this.getTables(db);
135
+ for (const table of tables) {
136
+ if (!exclude.includes(table)) {
137
+ await this.truncateTable(db, table);
138
+ }
139
+ }
140
+ }
141
+ }
142
+
143
+ export const mysqlAdapter = new MySQLAdapter();