/** * 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}` } // eslint-disable-next-line @typescript-eslint/no-unused-vars param(_index: number): string { return '?' } params(count: number): string { return Array.from({ length: count }, () => '?').join(',') } currentTimestamp(): string { return 'UTC_TIMESTAMP()' } 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 } } // eslint-disable-next-line @typescript-eslint/no-unused-vars maxBatchRows(_columnsPerRow: number): number { return 1000 } }