feat(db): implement SqlDialect with MySQL, SQL Server, PostgreSQL dialects
Add three SqlDialect implementations with a factory function: - MySqlDialect: positional ?, ON DUPLICATE KEY UPDATE, LIMIT/OFFSET - SqlServerDialect: @pN params, MERGE USING, OFFSET/FETCH - PostgreSqlDialect: $N (1-based), ON CONFLICT DO UPDATE, LIMIT/OFFSET TDD approach: 43 tests written first, all passing. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
73
src/main/services/database/dialects/mysql-dialect.ts
Normal file
73
src/main/services/database/dialects/mysql-dialect.ts
Normal file
@@ -0,0 +1,73 @@
|
||||
/**
|
||||
* MySQL SQL Dialect Implementation
|
||||
*
|
||||
* Encapsulates MySQL-specific SQL syntax for:
|
||||
* - Table name quoting (underscore-separated)
|
||||
* - Positional parameter placeholders (?)
|
||||
* - INSERT ... ON DUPLICATE KEY UPDATE upsert
|
||||
* - LIMIT/OFFSET pagination
|
||||
*/
|
||||
|
||||
import type { SqlDialect } from '@types/sql-dialect.types'
|
||||
|
||||
export class MySqlDialect implements SqlDialect {
|
||||
readonly dbType = 'mysql' as const
|
||||
|
||||
quoteTableName(schema: string, table: string): string {
|
||||
return `${schema}_${table}`
|
||||
}
|
||||
|
||||
param(_index: number): string {
|
||||
return '?'
|
||||
}
|
||||
|
||||
params(count: number): string {
|
||||
return Array.from({ length: count }, () => '?').join(',')
|
||||
}
|
||||
|
||||
currentTimestamp(): string {
|
||||
return 'NOW()'
|
||||
}
|
||||
|
||||
upsert(params: {
|
||||
table: string
|
||||
keyColumns: string[]
|
||||
allColumns: string[]
|
||||
startParamIndex: number
|
||||
}): { sql: string; nextParamIndex: number } {
|
||||
const { table, keyColumns, allColumns, startParamIndex } = params
|
||||
|
||||
const columns = allColumns.join(', ')
|
||||
const placeholders = allColumns.map(() => '?').join(', ')
|
||||
|
||||
const nonKeyColumns = allColumns.filter((col) => !keyColumns.includes(col))
|
||||
const updateClause = nonKeyColumns
|
||||
.map((col) => `${col} = VALUES(${col})`)
|
||||
.join(', ')
|
||||
|
||||
const sql = `INSERT INTO ${table} (${columns}) VALUES (${placeholders}) ON DUPLICATE KEY UPDATE ${updateClause}`
|
||||
|
||||
return {
|
||||
sql,
|
||||
nextParamIndex: startParamIndex + allColumns.length
|
||||
}
|
||||
}
|
||||
|
||||
paginate(params: {
|
||||
sql: string
|
||||
limit: number
|
||||
offset?: number
|
||||
paramIndex: number
|
||||
}): { sql: string; nextParamIndex: number } {
|
||||
const { sql, limit, offset, paramIndex } = params
|
||||
|
||||
return {
|
||||
sql: `${sql} LIMIT ${limit} OFFSET ${offset ?? 0}`,
|
||||
nextParamIndex: paramIndex
|
||||
}
|
||||
}
|
||||
|
||||
maxBatchRows(_columnsPerRow: number): number {
|
||||
return 1000
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user