/** * 데이터베이스별 쿼리 빌더 * PostgreSQL, MySQL/MariaDB, MSSQL, Oracle 지원 */ export type DbType = "postgresql" | "mysql" | "mariadb" | "mssql" | "oracle"; /** * DB별 파라미터 플레이스홀더 생성 */ export function getPlaceholder(dbType: string, index: number): string { const normalizedType = dbType.toLowerCase(); switch (normalizedType) { case "postgresql": return `$${index}`; case "mysql": case "mariadb": return "?"; case "mssql": return `@p${index}`; case "oracle": return `:${index}`; default: // 기본값은 PostgreSQL return `$${index}`; } } /** * UPDATE 쿼리 생성 */ export function buildUpdateQuery( dbType: string, tableName: string, updates: { column: string; value: any }[], whereColumn: string = "id" ): { query: string; values: any[] } { const normalizedType = dbType.toLowerCase(); const values: any[] = []; // SET 절 생성 const setClause = updates .map((update, index) => { values.push(update.value); const placeholder = getPlaceholder(normalizedType, values.length); return `${update.column} = ${placeholder}`; }) .join(", "); // WHERE 절 생성 values.push(undefined); // whereValue는 나중에 설정 const wherePlaceholder = getPlaceholder(normalizedType, values.length); // updated_at 처리 (DB별 NOW() 함수) let updatedAtExpr = "NOW()"; if (normalizedType === "mssql") { updatedAtExpr = "GETDATE()"; } else if (normalizedType === "oracle") { updatedAtExpr = "SYSDATE"; } const query = ` UPDATE ${tableName} SET ${setClause}, updated_at = ${updatedAtExpr} WHERE ${whereColumn} = ${wherePlaceholder} `; return { query, values }; } /** * INSERT 쿼리 생성 */ export function buildInsertQuery( dbType: string, tableName: string, data: Record ): { query: string; values: any[]; returningClause: string } { const normalizedType = dbType.toLowerCase(); const columns = Object.keys(data); const values = Object.values(data); // 플레이스홀더 생성 const placeholders = columns .map((_, index) => getPlaceholder(normalizedType, index + 1)) .join(", "); let query = ` INSERT INTO ${tableName} (${columns.join(", ")}) VALUES (${placeholders}) `; // RETURNING/OUTPUT 절 추가 (DB별로 다름) let returningClause = ""; if (normalizedType === "postgresql") { query += " RETURNING id"; returningClause = "RETURNING id"; } else if (normalizedType === "mssql") { // MSSQL은 OUTPUT 절을 INSERT와 VALUES 사이에 const insertIndex = query.indexOf("VALUES"); query = query.substring(0, insertIndex) + "OUTPUT INSERTED.id " + query.substring(insertIndex); returningClause = "OUTPUT INSERTED.id"; } else if (normalizedType === "oracle") { query += " RETURNING id INTO :out_id"; returningClause = "RETURNING id INTO :out_id"; } // MySQL/MariaDB는 RETURNING 없음, LAST_INSERT_ID() 사용 return { query, values, returningClause }; } /** * SELECT 쿼리 생성 */ export function buildSelectQuery( dbType: string, tableName: string, whereColumn: string = "id" ): { query: string; placeholder: string } { const normalizedType = dbType.toLowerCase(); const placeholder = getPlaceholder(normalizedType, 1); const query = `SELECT * FROM ${tableName} WHERE ${whereColumn} = ${placeholder}`; return { query, placeholder }; } /** * LIMIT/OFFSET 쿼리 생성 (페이징) */ export function buildPaginationClause( dbType: string, limit?: number, offset?: number ): string { const normalizedType = dbType.toLowerCase(); if (!limit) { return ""; } if ( normalizedType === "postgresql" || normalizedType === "mysql" || normalizedType === "mariadb" ) { // PostgreSQL, MySQL, MariaDB: LIMIT ... OFFSET ... let clause = ` LIMIT ${limit}`; if (offset) { clause += ` OFFSET ${offset}`; } return clause; } else if (normalizedType === "mssql") { // MSSQL: OFFSET ... ROWS FETCH NEXT ... ROWS ONLY if (offset) { return ` OFFSET ${offset} ROWS FETCH NEXT ${limit} ROWS ONLY`; } else { return ` OFFSET 0 ROWS FETCH NEXT ${limit} ROWS ONLY`; } } else if (normalizedType === "oracle") { // Oracle: ROWNUM 또는 FETCH FIRST (12c+) if (offset) { return ` OFFSET ${offset} ROWS FETCH NEXT ${limit} ROWS ONLY`; } else { return ` FETCH FIRST ${limit} ROWS ONLY`; } } return ""; } /** * 트랜잭션 시작 */ export function getBeginTransactionQuery(dbType: string): string { const normalizedType = dbType.toLowerCase(); if (normalizedType === "mssql") { return "BEGIN TRANSACTION"; } return "BEGIN"; } /** * 트랜잭션 커밋 */ export function getCommitQuery(dbType: string): string { return "COMMIT"; } /** * 트랜잭션 롤백 */ export function getRollbackQuery(dbType: string): string { return "ROLLBACK"; } /** * DB 연결 테스트 쿼리 */ export function getConnectionTestQuery(dbType: string): string { const normalizedType = dbType.toLowerCase(); switch (normalizedType) { case "postgresql": return "SELECT 1"; case "mysql": case "mariadb": return "SELECT 1"; case "mssql": return "SELECT 1"; case "oracle": return "SELECT 1 FROM DUAL"; default: return "SELECT 1"; } }