77 lines
2.1 KiB
TypeScript
77 lines
2.1 KiB
TypeScript
/**
|
|
* 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
|
|
}
|
|
}
|