Compare commits

...

2 Commits

Author SHA1 Message Date
dohyeons
53bf3877ac Merge remote-tracking branch 'upstream/main' 2025-11-21 03:41:02 +09:00
dohyeons
fda7614d48 빌드에러해결 2025-11-21 03:40:41 +09:00
2 changed files with 76 additions and 31 deletions

View File

@@ -14,8 +14,17 @@ router.get(
authenticateToken,
async (req: AuthenticatedRequest, res) => {
try {
const { leftTable, rightTable, leftColumn, rightColumn, leftValue, dataFilter, enableEntityJoin, displayColumns, deduplication } =
req.query;
const {
leftTable,
rightTable,
leftColumn,
rightColumn,
leftValue,
dataFilter,
enableEntityJoin,
displayColumns,
deduplication,
} = req.query;
// 입력값 검증
if (!leftTable || !rightTable || !leftColumn || !rightColumn) {
@@ -38,7 +47,9 @@ router.get(
}
// 🆕 enableEntityJoin 파싱
const enableEntityJoinFlag = enableEntityJoin === "true" || enableEntityJoin === true;
const enableEntityJoinFlag =
enableEntityJoin === "true" ||
(typeof enableEntityJoin === "boolean" && enableEntityJoin);
// SQL 인젝션 방지를 위한 검증
const tables = [leftTable as string, rightTable as string];
@@ -68,7 +79,9 @@ router.get(
const userCompany = req.user?.companyCode;
// displayColumns 파싱 (item_info.item_name 등)
let parsedDisplayColumns: Array<{ name: string; label?: string }> | undefined;
let parsedDisplayColumns:
| Array<{ name: string; label?: string }>
| undefined;
if (displayColumns) {
try {
parsedDisplayColumns = JSON.parse(displayColumns as string);
@@ -78,12 +91,14 @@ router.get(
}
// 🆕 deduplication 파싱
let parsedDeduplication: {
let parsedDeduplication:
| {
enabled: boolean;
groupByColumn: string;
keepStrategy: "latest" | "earliest" | "base_price" | "current_date";
sortColumn?: string;
} | undefined;
}
| undefined;
if (deduplication) {
try {
parsedDeduplication = JSON.parse(deduplication as string);
@@ -340,7 +355,9 @@ router.get(
}
const { enableEntityJoin, groupByColumns } = req.query;
const enableEntityJoinFlag = enableEntityJoin === "true" || enableEntityJoin === true;
const enableEntityJoinFlag =
enableEntityJoin === "true" ||
(typeof enableEntityJoin === "boolean" && enableEntityJoin);
// groupByColumns 파싱 (JSON 문자열 또는 쉼표 구분)
let groupByColumnsArray: string[] = [];
@@ -350,7 +367,7 @@ router.get(
// JSON 형식이면 파싱, 아니면 쉼표로 분리
groupByColumnsArray = groupByColumns.startsWith("[")
? JSON.parse(groupByColumns)
: groupByColumns.split(",").map(c => c.trim());
: groupByColumns.split(",").map((c) => c.trim());
}
} catch (error) {
console.warn("groupByColumns 파싱 실패:", error);
@@ -359,11 +376,16 @@ router.get(
console.log(`🔍 레코드 상세 조회: ${tableName}/${id}`, {
enableEntityJoin: enableEntityJoinFlag,
groupByColumns: groupByColumnsArray
groupByColumns: groupByColumnsArray,
});
// 레코드 상세 조회 (Entity Join 옵션 + 그룹핑 옵션 포함)
const result = await dataService.getRecordDetail(tableName, id, enableEntityJoinFlag, groupByColumnsArray);
const result = await dataService.getRecordDetail(
tableName,
id,
enableEntityJoinFlag,
groupByColumnsArray
);
if (!result.success) {
return res.status(400).json(result);
@@ -415,7 +437,8 @@ router.post(
if (!tableName || !parentKeys || !records || !Array.isArray(records)) {
return res.status(400).json({
success: false,
message: "필수 파라미터가 누락되었습니다 (tableName, parentKeys, records).",
message:
"필수 파라미터가 누락되었습니다 (tableName, parentKeys, records).",
error: "MISSING_PARAMETERS",
});
}
@@ -450,17 +473,17 @@ router.post(
}
console.log(`✅ 그룹화된 데이터 UPSERT 성공: ${tableName}`, {
inserted: result.inserted,
updated: result.updated,
deleted: result.deleted,
inserted: result.data?.inserted || 0,
updated: result.data?.updated || 0,
deleted: result.data?.deleted || 0,
});
return res.json({
success: true,
message: "데이터가 저장되었습니다.",
inserted: result.inserted,
updated: result.updated,
deleted: result.deleted,
inserted: result.data?.inserted || 0,
updated: result.data?.updated || 0,
deleted: result.data?.deleted || 0,
});
} catch (error) {
console.error("그룹화된 데이터 UPSERT 오류:", error);
@@ -508,14 +531,20 @@ router.post(
const enrichedData = { ...data };
// 테이블에 company_code 컬럼이 있는지 확인하고 자동으로 추가
const hasCompanyCode = await dataService.checkColumnExists(tableName, "company_code");
const hasCompanyCode = await dataService.checkColumnExists(
tableName,
"company_code"
);
if (hasCompanyCode && req.user?.companyCode) {
enrichedData.company_code = req.user.companyCode;
console.log(`🏢 company_code 자동 추가: ${req.user.companyCode}`);
}
// 테이블에 company_name 컬럼이 있는지 확인하고 자동으로 추가
const hasCompanyName = await dataService.checkColumnExists(tableName, "company_name");
const hasCompanyName = await dataService.checkColumnExists(
tableName,
"company_name"
);
if (hasCompanyName && req.user?.companyName) {
enrichedData.company_name = req.user.companyName;
console.log(`🏢 company_name 자동 추가: ${req.user.companyName}`);
@@ -679,7 +708,10 @@ router.post(
console.log(`🗑️ 그룹 삭제:`, { tableName, filterConditions });
const result = await dataService.deleteGroupRecords(tableName, filterConditions);
const result = await dataService.deleteGroupRecords(
tableName,
filterConditions
);
if (!result.success) {
return res.status(400).json(result);

13
backend-node/src/types/express.d.ts vendored Normal file
View File

@@ -0,0 +1,13 @@
import "express";
declare module "express-serve-static-core" {
interface Request {
user?: {
userId: string;
companyCode: string;
userType: string;
locale?: string;
};
}
}