diff --git a/backend-node/src/services/tableManagementService.ts b/backend-node/src/services/tableManagementService.ts index 0ab0c4cf..9fee8c2c 100644 --- a/backend-node/src/services/tableManagementService.ts +++ b/backend-node/src/services/tableManagementService.ts @@ -1,4 +1,4 @@ -import prisma from "../config/database"; +import { query, queryOne, transaction } from "../database/db"; import { logger } from "../utils/logger"; import { cache, CacheKeys } from "../utils/cache"; import { @@ -28,13 +28,14 @@ export class TableManagementService { ): Promise<{ isCodeType: boolean; codeCategory?: string }> { try { // column_labels 테이블에서 해당 컬럼의 web_type이 'code'인지 확인 - const result = await prisma.$queryRaw` - SELECT web_type, code_category - FROM column_labels - WHERE table_name = ${tableName} - AND column_name = ${columnName} - AND web_type = 'code' - `; + const result = await query( + `SELECT web_type, code_category + FROM column_labels + WHERE table_name = $1 + AND column_name = $2 + AND web_type = 'code'`, + [tableName, columnName] + ); if (Array.isArray(result) && result.length > 0) { const row = result[0] as any; @@ -70,8 +71,8 @@ export class TableManagementService { } // information_schema는 여전히 $queryRaw 사용 - const rawTables = await prisma.$queryRaw` - SELECT + const rawTables = await query( + `SELECT t.table_name as "tableName", COALESCE(tl.table_label, t.table_name) as "displayName", COALESCE(tl.description, '') as "description", @@ -83,8 +84,8 @@ export class TableManagementService { AND t.table_type = 'BASE TABLE' AND t.table_name NOT LIKE 'pg_%' AND t.table_name NOT LIKE 'sql_%' - ORDER BY t.table_name - `; + ORDER BY t.table_name` + ); // BigInt를 Number로 변환하여 JSON 직렬화 문제 해결 const tables: TableInfo[] = rawTables.map((table) => ({ @@ -147,11 +148,12 @@ export class TableManagementService { // 전체 컬럼 수 조회 (캐시 확인) let total = cache.get(countCacheKey); if (!total) { - const totalResult = await prisma.$queryRaw<[{ count: bigint }]>` - SELECT COUNT(*) as count - FROM information_schema.columns c - WHERE c.table_name = ${tableName} - `; + const totalResult = await query<{ count: bigint }>( + `SELECT COUNT(*) as count + FROM information_schema.columns c + WHERE c.table_name = $1`, + [tableName] + ); total = Number(totalResult[0].count); // 컬럼 수는 자주 변하지 않으므로 30분 캐시 cache.set(countCacheKey, total, 30 * 60 * 1000); @@ -159,8 +161,8 @@ export class TableManagementService { // 페이지네이션 적용한 컬럼 조회 const offset = (page - 1) * size; - const rawColumns = await prisma.$queryRaw` - SELECT + const rawColumns = await query( + `SELECT c.column_name as "columnName", COALESCE(cl.column_label, c.column_name) as "displayName", c.data_type as "dataType", @@ -195,12 +197,13 @@ export class TableManagementService { ON tc.constraint_name = kcu.constraint_name AND tc.table_schema = kcu.table_schema WHERE tc.constraint_type = 'PRIMARY KEY' - AND tc.table_name = ${tableName} + AND tc.table_name = $1 ) pk ON c.column_name = pk.column_name AND c.table_name = pk.table_name - WHERE c.table_name = ${tableName} + WHERE c.table_name = $1 ORDER BY c.ordinal_position - LIMIT ${size} OFFSET ${offset} - `; + LIMIT $2 OFFSET $3`, + [tableName, size, offset] + ); // BigInt를 Number로 변환하여 JSON 직렬화 문제 해결 const columns: ColumnTypeInfo[] = rawColumns.map((column) => ({ @@ -251,15 +254,12 @@ export class TableManagementService { try { logger.info(`테이블 라벨 자동 추가 시작: ${tableName}`); - await prisma.table_labels.upsert({ - where: { table_name: tableName }, - update: {}, // 이미 존재하면 변경하지 않음 - create: { - table_name: tableName, - table_label: tableName, - description: "", - }, - }); + await query( + `INSERT INTO table_labels (table_name, table_label, description, created_date, updated_date) + VALUES ($1, $2, $3, NOW(), NOW()) + ON CONFLICT (table_name) DO NOTHING`, + [tableName, tableName, ""] + ); logger.info(`테이블 라벨 자동 추가 완료: ${tableName}`); } catch (error) { @@ -282,15 +282,16 @@ export class TableManagementService { logger.info(`테이블 라벨 업데이트 시작: ${tableName}`); // table_labels 테이블에 UPSERT - await prisma.$executeRaw` - INSERT INTO table_labels (table_name, table_label, description, created_date, updated_date) - VALUES (${tableName}, ${displayName}, ${description || ""}, NOW(), NOW()) - ON CONFLICT (table_name) - DO UPDATE SET - table_label = EXCLUDED.table_label, - description = EXCLUDED.description, - updated_date = NOW() - `; + await query( + `INSERT INTO table_labels (table_name, table_label, description, created_date, updated_date) + VALUES ($1, $2, $3, NOW(), NOW()) + ON CONFLICT (table_name) + DO UPDATE SET + table_label = EXCLUDED.table_label, + description = EXCLUDED.description, + updated_date = NOW()`, + [tableName, displayName, description || ""] + ); // 캐시 무효화 cache.delete(CacheKeys.TABLE_LIST); @@ -320,43 +321,40 @@ export class TableManagementService { await this.insertTableIfNotExists(tableName); // column_labels 업데이트 또는 생성 - await prisma.column_labels.upsert({ - where: { - table_name_column_name: { - table_name: tableName, - column_name: columnName, - }, - }, - update: { - column_label: settings.columnLabel, - input_type: settings.inputType, - detail_settings: settings.detailSettings, - code_category: settings.codeCategory, - code_value: settings.codeValue, - reference_table: settings.referenceTable, - reference_column: settings.referenceColumn, - display_column: settings.displayColumn, // 🎯 Entity 조인에서 표시할 컬럼명 - display_order: settings.displayOrder || 0, - is_visible: - settings.isVisible !== undefined ? settings.isVisible : true, - updated_date: new Date(), - }, - create: { - table_name: tableName, - column_name: columnName, - column_label: settings.columnLabel, - input_type: settings.inputType, - detail_settings: settings.detailSettings, - code_category: settings.codeCategory, - code_value: settings.codeValue, - reference_table: settings.referenceTable, - reference_column: settings.referenceColumn, - display_column: settings.displayColumn, // 🎯 Entity 조인에서 표시할 컬럼명 - display_order: settings.displayOrder || 0, - is_visible: - settings.isVisible !== undefined ? settings.isVisible : true, - }, - }); + await query( + `INSERT INTO column_labels ( + table_name, column_name, column_label, input_type, detail_settings, + code_category, code_value, reference_table, reference_column, + display_column, display_order, is_visible, created_date, updated_date + ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, NOW(), NOW()) + ON CONFLICT (table_name, column_name) + DO UPDATE SET + column_label = EXCLUDED.column_label, + input_type = EXCLUDED.input_type, + detail_settings = EXCLUDED.detail_settings, + code_category = EXCLUDED.code_category, + code_value = EXCLUDED.code_value, + reference_table = EXCLUDED.reference_table, + reference_column = EXCLUDED.reference_column, + display_column = EXCLUDED.display_column, + display_order = EXCLUDED.display_order, + is_visible = EXCLUDED.is_visible, + updated_date = NOW()`, + [ + tableName, + columnName, + settings.columnLabel, + settings.inputType, + settings.detailSettings, + settings.codeCategory, + settings.codeValue, + settings.referenceTable, + settings.referenceColumn, + settings.displayColumn, + settings.displayOrder || 0, + settings.isVisible !== undefined ? settings.isVisible : true, + ] + ); // 캐시 무효화 - 해당 테이블의 컬럼 캐시 삭제 cache.deleteByPattern(`table_columns:${tableName}:`); @@ -387,8 +385,8 @@ export class TableManagementService { `전체 컬럼 설정 일괄 업데이트 시작: ${tableName}, ${columnSettings.length}개` ); - // Prisma 트랜잭션 사용 - await prisma.$transaction(async (tx) => { + // Raw Query 트랜잭션 사용 + await transaction(async (client) => { // 테이블이 table_labels에 없으면 자동 추가 await this.insertTableIfNotExists(tableName); @@ -434,16 +432,18 @@ export class TableManagementService { try { logger.info(`테이블 라벨 정보 조회 시작: ${tableName}`); - const tableLabel = await prisma.table_labels.findUnique({ - where: { table_name: tableName }, - select: { - table_name: true, - table_label: true, - description: true, - created_date: true, - updated_date: true, - }, - }); + const tableLabel = await queryOne<{ + table_name: string; + table_label: string | null; + description: string | null; + created_date: Date | null; + updated_date: Date | null; + }>( + `SELECT table_name, table_label, description, created_date, updated_date + FROM table_labels + WHERE table_name = $1`, + [tableName] + ); if (!tableLabel) { return null; @@ -478,31 +478,30 @@ export class TableManagementService { try { logger.info(`컬럼 라벨 정보 조회 시작: ${tableName}.${columnName}`); - const columnLabel = await prisma.column_labels.findUnique({ - where: { - table_name_column_name: { - table_name: tableName, - column_name: columnName, - }, - }, - select: { - id: true, - table_name: true, - column_name: true, - column_label: true, - web_type: true, - detail_settings: true, - description: true, - display_order: true, - is_visible: true, - code_category: true, - code_value: true, - reference_table: true, - reference_column: true, - created_date: true, - updated_date: true, - }, - }); + const columnLabel = await queryOne<{ + id: number; + table_name: string; + column_name: string; + column_label: string | null; + web_type: string | null; + detail_settings: any; + description: string | null; + display_order: number | null; + is_visible: boolean | null; + code_category: string | null; + code_value: string | null; + reference_table: string | null; + reference_column: string | null; + created_date: Date | null; + updated_date: Date | null; + }>( + `SELECT id, table_name, column_name, column_label, web_type, detail_settings, + description, display_order, is_visible, code_category, code_value, + reference_table, reference_column, created_date, updated_date + FROM column_labels + WHERE table_name = $1 AND column_name = $2`, + [tableName, columnName] + ); if (!columnLabel) { return null; @@ -563,57 +562,28 @@ export class TableManagementService { ...detailSettings, }; - // column_labels 테이블에 해당 컬럼이 있는지 확인 - const existingColumn = await prisma.column_labels.findFirst({ - where: { - table_name: tableName, - column_name: columnName, - }, - }); - - if (existingColumn) { - // 기존 컬럼 라벨 업데이트 - const updateData: any = { - web_type: webType, - detail_settings: JSON.stringify(finalDetailSettings), - updated_date: new Date(), - }; - - if (inputType) { - updateData.input_type = inputType; - } - - await prisma.column_labels.update({ - where: { - id: existingColumn.id, - }, - data: updateData, - }); - logger.info( - `컬럼 웹 타입 업데이트 완료: ${tableName}.${columnName} = ${webType}` - ); - } else { - // 새로운 컬럼 라벨 생성 - const createData: any = { - table_name: tableName, - column_name: columnName, - web_type: webType, - detail_settings: JSON.stringify(finalDetailSettings), - created_date: new Date(), - updated_date: new Date(), - }; - - if (inputType) { - createData.input_type = inputType; - } - - await prisma.column_labels.create({ - data: createData, - }); - logger.info( - `컬럼 라벨 생성 및 웹 타입 설정 완료: ${tableName}.${columnName} = ${webType}` - ); - } + // column_labels UPSERT로 업데이트 또는 생성 + await query( + `INSERT INTO column_labels ( + table_name, column_name, web_type, detail_settings, input_type, created_date, updated_date + ) VALUES ($1, $2, $3, $4, $5, NOW(), NOW()) + ON CONFLICT (table_name, column_name) + DO UPDATE SET + web_type = EXCLUDED.web_type, + detail_settings = EXCLUDED.detail_settings, + input_type = COALESCE(EXCLUDED.input_type, column_labels.input_type), + updated_date = NOW()`, + [ + tableName, + columnName, + webType, + JSON.stringify(finalDetailSettings), + inputType || null, + ] + ); + logger.info( + `컬럼 웹 타입 설정 완료: ${tableName}.${columnName} = ${webType}` + ); } catch (error) { logger.error( `컬럼 웹 타입 설정 중 오류 발생: ${tableName}.${columnName}`, @@ -650,20 +620,18 @@ export class TableManagementService { }; // table_type_columns 테이블에서 업데이트 - await prisma.$executeRaw` - INSERT INTO table_type_columns ( + await query( + `INSERT INTO table_type_columns ( table_name, column_name, input_type, detail_settings, is_nullable, display_order, created_date, updated_date - ) VALUES ( - ${tableName}, ${columnName}, ${inputType}, ${JSON.stringify(finalDetailSettings)}, - 'Y', 0, now(), now() - ) + ) VALUES ($1, $2, $3, $4, 'Y', 0, now(), now()) ON CONFLICT (table_name, column_name) DO UPDATE SET - input_type = ${inputType}, - detail_settings = ${JSON.stringify(finalDetailSettings)}, - updated_date = now(); - `; + input_type = EXCLUDED.input_type, + detail_settings = EXCLUDED.detail_settings, + updated_date = now()`, + [tableName, columnName, inputType, JSON.stringify(finalDetailSettings)] + ); logger.info( `컬럼 입력 타입 설정 완료: ${tableName}.${columnName} = ${inputType}` @@ -911,27 +879,24 @@ export class TableManagementService { ); // 🎯 컬럼명을 doc_type으로 사용하여 파일 구분 - const fileInfos = await prisma.attach_file_info.findMany({ - where: { - target_objid: String(targetObjid), - doc_type: columnName, // 컬럼명으로 파일 구분 - status: "ACTIVE", - }, - select: { - objid: true, - real_file_name: true, - file_size: true, - file_ext: true, - file_path: true, - doc_type: true, - doc_type_name: true, - regdate: true, - writer: true, - }, - orderBy: { - regdate: "desc", - }, - }); + const fileInfos = await query<{ + objid: string; + real_file_name: string; + file_size: number; + file_ext: string; + file_path: string; + doc_type: string; + doc_type_name: string; + regdate: Date; + writer: string; + }>( + `SELECT objid, real_file_name, file_size, file_ext, file_path, + doc_type, doc_type_name, regdate, writer + FROM attach_file_info + WHERE target_objid = $1 AND doc_type = $2 AND status = 'ACTIVE' + ORDER BY regdate DESC`, + [String(targetObjid), columnName] + ); // 파일 정보 포맷팅 return fileInfos.map((fileInfo) => ({ @@ -956,23 +921,24 @@ export class TableManagementService { */ private async getFileInfoByPath(filePath: string): Promise { try { - const fileInfo = await prisma.attach_file_info.findFirst({ - where: { - file_path: filePath, - status: "ACTIVE", - }, - select: { - objid: true, - real_file_name: true, - file_size: true, - file_ext: true, - file_path: true, - doc_type: true, - doc_type_name: true, - regdate: true, - writer: true, - }, - }); + const fileInfo = await queryOne<{ + objid: string; + real_file_name: string; + file_size: number; + file_ext: string; + file_path: string; + doc_type: string; + doc_type_name: string; + regdate: Date; + writer: string; + }>( + `SELECT objid, real_file_name, file_size, file_ext, file_path, + doc_type, doc_type_name, regdate, writer + FROM attach_file_info + WHERE file_path = $1 AND status = 'ACTIVE' + LIMIT 1`, + [filePath] + ); if (!fileInfo) { return null; @@ -1000,17 +966,14 @@ export class TableManagementService { */ private async getFileTypeColumns(tableName: string): Promise { try { - const fileColumns = await prisma.column_labels.findMany({ - where: { - table_name: tableName, - web_type: "file", - }, - select: { - column_name: true, - }, - }); + const fileColumns = await query<{ column_name: string }>( + `SELECT column_name + FROM column_labels + WHERE table_name = $1 AND web_type = 'file'`, + [tableName] + ); - const columnNames = fileColumns.map((col: any) => col.column_name); + const columnNames = fileColumns.map((col) => col.column_name); logger.info(`파일 타입 컬럼 감지: ${tableName}`, columnNames); return columnNames; } catch (error) { @@ -1379,19 +1342,19 @@ export class TableManagementService { displayColumn?: string; } | null> { try { - const result = await prisma.column_labels.findFirst({ - where: { - table_name: tableName, - column_name: columnName, - }, - select: { - web_type: true, - code_category: true, - reference_table: true, - reference_column: true, - display_column: true, - }, - }); + const result = await queryOne<{ + web_type: string | null; + code_category: string | null; + reference_table: string | null; + reference_column: string | null; + display_column: string | null; + }>( + `SELECT web_type, code_category, reference_table, reference_column, display_column + FROM column_labels + WHERE table_name = $1 AND column_name = $2 + LIMIT 1`, + [tableName, columnName] + ); if (!result) { return null; @@ -1535,10 +1498,7 @@ export class TableManagementService { // 전체 개수 조회 const countQuery = `SELECT COUNT(*) as count FROM ${safeTableName} ${whereClause}`; - const countResult = await prisma.$queryRawUnsafe( - countQuery, - ...searchValues - ); + const countResult = await query(countQuery, ...searchValues); const total = parseInt(countResult[0].count); // 데이터 조회 @@ -1549,12 +1509,7 @@ export class TableManagementService { LIMIT $${paramIndex} OFFSET $${paramIndex + 1} `; - let data = await prisma.$queryRawUnsafe( - dataQuery, - ...searchValues, - size, - offset - ); + let data = await query(dataQuery, ...searchValues, size, offset); // 🎯 파일 컬럼이 있으면 파일 정보 보강 if (fileColumns.length > 0) { @@ -1699,10 +1654,9 @@ export class TableManagementService { ORDER BY ordinal_position `; - const columnInfoResult = (await prisma.$queryRawUnsafe( - columnInfoQuery, - tableName - )) as any[]; + const columnInfoResult = (await query(columnInfoQuery, [ + tableName, + ])) as any[]; const columnTypeMap = new Map(); columnInfoResult.forEach((col: any) => { @@ -1759,15 +1713,15 @@ export class TableManagementService { .join(", "); const columnNames = columns.map((col) => `"${col}"`).join(", "); - const query = ` + const insertQuery = ` INSERT INTO "${tableName}" (${columnNames}) VALUES (${placeholders}) `; - logger.info(`실행할 쿼리: ${query}`); + logger.info(`실행할 쿼리: ${insertQuery}`); logger.info(`쿼리 파라미터:`, values); - await prisma.$queryRawUnsafe(query, ...values); + await query(insertQuery, values); logger.info(`테이블 데이터 추가 완료: ${tableName}`); } catch (error) { @@ -1800,10 +1754,9 @@ export class TableManagementService { ORDER BY c.ordinal_position `; - const columnInfoResult = (await prisma.$queryRawUnsafe( - columnInfoQuery, - tableName - )) as any[]; + const columnInfoResult = (await query(columnInfoQuery, [ + tableName, + ])) as any[]; const columnTypeMap = new Map(); const primaryKeys: string[] = []; @@ -1866,7 +1819,7 @@ export class TableManagementService { } // UPDATE 쿼리 생성 - const query = ` + const updateQuery = ` UPDATE "${tableName}" SET ${setConditions.join(", ")} WHERE ${whereConditions.join(" AND ")} @@ -1874,10 +1827,10 @@ export class TableManagementService { const allValues = [...setValues, ...whereValues]; - logger.info(`실행할 UPDATE 쿼리: ${query}`); + logger.info(`실행할 UPDATE 쿼리: ${updateQuery}`); logger.info(`쿼리 파라미터:`, allValues); - const result = await prisma.$queryRawUnsafe(query, ...allValues); + const result = await query(updateQuery, allValues); logger.info(`테이블 데이터 수정 완료: ${tableName}`, result); } catch (error) { @@ -1946,9 +1899,10 @@ export class TableManagementService { ORDER BY kcu.ordinal_position `; - const primaryKeys = await prisma.$queryRawUnsafe< - { column_name: string }[] - >(primaryKeyQuery, tableName); + const primaryKeys = await query<{ column_name: string }>( + primaryKeyQuery, + [tableName] + ); if (primaryKeys.length === 0) { // 기본 키가 없는 경우, 모든 컬럼으로 삭제 조건 생성 @@ -1965,7 +1919,7 @@ export class TableManagementService { const deleteQuery = `DELETE FROM "${tableName}" WHERE ${conditions}`; - const result = await prisma.$queryRawUnsafe(deleteQuery, ...values); + const result = await query(deleteQuery, values); deletedCount += Number(result); } } else { @@ -1987,7 +1941,7 @@ export class TableManagementService { const deleteQuery = `DELETE FROM "${tableName}" WHERE ${conditions}`; - const result = await prisma.$queryRawUnsafe(deleteQuery, ...values); + const result = await query(deleteQuery, values); deletedCount += Number(result); } } @@ -2269,8 +2223,8 @@ export class TableManagementService { // 병렬 실행 const [dataResult, countResult] = await Promise.all([ - prisma.$queryRawUnsafe(dataQuery), - prisma.$queryRawUnsafe(countQuery), + query(dataQuery), + query(countQuery), ]); const data = Array.isArray(dataResult) ? dataResult : []; @@ -2642,17 +2596,16 @@ export class TableManagementService { data: Array<{ column_name: string; data_type: string }>; }> { try { - const columns = await prisma.$queryRaw< - Array<{ - column_name: string; - data_type: string; - }> - >` - SELECT column_name, data_type - FROM information_schema.columns - WHERE table_name = ${tableName} - ORDER BY ordinal_position - `; + const columns = await query<{ + column_name: string; + data_type: string; + }>( + `SELECT column_name, data_type + FROM information_schema.columns + WHERE table_name = $1 + ORDER BY ordinal_position`, + [tableName] + ); return { data: columns }; } catch (error) { @@ -2687,45 +2640,40 @@ export class TableManagementService { try { logger.info(`컬럼 라벨 업데이트: ${tableName}.${columnName}`); - await prisma.column_labels.upsert({ - where: { - table_name_column_name: { - table_name: tableName, - column_name: columnName, - }, - }, - update: { - column_label: updates.columnLabel, - web_type: updates.webType, - detail_settings: updates.detailSettings, - description: updates.description, - display_order: updates.displayOrder, - is_visible: updates.isVisible, - code_category: updates.codeCategory, - code_value: updates.codeValue, - reference_table: updates.referenceTable, - reference_column: updates.referenceColumn, - // display_column: updates.displayColumn, // 🎯 새로 추가 (임시 주석) - updated_date: new Date(), - }, - create: { - table_name: tableName, - column_name: columnName, - column_label: updates.columnLabel || columnName, - web_type: updates.webType || "text", - detail_settings: updates.detailSettings, - description: updates.description, - display_order: updates.displayOrder || 0, - is_visible: updates.isVisible !== false, - code_category: updates.codeCategory, - code_value: updates.codeValue, - reference_table: updates.referenceTable, - reference_column: updates.referenceColumn, - // display_column: updates.displayColumn, // 🎯 새로 추가 (임시 주석) - created_date: new Date(), - updated_date: new Date(), - }, - }); + await query( + `INSERT INTO column_labels ( + table_name, column_name, column_label, web_type, detail_settings, + description, display_order, is_visible, code_category, code_value, + reference_table, reference_column, created_date, updated_date + ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, NOW(), NOW()) + ON CONFLICT (table_name, column_name) + DO UPDATE SET + column_label = EXCLUDED.column_label, + web_type = EXCLUDED.web_type, + detail_settings = EXCLUDED.detail_settings, + description = EXCLUDED.description, + display_order = EXCLUDED.display_order, + is_visible = EXCLUDED.is_visible, + code_category = EXCLUDED.code_category, + code_value = EXCLUDED.code_value, + reference_table = EXCLUDED.reference_table, + reference_column = EXCLUDED.reference_column, + updated_date = NOW()`, + [ + tableName, + columnName, + updates.columnLabel || columnName, + updates.webType || "text", + updates.detailSettings, + updates.description, + updates.displayOrder || 0, + updates.isVisible !== false, + updates.codeCategory, + updates.codeValue, + updates.referenceTable, + updates.referenceColumn, + ] + ); logger.info(`컬럼 라벨 업데이트 완료: ${tableName}.${columnName}`); } catch (error) { @@ -2949,8 +2897,8 @@ export class TableManagementService { try { logger.info(`테이블 스키마 정보 조회: ${tableName}`); - const rawColumns = await prisma.$queryRaw` - SELECT + const rawColumns = await query( + `SELECT column_name as "columnName", column_name as "displayName", data_type as "dataType", @@ -2963,15 +2911,16 @@ export class TableManagementService { CASE WHEN column_name IN ( SELECT column_name FROM information_schema.key_column_usage - WHERE table_name = ${tableName} AND constraint_name LIKE '%_pkey' + WHERE table_name = $1 AND constraint_name LIKE '%_pkey' ) THEN true ELSE false END as "isPrimaryKey" FROM information_schema.columns - WHERE table_name = ${tableName} + WHERE table_name = $1 AND table_schema = 'public' - ORDER BY ordinal_position - `; + ORDER BY ordinal_position`, + [tableName] + ); const columns: ColumnTypeInfo[] = rawColumns.map((col) => ({ tableName: tableName, @@ -3012,14 +2961,15 @@ export class TableManagementService { try { logger.info(`테이블 존재 여부 확인: ${tableName}`); - const result = await prisma.$queryRaw` - SELECT EXISTS ( + const result = await query( + `SELECT EXISTS ( SELECT 1 FROM information_schema.tables - WHERE table_name = ${tableName} + WHERE table_name = $1 AND table_schema = 'public' AND table_type = 'BASE TABLE' - ) as "exists" - `; + ) as "exists"`, + [tableName] + ); const exists = result[0]?.exists || false; logger.info(`테이블 존재 여부: ${tableName} = ${exists}`); @@ -3038,8 +2988,8 @@ export class TableManagementService { logger.info(`컬럼 입력타입 정보 조회: ${tableName}`); // table_type_columns에서 입력타입 정보 조회 - const rawInputTypes = await prisma.$queryRaw` - SELECT + const rawInputTypes = await query( + `SELECT ttc.column_name as "columnName", ttc.column_name as "displayName", COALESCE(ttc.input_type, 'text') as "inputType", @@ -3049,9 +2999,10 @@ export class TableManagementService { FROM table_type_columns ttc LEFT JOIN information_schema.columns ic ON ttc.table_name = ic.table_name AND ttc.column_name = ic.column_name - WHERE ttc.table_name = ${tableName} - ORDER BY ttc.display_order, ttc.column_name - `; + WHERE ttc.table_name = $1 + ORDER BY ttc.display_order, ttc.column_name`, + [tableName] + ); const inputTypes: ColumnTypeInfo[] = rawInputTypes.map((col) => ({ tableName: tableName, @@ -3099,7 +3050,7 @@ export class TableManagementService { logger.info("데이터베이스 연결 상태 확인"); // 간단한 쿼리로 연결 테스트 - const result = await prisma.$queryRaw`SELECT 1 as "test"`; + const result = await query(`SELECT 1 as "test"`); if (result && result.length > 0) { logger.info("데이터베이스 연결 성공");