feat: Phase 3.16 데이터 관리 서비스 Raw Query 전환 완료
4개 서비스 18개 Prisma 호출 전환 완료: 1. **EnhancedDynamicFormService** (6개) - validateTableExists - information_schema 조회 - getTableColumns - 테이블 컬럼 정보 조회 with 캐싱 - getColumnWebTypes - 웹타입 정보 조회 - getPrimaryKeys - Primary Key 조회 - performInsert - 동적 INSERT with RETURNING - performUpdate - 동적 UPDATE with RETURNING 2. **DataMappingService** (5개) - getSourceData - 소스 테이블 데이터 조회 - executeInsert - 동적 INSERT - executeUpsert - ON CONFLICT DO UPDATE - executeUpdate - 동적 UPDATE - disconnect - 제거 (Raw Query 불필요) 3. **DataService** (4개) - getTableData - 동적 SELECT with 동적 WHERE/ORDER BY - checkTableExists - information_schema 테이블 존재 확인 - getTableColumnsSimple - 컬럼 정보 조회 - getColumnLabel - 컬럼 라벨 조회 4. **AdminService** (3개) - getAdminMenuList - WITH RECURSIVE 쿼리 - getUserMenuList - WITH RECURSIVE 쿼리 - getMenuInfo - LEFT JOIN으로 회사 정보 포함 기술적 성과: - 변수명 충돌 해결 (query vs sql) - WITH RECURSIVE 쿼리 전환 - Prisma include → LEFT JOIN 전환 - 동적 쿼리 생성 (WHERE, ORDER BY) - SQL 인젝션 방지 (컬럼명 검증) 진행률: Phase 3 173/186 (93.0%) 문서: PHASE3.16_DATA_MANAGEMENT_SERVICES_MIGRATION.md
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
* 타입 안전성과 검증 강화
|
||||
*/
|
||||
|
||||
import { PrismaClient } from "@prisma/client";
|
||||
import { query, queryOne } from "../database/db";
|
||||
import {
|
||||
WebType,
|
||||
DynamicWebType,
|
||||
@@ -14,8 +14,6 @@ import {
|
||||
} from "../types/unified-web-types";
|
||||
import { DataflowControlService } from "./dataflowControlService";
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
// 테이블 컬럼 정보
|
||||
export interface TableColumn {
|
||||
column_name: string;
|
||||
@@ -156,17 +154,15 @@ export class EnhancedDynamicFormService {
|
||||
*/
|
||||
private async validateTableExists(tableName: string): Promise<boolean> {
|
||||
try {
|
||||
const result = await prisma.$queryRawUnsafe(
|
||||
`
|
||||
SELECT EXISTS (
|
||||
const result = await query<{ exists: boolean }>(
|
||||
`SELECT EXISTS (
|
||||
SELECT FROM information_schema.tables
|
||||
WHERE table_name = $1
|
||||
) as exists
|
||||
`,
|
||||
tableName
|
||||
) as exists`,
|
||||
[tableName]
|
||||
);
|
||||
|
||||
return (result as any)[0]?.exists || false;
|
||||
return result[0]?.exists || false;
|
||||
} catch (error) {
|
||||
console.error(`❌ 테이블 존재 여부 확인 실패: ${tableName}`, error);
|
||||
return false;
|
||||
@@ -184,9 +180,8 @@ export class EnhancedDynamicFormService {
|
||||
}
|
||||
|
||||
try {
|
||||
const columns = (await prisma.$queryRawUnsafe(
|
||||
`
|
||||
SELECT
|
||||
const columns = await query<TableColumn>(
|
||||
`SELECT
|
||||
column_name,
|
||||
data_type,
|
||||
is_nullable,
|
||||
@@ -196,10 +191,9 @@ export class EnhancedDynamicFormService {
|
||||
numeric_scale
|
||||
FROM information_schema.columns
|
||||
WHERE table_name = $1
|
||||
ORDER BY ordinal_position
|
||||
`,
|
||||
tableName
|
||||
)) as TableColumn[];
|
||||
ORDER BY ordinal_position`,
|
||||
[tableName]
|
||||
);
|
||||
|
||||
// 캐시 저장 (10분)
|
||||
this.columnCache.set(tableName, columns);
|
||||
@@ -226,18 +220,21 @@ export class EnhancedDynamicFormService {
|
||||
|
||||
try {
|
||||
// table_type_columns에서 웹타입 정보 조회
|
||||
const webTypeData = (await prisma.$queryRawUnsafe(
|
||||
`
|
||||
SELECT
|
||||
const webTypeData = await query<{
|
||||
column_name: string;
|
||||
web_type: string;
|
||||
is_nullable: string;
|
||||
detail_settings: any;
|
||||
}>(
|
||||
`SELECT
|
||||
column_name,
|
||||
web_type,
|
||||
is_nullable,
|
||||
detail_settings
|
||||
FROM table_type_columns
|
||||
WHERE table_name = $1
|
||||
`,
|
||||
tableName
|
||||
)) as any[];
|
||||
WHERE table_name = $1`,
|
||||
[tableName]
|
||||
);
|
||||
|
||||
const columnWebTypes: ColumnWebTypeInfo[] = webTypeData.map((row) => ({
|
||||
columnName: row.column_name,
|
||||
@@ -555,15 +552,13 @@ export class EnhancedDynamicFormService {
|
||||
*/
|
||||
private async getPrimaryKeys(tableName: string): Promise<string[]> {
|
||||
try {
|
||||
const result = (await prisma.$queryRawUnsafe(
|
||||
`
|
||||
SELECT column_name
|
||||
const result = await query<{ column_name: string }>(
|
||||
`SELECT column_name
|
||||
FROM information_schema.key_column_usage
|
||||
WHERE table_name = $1
|
||||
AND constraint_name LIKE '%_pkey'
|
||||
`,
|
||||
tableName
|
||||
)) as any[];
|
||||
AND constraint_name LIKE '%_pkey'`,
|
||||
[tableName]
|
||||
);
|
||||
|
||||
return result.map((row) => row.column_name);
|
||||
} catch (error) {
|
||||
@@ -594,10 +589,7 @@ export class EnhancedDynamicFormService {
|
||||
query: insertQuery.replace(/\n\s+/g, " "),
|
||||
});
|
||||
|
||||
const result = (await prisma.$queryRawUnsafe(
|
||||
insertQuery,
|
||||
...values
|
||||
)) as any[];
|
||||
const result = await query<any>(insertQuery, values);
|
||||
|
||||
return {
|
||||
data: result[0],
|
||||
@@ -649,10 +641,7 @@ export class EnhancedDynamicFormService {
|
||||
query: updateQuery.replace(/\n\s+/g, " "),
|
||||
});
|
||||
|
||||
const result = (await prisma.$queryRawUnsafe(
|
||||
updateQuery,
|
||||
...updateValues
|
||||
)) as any[];
|
||||
const result = await query<any>(updateQuery, updateValues);
|
||||
|
||||
return {
|
||||
data: result[0],
|
||||
|
||||
Reference in New Issue
Block a user