feat: Phase 3.10 EventTriggerService Raw Query 전환 완료

6개 Prisma 호출을 모두 Raw Query로 전환
- JSON 필드 검색 (JSONB 연산자 활용)
- 동적 INSERT 쿼리 (PostgreSQL 플레이스홀더)
- 동적 UPDATE 쿼리 (WHERE 조건 + 플레이스홀더)
- 동적 DELETE 쿼리 (WHERE 조건)
- UPSERT 쿼리 (ON CONFLICT)
- 다이어그램 단건 조회 (findUnique → queryOne)

주요 기술적 해결:
- JSON 필드 검색 ($queryRaw → query)
  - category::text = '"data-save"'
  - category::jsonb ? 'data-save'
  - category::jsonb @> '["data-save"]'
- MySQL 플레이스홀더(?) → PostgreSQL 플레이스홀더($1, $2, ...)
- 동적 테이블 INSERT/UPDATE/DELETE (보안 강화)
- ON CONFLICT를 사용한 UPSERT
- 조건부 실행 로직 유지

TypeScript 컴파일 성공
Prisma import 완전 제거

Phase 3 진행률: 120/162 (74.1%)
전체 진행률: 371/444 (83.6%)
This commit is contained in:
kjs 2025-10-01 11:43:19 +09:00
parent 16d4ba4a51
commit 134d24579c
2 changed files with 40 additions and 27 deletions

View File

@ -131,7 +131,7 @@ backend-node/ (루트)
- `layoutService.ts` (0개) - ✅ **전환 완료** (Phase 3.7)
- `dbTypeCategoryService.ts` (0개) - ✅ **전환 완료** (Phase 3.8)
- `templateStandardService.ts` (0개) - ✅ **전환 완료** (Phase 3.9)
- `eventTriggerService.ts` (6개) - JSON 검색 쿼리
- `eventTriggerService.ts` (0개) - ✅ **전환 완료** (Phase 3.10)
#### 🟡 **중간 (단순 CRUD) - 3순위**
@ -1214,6 +1214,16 @@ describe("Performance Benchmarks", () => {
- [x] DISTINCT 쿼리 (카테고리 목록)
- [x] TypeScript 컴파일 성공
- [x] Prisma import 완전 제거
- [x] **EventTriggerService 전환 (6개)****완료** (Phase 3.10)
- [x] 6개 Prisma 호출 전환 완료 (이벤트 트리거, JSON 검색)
- [x] JSON 필드 검색 ($queryRaw → query, JSONB 연산자)
- [x] 동적 INSERT 쿼리 (PostgreSQL 플레이스홀더)
- [x] 동적 UPDATE 쿼리 (WHERE 조건 + 플레이스홀더)
- [x] 동적 DELETE 쿼리 (WHERE 조건)
- [x] UPSERT 쿼리 (ON CONFLICT)
- [x] 다이어그램 조회 (findUnique → queryOne)
- [x] TypeScript 컴파일 성공
- [x] Prisma import 완전 제거
- [ ] 배치 관련 서비스 전환 (26개) ⭐ 대규모 신규 발견
- [ ] BatchExternalDbService (8개)
- [ ] BatchExecutionLogService (7개), BatchManagementService (5개)

View File

@ -1,8 +1,6 @@
import { PrismaClient } from "@prisma/client";
import { query, queryOne } from "../database/db";
import { logger } from "../utils/logger";
const prisma = new PrismaClient();
// 조건 노드 타입 정의
interface ConditionNode {
id: string; // 고유 ID
@ -92,15 +90,16 @@ export class EventTriggerService {
try {
// 🔥 수정: Raw SQL을 사용하여 JSON 배열 검색
const diagrams = (await prisma.$queryRaw`
SELECT * FROM dataflow_diagrams
WHERE company_code = ${companyCode}
AND (
category::text = '"data-save"' OR
category::jsonb ? 'data-save' OR
category::jsonb @> '["data-save"]'
)
`) as any[];
const diagrams = await query<any>(
`SELECT * FROM dataflow_diagrams
WHERE company_code = $1
AND (
category::text = '"data-save"' OR
category::jsonb ? 'data-save' OR
category::jsonb @> '["data-save"]'
)`,
[companyCode]
);
// 각 관계도에서 해당 테이블을 소스로 하는 데이터 저장 관계들 필터링
const matchingDiagrams = diagrams.filter((diagram) => {
@ -537,13 +536,14 @@ export class EventTriggerService {
data: Record<string, any>
): Promise<void> {
// 동적 테이블 INSERT 실행
const sql = `INSERT INTO ${tableName} (${Object.keys(data).join(", ")}) VALUES (${Object.keys(
data
)
.map(() => "?")
.join(", ")})`;
// PostgreSQL 파라미터 플레이스홀더로 변경 (? → $1, $2, ...)
const values = Object.values(data);
const placeholders = values.map((_, i) => `$${i + 1}`).join(", ");
const sql = `INSERT INTO ${tableName} (${Object.keys(data).join(
", "
)}) VALUES (${placeholders})`;
await prisma.$executeRawUnsafe(sql, ...Object.values(data));
await query(sql, values);
logger.info(`Inserted data into ${tableName}:`, data);
}
@ -563,14 +563,15 @@ export class EventTriggerService {
}
// 동적 테이블 UPDATE 실행
const values = Object.values(data);
const setClause = Object.keys(data)
.map((key) => `${key} = ?`)
.map((key, i) => `${key} = $${i + 1}`)
.join(", ");
const whereClause = this.buildWhereClause(conditions);
const sql = `UPDATE ${tableName} SET ${setClause} WHERE ${whereClause}`;
await prisma.$executeRawUnsafe(sql, ...Object.values(data));
await query(sql, values);
logger.info(`Updated data in ${tableName}:`, data);
}
@ -593,7 +594,7 @@ export class EventTriggerService {
const whereClause = this.buildWhereClause(conditions);
const sql = `DELETE FROM ${tableName} WHERE ${whereClause}`;
await prisma.$executeRawUnsafe(sql);
await query(sql, []);
logger.info(`Deleted data from ${tableName} with conditions`);
}
@ -608,15 +609,16 @@ export class EventTriggerService {
const columns = Object.keys(data);
const values = Object.values(data);
const conflictColumns = ["id", "company_code"]; // 기본 충돌 컬럼
const placeholders = values.map((_, i) => `$${i + 1}`).join(", ");
const sql = `
INSERT INTO ${tableName} (${columns.join(", ")})
VALUES (${columns.map(() => "?").join(", ")})
VALUES (${placeholders})
ON CONFLICT (${conflictColumns.join(", ")})
DO UPDATE SET ${columns.map((col) => `${col} = EXCLUDED.${col}`).join(", ")}
`;
await prisma.$executeRawUnsafe(sql, ...values);
await query(sql, values);
logger.info(`Upserted data into ${tableName}:`, data);
}
@ -678,9 +680,10 @@ export class EventTriggerService {
companyCode: string
): Promise<{ conditionMet: boolean; result?: ExecutionResult }> {
try {
const diagram = await prisma.dataflow_diagrams.findUnique({
where: { diagram_id: diagramId },
});
const diagram = await queryOne<any>(
`SELECT * FROM dataflow_diagrams WHERE diagram_id = $1`,
[diagramId]
);
if (!diagram) {
throw new Error(`Diagram ${diagramId} not found`);