버튼 삭제 수정기능 구현
This commit is contained in:
@@ -99,6 +99,58 @@ export const updateFormData = async (
|
||||
}
|
||||
};
|
||||
|
||||
// 폼 데이터 부분 업데이트 (변경된 필드만)
|
||||
export const updateFormDataPartial = async (
|
||||
req: AuthenticatedRequest,
|
||||
res: Response
|
||||
): Promise<Response | void> => {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
const { companyCode, userId } = req.user as any;
|
||||
const { tableName, originalData, newData } = req.body;
|
||||
|
||||
if (!tableName || !originalData || !newData) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message:
|
||||
"필수 필드가 누락되었습니다. (tableName, originalData, newData)",
|
||||
});
|
||||
}
|
||||
|
||||
console.log("🔄 컨트롤러: 부분 업데이트 요청:", {
|
||||
id,
|
||||
tableName,
|
||||
originalData,
|
||||
newData,
|
||||
});
|
||||
|
||||
// 메타데이터 추가
|
||||
const newDataWithMeta = {
|
||||
...newData,
|
||||
updated_by: userId,
|
||||
};
|
||||
|
||||
const result = await dynamicFormService.updateFormDataPartial(
|
||||
parseInt(id),
|
||||
tableName,
|
||||
originalData,
|
||||
newDataWithMeta
|
||||
);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: result,
|
||||
message: "데이터가 성공적으로 업데이트되었습니다.",
|
||||
});
|
||||
} catch (error: any) {
|
||||
console.error("❌ 부분 업데이트 실패:", error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: error.message || "부분 업데이트에 실패했습니다.",
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 폼 데이터 삭제
|
||||
export const deleteFormData = async (
|
||||
req: AuthenticatedRequest,
|
||||
@@ -131,6 +183,41 @@ export const deleteFormData = async (
|
||||
}
|
||||
};
|
||||
|
||||
// 테이블의 기본키 조회
|
||||
export const getTablePrimaryKeys = async (
|
||||
req: AuthenticatedRequest,
|
||||
res: Response
|
||||
): Promise<Response | void> => {
|
||||
try {
|
||||
const { tableName } = req.params;
|
||||
|
||||
if (!tableName) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: "테이블명이 누락되었습니다.",
|
||||
});
|
||||
}
|
||||
|
||||
console.log(`🔑 테이블 ${tableName}의 기본키 조회 요청`);
|
||||
|
||||
const primaryKeys = await dynamicFormService.getTablePrimaryKeys(tableName);
|
||||
|
||||
console.log(`✅ 테이블 ${tableName}의 기본키:`, primaryKeys);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: primaryKeys,
|
||||
message: "기본키 조회가 완료되었습니다.",
|
||||
});
|
||||
} catch (error: any) {
|
||||
console.error("❌ 기본키 조회 실패:", error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: error.message || "기본키 조회에 실패했습니다.",
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 단일 폼 데이터 조회
|
||||
export const getFormData = async (
|
||||
req: AuthenticatedRequest,
|
||||
|
||||
@@ -3,11 +3,13 @@ import { authenticateToken } from "../middleware/authMiddleware";
|
||||
import {
|
||||
saveFormData,
|
||||
updateFormData,
|
||||
updateFormDataPartial,
|
||||
deleteFormData,
|
||||
getFormData,
|
||||
getFormDataList,
|
||||
validateFormData,
|
||||
getTableColumns,
|
||||
getTablePrimaryKeys,
|
||||
} from "../controllers/dynamicFormController";
|
||||
|
||||
const router = express.Router();
|
||||
@@ -18,6 +20,7 @@ router.use(authenticateToken);
|
||||
// 폼 데이터 CRUD
|
||||
router.post("/save", saveFormData);
|
||||
router.put("/:id", updateFormData);
|
||||
router.patch("/:id/partial", updateFormDataPartial); // 부분 업데이트
|
||||
router.delete("/:id", deleteFormData);
|
||||
router.get("/:id", getFormData);
|
||||
|
||||
@@ -30,4 +33,7 @@ router.post("/validate", validateFormData);
|
||||
// 테이블 컬럼 정보 조회 (검증용)
|
||||
router.get("/table/:tableName/columns", getTableColumns);
|
||||
|
||||
// 테이블 기본키 조회
|
||||
router.get("/table/:tableName/primary-keys", getTablePrimaryKeys);
|
||||
|
||||
export default router;
|
||||
|
||||
@@ -14,6 +14,12 @@ export interface FormDataResult {
|
||||
updatedBy: string;
|
||||
}
|
||||
|
||||
export interface PartialUpdateResult {
|
||||
success: boolean;
|
||||
data: any;
|
||||
message: string;
|
||||
}
|
||||
|
||||
export interface PaginatedFormData {
|
||||
content: FormDataResult[];
|
||||
totalElements: number;
|
||||
@@ -128,9 +134,9 @@ export class DynamicFormService {
|
||||
}
|
||||
|
||||
/**
|
||||
* 테이블의 Primary Key 컬럼 조회
|
||||
* 테이블의 Primary Key 컬럼 조회 (공개 메서드로 변경)
|
||||
*/
|
||||
private async getTablePrimaryKeys(tableName: string): Promise<string[]> {
|
||||
async getTablePrimaryKeys(tableName: string): Promise<string[]> {
|
||||
try {
|
||||
const result = (await prisma.$queryRawUnsafe(`
|
||||
SELECT kcu.column_name
|
||||
@@ -385,6 +391,118 @@ export class DynamicFormService {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 폼 데이터 부분 업데이트 (변경된 필드만 업데이트)
|
||||
*/
|
||||
async updateFormDataPartial(
|
||||
id: number,
|
||||
tableName: string,
|
||||
originalData: Record<string, any>,
|
||||
newData: Record<string, any>
|
||||
): Promise<PartialUpdateResult> {
|
||||
try {
|
||||
console.log("🔄 서비스: 부분 업데이트 시작:", {
|
||||
id,
|
||||
tableName,
|
||||
originalData,
|
||||
newData,
|
||||
});
|
||||
|
||||
// 테이블의 실제 컬럼 정보 조회
|
||||
const tableColumns = await this.getTableColumnNames(tableName);
|
||||
console.log(`📋 테이블 ${tableName}의 컬럼:`, tableColumns);
|
||||
|
||||
// 변경된 필드만 찾기
|
||||
const changedFields: Record<string, any> = {};
|
||||
|
||||
for (const [key, value] of Object.entries(newData)) {
|
||||
// 메타데이터 필드 제외
|
||||
if (
|
||||
["created_by", "updated_by", "company_code", "screen_id"].includes(
|
||||
key
|
||||
)
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 테이블에 존재하지 않는 컬럼 제외
|
||||
if (!tableColumns.includes(key)) {
|
||||
console.log(
|
||||
`⚠️ 컬럼 ${key}는 테이블 ${tableName}에 존재하지 않아 제외됨`
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
// 값이 실제로 변경된 경우만 포함
|
||||
if (originalData[key] !== value) {
|
||||
changedFields[key] = value;
|
||||
console.log(
|
||||
`📝 변경된 필드: ${key} = "${originalData[key]}" → "${value}"`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// 변경된 필드가 없으면 업데이트 건너뛰기
|
||||
if (Object.keys(changedFields).length === 0) {
|
||||
console.log("📋 변경된 필드가 없습니다. 업데이트를 건너뜁니다.");
|
||||
return {
|
||||
success: true,
|
||||
data: originalData,
|
||||
message: "변경사항이 없어 업데이트하지 않았습니다.",
|
||||
};
|
||||
}
|
||||
|
||||
// 업데이트 관련 필드 추가 (변경사항이 있는 경우에만)
|
||||
if (tableColumns.includes("updated_at")) {
|
||||
changedFields.updated_at = new Date();
|
||||
}
|
||||
|
||||
console.log("🎯 실제 업데이트할 필드들:", changedFields);
|
||||
|
||||
// 동적으로 기본키 조회
|
||||
const primaryKeys = await this.getTablePrimaryKeys(tableName);
|
||||
if (!primaryKeys || primaryKeys.length === 0) {
|
||||
throw new Error(`테이블 ${tableName}의 기본키를 찾을 수 없습니다.`);
|
||||
}
|
||||
|
||||
const primaryKeyColumn = primaryKeys[0];
|
||||
console.log(`🔑 테이블 ${tableName}의 기본키: ${primaryKeyColumn}`);
|
||||
|
||||
// 동적 UPDATE SQL 생성 (변경된 필드만)
|
||||
const setClause = Object.keys(changedFields)
|
||||
.map((key, index) => `${key} = $${index + 1}`)
|
||||
.join(", ");
|
||||
|
||||
const values: any[] = Object.values(changedFields);
|
||||
values.push(id); // WHERE 조건용 ID 추가
|
||||
|
||||
const updateQuery = `
|
||||
UPDATE ${tableName}
|
||||
SET ${setClause}
|
||||
WHERE ${primaryKeyColumn} = $${values.length}
|
||||
RETURNING *
|
||||
`;
|
||||
|
||||
console.log("📝 실행할 부분 UPDATE SQL:", updateQuery);
|
||||
console.log("📊 SQL 파라미터:", values);
|
||||
|
||||
const result = await prisma.$queryRawUnsafe(updateQuery, ...values);
|
||||
|
||||
console.log("✅ 서비스: 부분 업데이트 성공:", result);
|
||||
|
||||
const updatedRecord = Array.isArray(result) ? result[0] : result;
|
||||
|
||||
return {
|
||||
success: true,
|
||||
data: updatedRecord,
|
||||
message: "데이터가 성공적으로 업데이트되었습니다.",
|
||||
};
|
||||
} catch (error: any) {
|
||||
console.error("❌ 서비스: 부분 업데이트 실패:", error);
|
||||
throw new Error(`부분 업데이트 실패: ${error}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 폼 데이터 업데이트 (실제 테이블에서 직접 업데이트)
|
||||
*/
|
||||
@@ -448,11 +566,19 @@ export class DynamicFormService {
|
||||
const values: any[] = Object.values(dataToUpdate);
|
||||
values.push(id); // WHERE 조건용 ID 추가
|
||||
|
||||
// ID 또는 objid로 찾기 시도
|
||||
// 동적으로 기본키 조회
|
||||
const primaryKeys = await this.getTablePrimaryKeys(tableName);
|
||||
if (!primaryKeys || primaryKeys.length === 0) {
|
||||
throw new Error(`테이블 ${tableName}의 기본키를 찾을 수 없습니다.`);
|
||||
}
|
||||
|
||||
const primaryKeyColumn = primaryKeys[0]; // 첫 번째 기본키 사용
|
||||
console.log(`🔑 테이블 ${tableName}의 기본키: ${primaryKeyColumn}`);
|
||||
|
||||
const updateQuery = `
|
||||
UPDATE ${tableName}
|
||||
SET ${setClause}
|
||||
WHERE (id = $${values.length} OR objid = $${values.length})
|
||||
WHERE ${primaryKeyColumn} = $${values.length}
|
||||
RETURNING *
|
||||
`;
|
||||
|
||||
@@ -524,10 +650,40 @@ export class DynamicFormService {
|
||||
tableName,
|
||||
});
|
||||
|
||||
// 동적 DELETE SQL 생성
|
||||
// 1. 먼저 테이블의 기본키 컬럼명을 동적으로 조회
|
||||
const primaryKeyQuery = `
|
||||
SELECT kcu.column_name
|
||||
FROM information_schema.table_constraints tc
|
||||
JOIN information_schema.key_column_usage kcu
|
||||
ON tc.constraint_name = kcu.constraint_name
|
||||
WHERE tc.table_name = $1
|
||||
AND tc.constraint_type = 'PRIMARY KEY'
|
||||
LIMIT 1
|
||||
`;
|
||||
|
||||
console.log("🔍 기본키 조회 SQL:", primaryKeyQuery);
|
||||
console.log("🔍 테이블명:", tableName);
|
||||
|
||||
const primaryKeyResult = await prisma.$queryRawUnsafe(
|
||||
primaryKeyQuery,
|
||||
tableName
|
||||
);
|
||||
|
||||
if (
|
||||
!primaryKeyResult ||
|
||||
!Array.isArray(primaryKeyResult) ||
|
||||
primaryKeyResult.length === 0
|
||||
) {
|
||||
throw new Error(`테이블 ${tableName}의 기본키를 찾을 수 없습니다.`);
|
||||
}
|
||||
|
||||
const primaryKeyColumn = (primaryKeyResult[0] as any).column_name;
|
||||
console.log("🔑 발견된 기본키 컬럼:", primaryKeyColumn);
|
||||
|
||||
// 2. 동적으로 발견된 기본키를 사용한 DELETE SQL 생성
|
||||
const deleteQuery = `
|
||||
DELETE FROM ${tableName}
|
||||
WHERE (id = $1 OR objid = $1)
|
||||
WHERE ${primaryKeyColumn} = $1
|
||||
RETURNING *
|
||||
`;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user