/** * PostgreSQL Dialect Implementation * * Encapsulates PostgreSQL-specific SQL syntax for: * - Table name quoting (double-quoted "schema"."table") * - Positional parameter placeholders ($1, $2, ...) — 1-based * - INSERT ... ON CONFLICT ... DO UPDATE SET upsert * - LIMIT/OFFSET pagination */ import type { SqlDialect } from '../../../types/sql-dialect.types' export class PostgreSqlDialect implements SqlDialect { readonly dbType = 'postgresql' as const quoteTableName(schema: string, table: string): string { return `"${schema}"."${table}"` } param(index: number): string { return `$${index + 1}` } params(count: number): string { return Array.from({ length: count }, (_, i) => `$${i + 1}`).join(',') } currentTimestamp(): string { return 'CURRENT_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((_, i) => `$${startParamIndex + i + 1}`).join(', ') const conflictKeys = keyColumns.map((col) => `"${col}"`).join(', ') const nonKeyColumns = allColumns.filter((col) => !keyColumns.includes(col)) const updateSet = nonKeyColumns.map((col) => `"${col}" = EXCLUDED."${col}"`).join(', ') const sql = [ `INSERT INTO ${table} (${columns}) VALUES (${placeholders})`, `ON CONFLICT (${conflictKeys})`, `DO UPDATE SET ${updateSet}` ].join(' ') 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 } }