플로우 외부연결 중간커밋

This commit is contained in:
kjs
2025-10-21 13:19:18 +09:00
parent 967f9a9f5b
commit 0d96ea566b
12 changed files with 1667 additions and 100 deletions

View File

@@ -8,6 +8,8 @@ import { FlowStepDataCount, FlowStepDataList } from "../types/flow";
import { FlowDefinitionService } from "./flowDefinitionService";
import { FlowStepService } from "./flowStepService";
import { FlowConditionParser } from "./flowConditionParser";
import { executeExternalQuery } from "./externalDbHelper";
import { getPlaceholder, buildPaginationClause } from "./dbQueryBuilder";
export class FlowExecutionService {
private flowDefinitionService: FlowDefinitionService;
@@ -28,6 +30,13 @@ export class FlowExecutionService {
throw new Error(`Flow definition not found: ${flowId}`);
}
console.log("🔍 [getStepDataCount] Flow Definition:", {
flowId,
dbSourceType: flowDef.dbSourceType,
dbConnectionId: flowDef.dbConnectionId,
tableName: flowDef.tableName,
});
// 2. 플로우 단계 조회
const step = await this.flowStepService.findById(stepId);
if (!step) {
@@ -46,11 +55,40 @@ export class FlowExecutionService {
step.conditionJson
);
// 5. 카운트 쿼리 실행
// 5. 카운트 쿼리 실행 (내부 또는 외부 DB)
const query = `SELECT COUNT(*) as count FROM ${tableName} WHERE ${where}`;
const result = await db.query(query, params);
return parseInt(result[0].count);
console.log("🔍 [getStepDataCount] Query Info:", {
tableName,
query,
params,
isExternal: flowDef.dbSourceType === "external",
connectionId: flowDef.dbConnectionId,
});
let result: any;
if (flowDef.dbSourceType === "external" && flowDef.dbConnectionId) {
// 외부 DB 조회
console.log(
"✅ [getStepDataCount] Using EXTERNAL DB:",
flowDef.dbConnectionId
);
const externalResult = await executeExternalQuery(
flowDef.dbConnectionId,
query,
params
);
console.log("📦 [getStepDataCount] External result:", externalResult);
result = externalResult.rows;
} else {
// 내부 DB 조회
console.log("✅ [getStepDataCount] Using INTERNAL DB");
result = await db.query(query, params);
}
const count = parseInt(result[0].count || result[0].COUNT);
console.log("✅ [getStepDataCount] Final count:", count);
return count;
}
/**
@@ -88,47 +126,98 @@ export class FlowExecutionService {
const offset = (page - 1) * pageSize;
const isExternalDb =
flowDef.dbSourceType === "external" && flowDef.dbConnectionId;
// 5. 전체 카운트
const countQuery = `SELECT COUNT(*) as count FROM ${tableName} WHERE ${where}`;
const countResult = await db.query(countQuery, params);
const total = parseInt(countResult[0].count);
let countResult: any;
let total: number;
// 6. 테이블의 Primary Key 컬럼 찾기
let orderByColumn = "";
try {
const pkQuery = `
SELECT a.attname
FROM pg_index i
JOIN pg_attribute a ON a.attrelid = i.indrelid AND a.attnum = ANY(i.indkey)
WHERE i.indrelid = $1::regclass
AND i.indisprimary
LIMIT 1
`;
const pkResult = await db.query(pkQuery, [tableName]);
if (pkResult.length > 0) {
orderByColumn = pkResult[0].attname;
}
} catch (err) {
// Primary Key를 찾지 못하면 ORDER BY 없이 진행
console.warn(`Could not find primary key for table ${tableName}:`, err);
if (isExternalDb) {
const externalCountResult = await executeExternalQuery(
flowDef.dbConnectionId!,
countQuery,
params
);
countResult = externalCountResult.rows;
total = parseInt(countResult[0].count || countResult[0].COUNT);
} else {
countResult = await db.query(countQuery, params);
total = parseInt(countResult[0].count);
}
// 7. 데이터 조회
const orderByClause = orderByColumn ? `ORDER BY ${orderByColumn} DESC` : "";
const dataQuery = `
SELECT * FROM ${tableName}
WHERE ${where}
${orderByClause}
LIMIT $${params.length + 1} OFFSET $${params.length + 2}
`;
const dataResult = await db.query(dataQuery, [...params, pageSize, offset]);
// 6. 데이터 조회 (DB 타입별 페이징 처리)
let dataQuery: string;
let dataParams: any[];
return {
records: dataResult,
total,
page,
pageSize,
};
if (isExternalDb) {
// 외부 DB는 id 컬럼으로 정렬 (가정)
// DB 타입에 따른 페이징 절은 빌더에서 처리하지 않고 직접 작성
// PostgreSQL, MySQL, MSSQL, Oracle 모두 지원하도록 단순화
dataQuery = `
SELECT * FROM ${tableName}
WHERE ${where}
ORDER BY id DESC
LIMIT ${pageSize} OFFSET ${offset}
`;
dataParams = params;
const externalDataResult = await executeExternalQuery(
flowDef.dbConnectionId!,
dataQuery,
dataParams
);
return {
records: externalDataResult.rows,
total,
page,
pageSize,
};
} else {
// 내부 DB (PostgreSQL)
// Primary Key 컬럼 찾기
let orderByColumn = "";
try {
const pkQuery = `
SELECT a.attname
FROM pg_index i
JOIN pg_attribute a ON a.attrelid = i.indrelid AND a.attnum = ANY(i.indkey)
WHERE i.indrelid = $1::regclass
AND i.indisprimary
LIMIT 1
`;
const pkResult = await db.query(pkQuery, [tableName]);
if (pkResult.length > 0) {
orderByColumn = pkResult[0].attname;
}
} catch (err) {
console.warn(`Could not find primary key for table ${tableName}:`, err);
}
const orderByClause = orderByColumn
? `ORDER BY ${orderByColumn} DESC`
: "";
dataQuery = `
SELECT * FROM ${tableName}
WHERE ${where}
${orderByClause}
LIMIT $${params.length + 1} OFFSET $${params.length + 2}
`;
const dataResult = await db.query(dataQuery, [
...params,
pageSize,
offset,
]);
return {
records: dataResult,
total,
page,
pageSize,
};
}
}
/**