@kysera/dialects 0.8.2 → 0.8.4
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 +787 -71
- package/dist/index.js +62 -4
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/adapters/mssql.ts +203 -57
- package/src/adapters/mysql.ts +105 -36
- package/src/adapters/postgres.ts +619 -28
- package/src/adapters/sqlite.ts +126 -36
- package/src/factory.ts +71 -17
- package/src/helpers.ts +405 -18
- package/src/index.ts +85 -9
- package/src/types.ts +103 -9
package/src/helpers.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import type { Kysely } from 'kysely'
|
|
9
|
-
import type { Dialect } from './types.js'
|
|
9
|
+
import type { Dialect, SchemaOptions, DatabaseErrorLike } from './types.js'
|
|
10
10
|
import { getAdapter } from './factory.js'
|
|
11
11
|
|
|
12
12
|
/**
|
|
@@ -21,7 +21,7 @@ const MAX_IDENTIFIER_LENGTH = 128
|
|
|
21
21
|
const IDENTIFIER_PATTERN = /^[a-zA-Z_][a-zA-Z0-9_.]*$/
|
|
22
22
|
|
|
23
23
|
/**
|
|
24
|
-
* Validate a SQL identifier (table name, column name, etc.)
|
|
24
|
+
* Validate a SQL identifier (table name, column name, schema name, etc.)
|
|
25
25
|
*
|
|
26
26
|
* @param name - The identifier to validate
|
|
27
27
|
* @returns true if the identifier is valid, false otherwise
|
|
@@ -58,44 +58,425 @@ export function assertValidIdentifier(name: string, context = 'identifier'): voi
|
|
|
58
58
|
}
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
+
// ============================================================================
|
|
62
|
+
// Schema Resolution Utilities
|
|
63
|
+
// ============================================================================
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Resolve schema name with validation
|
|
67
|
+
*
|
|
68
|
+
* This is the canonical implementation used by all dialect adapters.
|
|
69
|
+
* Eliminates code duplication across PostgreSQL, MySQL, SQLite, and MSSQL adapters.
|
|
70
|
+
*
|
|
71
|
+
* @param defaultSchema - The default schema to use if not specified in options
|
|
72
|
+
* @param options - Optional schema configuration
|
|
73
|
+
* @returns The resolved and validated schema name
|
|
74
|
+
* @throws Error if the schema name is invalid
|
|
75
|
+
*
|
|
76
|
+
* @example
|
|
77
|
+
* // Use with adapter's default schema
|
|
78
|
+
* const schema = resolveSchema('public', options)
|
|
79
|
+
*
|
|
80
|
+
* @example
|
|
81
|
+
* // Multi-tenant usage
|
|
82
|
+
* const schema = resolveSchema('public', { schema: `tenant_${tenantId}` })
|
|
83
|
+
*/
|
|
84
|
+
export function resolveSchema(defaultSchema: string, options?: SchemaOptions): string {
|
|
85
|
+
const schema = options?.schema ?? defaultSchema
|
|
86
|
+
assertValidIdentifier(schema, 'schema name')
|
|
87
|
+
return schema
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// ============================================================================
|
|
91
|
+
// Multi-tenant Schema Utilities
|
|
92
|
+
// ============================================================================
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Default prefix for tenant schemas
|
|
96
|
+
*/
|
|
97
|
+
const DEFAULT_TENANT_PREFIX = 'tenant_'
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Configuration for multi-tenant schema operations
|
|
101
|
+
*/
|
|
102
|
+
export interface TenantSchemaConfig {
|
|
103
|
+
/** Prefix for tenant schema names (default: 'tenant_') */
|
|
104
|
+
prefix?: string
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Generate a tenant schema name from a tenant ID
|
|
109
|
+
*
|
|
110
|
+
* @param tenantId - The unique tenant identifier
|
|
111
|
+
* @param config - Optional configuration
|
|
112
|
+
* @returns The tenant schema name (validated)
|
|
113
|
+
* @throws Error if the resulting schema name is invalid
|
|
114
|
+
*
|
|
115
|
+
* @example
|
|
116
|
+
* getTenantSchemaName('123') // 'tenant_123'
|
|
117
|
+
* getTenantSchemaName('acme') // 'tenant_acme'
|
|
118
|
+
* getTenantSchemaName('corp', { prefix: 'org_' }) // 'org_corp'
|
|
119
|
+
*/
|
|
120
|
+
export function getTenantSchemaName(tenantId: string, config?: TenantSchemaConfig): string {
|
|
121
|
+
if (!tenantId) {
|
|
122
|
+
throw new Error('Invalid tenant schema name: tenant ID cannot be empty')
|
|
123
|
+
}
|
|
124
|
+
const prefix = config?.prefix ?? DEFAULT_TENANT_PREFIX
|
|
125
|
+
const schemaName = `${prefix}${tenantId}`
|
|
126
|
+
assertValidIdentifier(schemaName, 'tenant schema name')
|
|
127
|
+
return schemaName
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Extract tenant ID from a tenant schema name
|
|
132
|
+
*
|
|
133
|
+
* @param schemaName - The schema name to parse
|
|
134
|
+
* @param config - Optional configuration
|
|
135
|
+
* @returns The tenant ID if the schema matches the pattern, null otherwise
|
|
136
|
+
*
|
|
137
|
+
* @example
|
|
138
|
+
* parseTenantSchemaName('tenant_123') // '123'
|
|
139
|
+
* parseTenantSchemaName('tenant_acme') // 'acme'
|
|
140
|
+
* parseTenantSchemaName('public') // null
|
|
141
|
+
* parseTenantSchemaName('org_corp', { prefix: 'org_' }) // 'corp'
|
|
142
|
+
*/
|
|
143
|
+
export function parseTenantSchemaName(schemaName: string, config?: TenantSchemaConfig): string | null {
|
|
144
|
+
const prefix = config?.prefix ?? DEFAULT_TENANT_PREFIX
|
|
145
|
+
if (schemaName.startsWith(prefix) && schemaName.length > prefix.length) {
|
|
146
|
+
return schemaName.slice(prefix.length)
|
|
147
|
+
}
|
|
148
|
+
return null
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Check if a schema name matches the tenant schema pattern
|
|
153
|
+
*
|
|
154
|
+
* @param schemaName - The schema name to check
|
|
155
|
+
* @param config - Optional configuration
|
|
156
|
+
* @returns true if the schema matches the tenant pattern
|
|
157
|
+
*
|
|
158
|
+
* @example
|
|
159
|
+
* isTenantSchema('tenant_123') // true
|
|
160
|
+
* isTenantSchema('public') // false
|
|
161
|
+
* isTenantSchema('org_corp', { prefix: 'org_' }) // true
|
|
162
|
+
*/
|
|
163
|
+
export function isTenantSchema(schemaName: string, config?: TenantSchemaConfig): boolean {
|
|
164
|
+
return parseTenantSchemaName(schemaName, config) !== null
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Filter an array of schema names to only tenant schemas
|
|
169
|
+
*
|
|
170
|
+
* @param schemas - Array of schema names
|
|
171
|
+
* @param config - Optional configuration
|
|
172
|
+
* @returns Array of tenant schema names
|
|
173
|
+
*
|
|
174
|
+
* @example
|
|
175
|
+
* filterTenantSchemas(['public', 'tenant_1', 'tenant_2', 'auth'])
|
|
176
|
+
* // ['tenant_1', 'tenant_2']
|
|
177
|
+
*/
|
|
178
|
+
export function filterTenantSchemas(schemas: string[], config?: TenantSchemaConfig): string[] {
|
|
179
|
+
return schemas.filter(schema => isTenantSchema(schema, config))
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Extract tenant IDs from an array of schema names
|
|
184
|
+
*
|
|
185
|
+
* @param schemas - Array of schema names
|
|
186
|
+
* @param config - Optional configuration
|
|
187
|
+
* @returns Array of tenant IDs (excluding non-tenant schemas)
|
|
188
|
+
*
|
|
189
|
+
* @example
|
|
190
|
+
* extractTenantIds(['public', 'tenant_1', 'tenant_2', 'auth'])
|
|
191
|
+
* // ['1', '2']
|
|
192
|
+
*/
|
|
193
|
+
export function extractTenantIds(schemas: string[], config?: TenantSchemaConfig): string[] {
|
|
194
|
+
return schemas
|
|
195
|
+
.map(schema => parseTenantSchemaName(schema, config))
|
|
196
|
+
.filter((id): id is string => id !== null)
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// ============================================================================
|
|
200
|
+
// Schema Copying Utilities
|
|
201
|
+
// ============================================================================
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Options for schema copying operations
|
|
205
|
+
*/
|
|
206
|
+
export interface SchemaCopyOptions {
|
|
207
|
+
/** Include table data (default: false, structure only) */
|
|
208
|
+
includeData?: boolean
|
|
209
|
+
/** Tables to exclude from copying */
|
|
210
|
+
excludeTables?: string[]
|
|
211
|
+
/** Tables to include (if specified, only these are copied) */
|
|
212
|
+
includeTables?: string[]
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Create a qualified table name with schema prefix
|
|
217
|
+
*
|
|
218
|
+
* @param schema - The schema name
|
|
219
|
+
* @param tableName - The table name
|
|
220
|
+
* @param escapeIdentifierFn - Function to escape identifiers for the specific dialect
|
|
221
|
+
* @returns Fully qualified table name (e.g., "public"."users")
|
|
222
|
+
*
|
|
223
|
+
* @example
|
|
224
|
+
* qualifyTableName('auth', 'users', escapeIdentifier)
|
|
225
|
+
* // PostgreSQL: "auth"."users"
|
|
226
|
+
* // MySQL: `auth`.`users`
|
|
227
|
+
*/
|
|
228
|
+
export function qualifyTableName(
|
|
229
|
+
schema: string,
|
|
230
|
+
tableName: string,
|
|
231
|
+
escapeIdentifierFn: (id: string) => string
|
|
232
|
+
): string {
|
|
233
|
+
return `${escapeIdentifierFn(schema)}.${escapeIdentifierFn(tableName)}`
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// ============================================================================
|
|
237
|
+
// Error Detection Utilities
|
|
238
|
+
// ============================================================================
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Error information extracted from a database error
|
|
242
|
+
*/
|
|
243
|
+
export interface ExtractedErrorInfo {
|
|
244
|
+
/** Error code (e.g., '23505' for PostgreSQL unique constraint) */
|
|
245
|
+
code: string
|
|
246
|
+
/** Error message in lowercase for case-insensitive matching */
|
|
247
|
+
message: string
|
|
248
|
+
/** Original error message */
|
|
249
|
+
originalMessage: string
|
|
250
|
+
/** Error number (for MSSQL) - undefined if not present */
|
|
251
|
+
number: number | undefined
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* Extract error information from an unknown database error
|
|
256
|
+
*
|
|
257
|
+
* This utility normalizes error information across different database drivers,
|
|
258
|
+
* eliminating the need for repeated type assertions in each adapter.
|
|
259
|
+
*
|
|
260
|
+
* @param error - The unknown error from a database operation
|
|
261
|
+
* @returns Normalized error information
|
|
262
|
+
*
|
|
263
|
+
* @example
|
|
264
|
+
* try {
|
|
265
|
+
* await db.insertInto('users').values(data).execute()
|
|
266
|
+
* } catch (error) {
|
|
267
|
+
* const info = extractErrorInfo(error)
|
|
268
|
+
* if (info.code === '23505') {
|
|
269
|
+
* // Handle unique constraint violation
|
|
270
|
+
* }
|
|
271
|
+
* }
|
|
272
|
+
*/
|
|
273
|
+
export function extractErrorInfo(error: unknown): ExtractedErrorInfo {
|
|
274
|
+
// Handle null/undefined gracefully
|
|
275
|
+
if (error == null || typeof error !== 'object') {
|
|
276
|
+
return {
|
|
277
|
+
code: '',
|
|
278
|
+
message: '',
|
|
279
|
+
originalMessage: '',
|
|
280
|
+
number: undefined
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
const e = error as DatabaseErrorLike
|
|
284
|
+
const originalMessage = e.message ?? ''
|
|
285
|
+
return {
|
|
286
|
+
code: e.code ?? '',
|
|
287
|
+
message: originalMessage.toLowerCase(),
|
|
288
|
+
originalMessage,
|
|
289
|
+
number: typeof e.number === 'number' ? e.number : undefined
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* Error matcher configuration for a specific error type
|
|
295
|
+
*/
|
|
296
|
+
export interface ErrorMatcherConfig {
|
|
297
|
+
/** PostgreSQL error codes */
|
|
298
|
+
codes?: string[]
|
|
299
|
+
/** MSSQL error numbers */
|
|
300
|
+
numbers?: number[]
|
|
301
|
+
/** Message substrings to match (case-insensitive) */
|
|
302
|
+
messages?: string[]
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* Create an error matcher function for a specific constraint type
|
|
307
|
+
*
|
|
308
|
+
* This factory eliminates code duplication across dialect adapters by creating
|
|
309
|
+
* reusable error detection functions.
|
|
310
|
+
*
|
|
311
|
+
* @param config - Configuration for matching the error
|
|
312
|
+
* @returns A function that checks if an error matches the configured patterns
|
|
313
|
+
*
|
|
314
|
+
* @example
|
|
315
|
+
* // Create a unique constraint error matcher for PostgreSQL
|
|
316
|
+
* const isUniqueConstraint = createErrorMatcher({
|
|
317
|
+
* codes: ['23505'],
|
|
318
|
+
* messages: ['unique constraint']
|
|
319
|
+
* })
|
|
320
|
+
*
|
|
321
|
+
* @example
|
|
322
|
+
* // Create a foreign key error matcher for MSSQL
|
|
323
|
+
* const isForeignKey = createErrorMatcher({
|
|
324
|
+
* numbers: [547],
|
|
325
|
+
* messages: ['foreign key']
|
|
326
|
+
* })
|
|
327
|
+
*/
|
|
328
|
+
export function createErrorMatcher(
|
|
329
|
+
config: ErrorMatcherConfig
|
|
330
|
+
): (error: unknown) => boolean {
|
|
331
|
+
const { codes = [], numbers = [], messages = [] } = config
|
|
332
|
+
|
|
333
|
+
return (error: unknown): boolean => {
|
|
334
|
+
const info = extractErrorInfo(error)
|
|
335
|
+
|
|
336
|
+
// Check error codes (PostgreSQL, MySQL)
|
|
337
|
+
if (codes.length > 0 && codes.includes(info.code)) {
|
|
338
|
+
return true
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
// Check error numbers (MSSQL)
|
|
342
|
+
if (numbers.length > 0 && info.number !== undefined && numbers.includes(info.number)) {
|
|
343
|
+
return true
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
// Check message patterns
|
|
347
|
+
if (messages.length > 0) {
|
|
348
|
+
for (const pattern of messages) {
|
|
349
|
+
if (info.message.includes(pattern.toLowerCase())) {
|
|
350
|
+
return true
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
return false
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
// ============================================================================
|
|
360
|
+
// Pre-built Error Matchers
|
|
361
|
+
// ============================================================================
|
|
362
|
+
|
|
363
|
+
/**
|
|
364
|
+
* Pre-built error matchers for common constraint violations
|
|
365
|
+
* These can be used directly or as reference for custom matchers
|
|
366
|
+
*/
|
|
367
|
+
export const errorMatchers = {
|
|
368
|
+
postgres: {
|
|
369
|
+
uniqueConstraint: createErrorMatcher({ codes: ['23505'], messages: ['unique constraint'] }),
|
|
370
|
+
foreignKey: createErrorMatcher({ codes: ['23503'], messages: ['foreign key constraint'] }),
|
|
371
|
+
notNull: createErrorMatcher({ codes: ['23502'], messages: ['not-null constraint'] })
|
|
372
|
+
},
|
|
373
|
+
mysql: {
|
|
374
|
+
// Include both named codes (ER_*) and numeric codes (1062, etc.)
|
|
375
|
+
uniqueConstraint: createErrorMatcher({
|
|
376
|
+
codes: ['ER_DUP_ENTRY', '1062'],
|
|
377
|
+
messages: ['duplicate entry']
|
|
378
|
+
}),
|
|
379
|
+
foreignKey: createErrorMatcher({
|
|
380
|
+
codes: ['ER_NO_REFERENCED_ROW_2', 'ER_ROW_IS_REFERENCED_2', 'ER_ROW_IS_REFERENCED', 'ER_NO_REFERENCED_ROW', '1451', '1452'],
|
|
381
|
+
messages: ['foreign key constraint']
|
|
382
|
+
}),
|
|
383
|
+
notNull: createErrorMatcher({
|
|
384
|
+
codes: ['ER_BAD_NULL_ERROR', '1048'],
|
|
385
|
+
messages: ['cannot be null']
|
|
386
|
+
})
|
|
387
|
+
},
|
|
388
|
+
sqlite: {
|
|
389
|
+
uniqueConstraint: createErrorMatcher({ messages: ['unique constraint failed'] }),
|
|
390
|
+
foreignKey: createErrorMatcher({ messages: ['foreign key constraint failed'] }),
|
|
391
|
+
notNull: createErrorMatcher({ messages: ['not null constraint failed'] })
|
|
392
|
+
},
|
|
393
|
+
mssql: {
|
|
394
|
+
// MSSQL uses numeric error codes
|
|
395
|
+
uniqueConstraint: createErrorMatcher({
|
|
396
|
+
codes: ['2627', '2601'],
|
|
397
|
+
numbers: [2627, 2601],
|
|
398
|
+
messages: ['violation of unique key constraint', 'cannot insert duplicate key', 'unique constraint']
|
|
399
|
+
}),
|
|
400
|
+
foreignKey: createErrorMatcher({
|
|
401
|
+
codes: ['547'],
|
|
402
|
+
numbers: [547],
|
|
403
|
+
messages: ['foreign key constraint', 'conflicted with the foreign key']
|
|
404
|
+
}),
|
|
405
|
+
notNull: createErrorMatcher({
|
|
406
|
+
codes: ['515'],
|
|
407
|
+
numbers: [515],
|
|
408
|
+
messages: ['cannot insert the value null', 'does not allow nulls']
|
|
409
|
+
})
|
|
410
|
+
}
|
|
411
|
+
} as const
|
|
412
|
+
|
|
61
413
|
/**
|
|
62
414
|
* Check if table exists in the database
|
|
63
415
|
*
|
|
416
|
+
* @param db - Kysely database instance
|
|
417
|
+
* @param tableName - Name of the table to check
|
|
418
|
+
* @param dialect - Database dialect
|
|
419
|
+
* @param options - Optional schema configuration
|
|
420
|
+
* @returns true if table exists, false otherwise
|
|
421
|
+
*
|
|
422
|
+
* @example
|
|
423
|
+
* // Check in default schema
|
|
424
|
+
* const exists = await tableExists(db, 'users', 'postgres')
|
|
425
|
+
*
|
|
64
426
|
* @example
|
|
65
|
-
*
|
|
427
|
+
* // Check in specific schema
|
|
428
|
+
* const exists = await tableExists(db, 'users', 'postgres', { schema: 'auth' })
|
|
66
429
|
*/
|
|
67
430
|
export async function tableExists(
|
|
68
431
|
db: Kysely<any>,
|
|
69
432
|
tableName: string,
|
|
70
|
-
dialect: Dialect
|
|
433
|
+
dialect: Dialect,
|
|
434
|
+
options?: SchemaOptions
|
|
71
435
|
): Promise<boolean> {
|
|
72
|
-
return await getAdapter(dialect).tableExists(db, tableName)
|
|
436
|
+
return await getAdapter(dialect).tableExists(db, tableName, options)
|
|
73
437
|
}
|
|
74
438
|
|
|
75
439
|
/**
|
|
76
440
|
* Get column names for a table
|
|
77
441
|
*
|
|
442
|
+
* @param db - Kysely database instance
|
|
443
|
+
* @param tableName - Name of the table
|
|
444
|
+
* @param dialect - Database dialect
|
|
445
|
+
* @param options - Optional schema configuration
|
|
446
|
+
* @returns Array of column names
|
|
447
|
+
*
|
|
78
448
|
* @example
|
|
79
|
-
* const columns = await getTableColumns(db, 'users', 'postgres')
|
|
449
|
+
* const columns = await getTableColumns(db, 'users', 'postgres', { schema: 'auth' })
|
|
80
450
|
* // ['id', 'name', 'email', 'created_at']
|
|
81
451
|
*/
|
|
82
452
|
export async function getTableColumns(
|
|
83
453
|
db: Kysely<any>,
|
|
84
454
|
tableName: string,
|
|
85
|
-
dialect: Dialect
|
|
455
|
+
dialect: Dialect,
|
|
456
|
+
options?: SchemaOptions
|
|
86
457
|
): Promise<string[]> {
|
|
87
|
-
return await getAdapter(dialect).getTableColumns(db, tableName)
|
|
458
|
+
return await getAdapter(dialect).getTableColumns(db, tableName, options)
|
|
88
459
|
}
|
|
89
460
|
|
|
90
461
|
/**
|
|
91
|
-
* Get all tables in the database
|
|
462
|
+
* Get all tables in the database/schema
|
|
463
|
+
*
|
|
464
|
+
* @param db - Kysely database instance
|
|
465
|
+
* @param dialect - Database dialect
|
|
466
|
+
* @param options - Optional schema configuration
|
|
467
|
+
* @returns Array of table names
|
|
92
468
|
*
|
|
93
469
|
* @example
|
|
94
|
-
*
|
|
95
|
-
*
|
|
470
|
+
* // Get tables in auth schema
|
|
471
|
+
* const tables = await getTables(db, 'postgres', { schema: 'auth' })
|
|
472
|
+
* // ['users', 'sessions', 'tokens']
|
|
96
473
|
*/
|
|
97
|
-
export async function getTables(
|
|
98
|
-
|
|
474
|
+
export async function getTables(
|
|
475
|
+
db: Kysely<any>,
|
|
476
|
+
dialect: Dialect,
|
|
477
|
+
options?: SchemaOptions
|
|
478
|
+
): Promise<string[]> {
|
|
479
|
+
return await getAdapter(dialect).getTables(db, options)
|
|
99
480
|
}
|
|
100
481
|
|
|
101
482
|
/**
|
|
@@ -187,16 +568,22 @@ export async function getDatabaseSize(
|
|
|
187
568
|
}
|
|
188
569
|
|
|
189
570
|
/**
|
|
190
|
-
* Truncate all tables in the database (useful for testing)
|
|
571
|
+
* Truncate all tables in the database/schema (useful for testing)
|
|
572
|
+
*
|
|
573
|
+
* @param db - Kysely database instance
|
|
574
|
+
* @param dialect - Database dialect
|
|
575
|
+
* @param exclude - Array of table names to exclude
|
|
576
|
+
* @param options - Optional schema configuration
|
|
191
577
|
*
|
|
192
578
|
* @example
|
|
193
|
-
* // Truncate all tables except migrations
|
|
194
|
-
* await truncateAllTables(db, 'postgres', ['kysely_migrations'])
|
|
579
|
+
* // Truncate all tables in auth schema except migrations
|
|
580
|
+
* await truncateAllTables(db, 'postgres', ['kysely_migrations'], { schema: 'auth' })
|
|
195
581
|
*/
|
|
196
582
|
export async function truncateAllTables(
|
|
197
583
|
db: Kysely<any>,
|
|
198
584
|
dialect: Dialect,
|
|
199
|
-
exclude: string[] = []
|
|
585
|
+
exclude: string[] = [],
|
|
586
|
+
options?: SchemaOptions
|
|
200
587
|
): Promise<void> {
|
|
201
|
-
await getAdapter(dialect).truncateAllTables(db, exclude)
|
|
588
|
+
await getAdapter(dialect).truncateAllTables(db, exclude, options)
|
|
202
589
|
}
|
package/src/index.ts
CHANGED
|
@@ -6,17 +6,36 @@
|
|
|
6
6
|
*
|
|
7
7
|
* @example
|
|
8
8
|
* // Using the adapter interface
|
|
9
|
-
* import { getAdapter } from '@kysera/dialects';
|
|
9
|
+
* import { getAdapter, createDialectAdapter } from '@kysera/dialects';
|
|
10
10
|
*
|
|
11
|
+
* // Get default adapter (uses 'public' schema for postgres)
|
|
11
12
|
* const adapter = getAdapter('postgres');
|
|
12
13
|
* const exists = await adapter.tableExists(db, 'users');
|
|
13
|
-
*
|
|
14
|
+
*
|
|
15
|
+
* // Create adapter with custom default schema
|
|
16
|
+
* const authAdapter = createDialectAdapter('postgres', { defaultSchema: 'auth' });
|
|
17
|
+
* const authTables = await authAdapter.getTables(db);
|
|
18
|
+
*
|
|
19
|
+
* // Override schema per-call
|
|
20
|
+
* const adminTables = await adapter.getTables(db, { schema: 'admin' });
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* // PostgreSQL schema management
|
|
24
|
+
* import { PostgresAdapter, createPostgresAdapter } from '@kysera/dialects';
|
|
25
|
+
*
|
|
26
|
+
* const adapter = createPostgresAdapter({ defaultSchema: 'public' });
|
|
27
|
+
*
|
|
28
|
+
* // Schema operations (PostgreSQL/MSSQL only)
|
|
29
|
+
* await adapter.createSchema(db, 'tenant_123');
|
|
30
|
+
* const schemas = await adapter.getSchemas(db);
|
|
31
|
+
* await adapter.dropSchema(db, 'tenant_123', { cascade: true });
|
|
14
32
|
*
|
|
15
33
|
* @example
|
|
16
34
|
* // Using helper functions (backward compatible)
|
|
17
35
|
* import { tableExists, escapeIdentifier, isUniqueConstraintError } from '@kysera/dialects';
|
|
18
36
|
*
|
|
19
37
|
* const exists = await tableExists(db, 'users', 'postgres');
|
|
38
|
+
* const existsInAuth = await tableExists(db, 'users', 'postgres', { schema: 'auth' });
|
|
20
39
|
* const escaped = escapeIdentifier('user-data', 'mysql');
|
|
21
40
|
*
|
|
22
41
|
* @example
|
|
@@ -28,14 +47,54 @@
|
|
|
28
47
|
*/
|
|
29
48
|
|
|
30
49
|
// Types - Dialect is the canonical type from @kysera/core
|
|
31
|
-
export type {
|
|
50
|
+
export type {
|
|
51
|
+
Dialect,
|
|
52
|
+
ConnectionConfig,
|
|
53
|
+
DialectAdapter,
|
|
54
|
+
DialectAdapterOptions,
|
|
55
|
+
SchemaOptions,
|
|
56
|
+
DatabaseErrorLike
|
|
57
|
+
} from './types.js'
|
|
32
58
|
|
|
33
59
|
// Factory and adapters
|
|
34
|
-
export {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
60
|
+
export {
|
|
61
|
+
getAdapter,
|
|
62
|
+
createDialectAdapter,
|
|
63
|
+
registerAdapter,
|
|
64
|
+
type AdapterOptions
|
|
65
|
+
} from './factory.js'
|
|
66
|
+
|
|
67
|
+
// PostgreSQL adapter with schema management
|
|
68
|
+
export {
|
|
69
|
+
PostgresAdapter,
|
|
70
|
+
postgresAdapter,
|
|
71
|
+
createPostgresAdapter,
|
|
72
|
+
type PostgresAdapterOptions
|
|
73
|
+
} from './adapters/postgres.js'
|
|
74
|
+
|
|
75
|
+
// MySQL adapter
|
|
76
|
+
export {
|
|
77
|
+
MySQLAdapter,
|
|
78
|
+
mysqlAdapter,
|
|
79
|
+
createMySQLAdapter,
|
|
80
|
+
type MySQLAdapterOptions
|
|
81
|
+
} from './adapters/mysql.js'
|
|
82
|
+
|
|
83
|
+
// SQLite adapter
|
|
84
|
+
export {
|
|
85
|
+
SQLiteAdapter,
|
|
86
|
+
sqliteAdapter,
|
|
87
|
+
createSQLiteAdapter,
|
|
88
|
+
type SQLiteAdapterOptions
|
|
89
|
+
} from './adapters/sqlite.js'
|
|
90
|
+
|
|
91
|
+
// MSSQL adapter with schema management
|
|
92
|
+
export {
|
|
93
|
+
MSSQLAdapter,
|
|
94
|
+
mssqlAdapter,
|
|
95
|
+
createMSSQLAdapter,
|
|
96
|
+
type MSSQLAdapterOptions
|
|
97
|
+
} from './adapters/mssql.js'
|
|
39
98
|
|
|
40
99
|
// Connection utilities
|
|
41
100
|
export { parseConnectionUrl, buildConnectionUrl, getDefaultPort } from './connection.js'
|
|
@@ -54,5 +113,22 @@ export {
|
|
|
54
113
|
isForeignKeyError,
|
|
55
114
|
isNotNullError,
|
|
56
115
|
getDatabaseSize,
|
|
57
|
-
truncateAllTables
|
|
116
|
+
truncateAllTables,
|
|
117
|
+
// Schema utilities
|
|
118
|
+
resolveSchema,
|
|
119
|
+
qualifyTableName,
|
|
120
|
+
// Multi-tenant utilities
|
|
121
|
+
getTenantSchemaName,
|
|
122
|
+
parseTenantSchemaName,
|
|
123
|
+
isTenantSchema,
|
|
124
|
+
filterTenantSchemas,
|
|
125
|
+
extractTenantIds,
|
|
126
|
+
type TenantSchemaConfig,
|
|
127
|
+
type SchemaCopyOptions,
|
|
128
|
+
// Error detection utilities
|
|
129
|
+
extractErrorInfo,
|
|
130
|
+
createErrorMatcher,
|
|
131
|
+
errorMatchers,
|
|
132
|
+
type ExtractedErrorInfo,
|
|
133
|
+
type ErrorMatcherConfig
|
|
58
134
|
} from './helpers.js'
|