131 lines
3.7 KiB
TypeScript
131 lines
3.7 KiB
TypeScript
|
|
import express from "express";
|
||
|
|
import { dataService } from "../services/dataService";
|
||
|
|
import { authenticateToken } from "../middleware/authMiddleware";
|
||
|
|
import { AuthenticatedRequest } from "../types/auth";
|
||
|
|
|
||
|
|
const router = express.Router();
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 동적 테이블 데이터 조회 API
|
||
|
|
* GET /api/data/{tableName}
|
||
|
|
*/
|
||
|
|
router.get(
|
||
|
|
"/:tableName",
|
||
|
|
authenticateToken,
|
||
|
|
async (req: AuthenticatedRequest, res) => {
|
||
|
|
try {
|
||
|
|
const { tableName } = req.params;
|
||
|
|
const { limit = "10", offset = "0", orderBy, ...filters } = req.query;
|
||
|
|
|
||
|
|
// 입력값 검증
|
||
|
|
if (!tableName || typeof tableName !== "string") {
|
||
|
|
return res.status(400).json({
|
||
|
|
success: false,
|
||
|
|
message: "테이블명이 필요합니다.",
|
||
|
|
error: "INVALID_TABLE_NAME",
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
// SQL 인젝션 방지를 위한 테이블명 검증
|
||
|
|
if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(tableName)) {
|
||
|
|
return res.status(400).json({
|
||
|
|
success: false,
|
||
|
|
message: "유효하지 않은 테이블명입니다.",
|
||
|
|
error: "INVALID_TABLE_NAME",
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
console.log(`📊 데이터 조회 요청: ${tableName}`, {
|
||
|
|
limit: parseInt(limit as string),
|
||
|
|
offset: parseInt(offset as string),
|
||
|
|
orderBy: orderBy as string,
|
||
|
|
filters,
|
||
|
|
user: req.user?.userId,
|
||
|
|
});
|
||
|
|
|
||
|
|
// 데이터 조회
|
||
|
|
const result = await dataService.getTableData({
|
||
|
|
tableName,
|
||
|
|
limit: parseInt(limit as string),
|
||
|
|
offset: parseInt(offset as string),
|
||
|
|
orderBy: orderBy as string,
|
||
|
|
filters: filters as Record<string, string>,
|
||
|
|
userCompany: req.user?.companyCode,
|
||
|
|
});
|
||
|
|
|
||
|
|
if (!result.success) {
|
||
|
|
return res.status(400).json(result);
|
||
|
|
}
|
||
|
|
|
||
|
|
console.log(
|
||
|
|
`✅ 데이터 조회 성공: ${tableName}, ${result.data?.length || 0}개 항목`
|
||
|
|
);
|
||
|
|
|
||
|
|
return res.json(result.data);
|
||
|
|
} catch (error) {
|
||
|
|
console.error("데이터 조회 오류:", error);
|
||
|
|
return res.status(500).json({
|
||
|
|
success: false,
|
||
|
|
message: "데이터 조회 중 오류가 발생했습니다.",
|
||
|
|
error: error instanceof Error ? error.message : "Unknown error",
|
||
|
|
});
|
||
|
|
}
|
||
|
|
}
|
||
|
|
);
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 테이블 컬럼 정보 조회 API
|
||
|
|
* GET /api/data/{tableName}/columns
|
||
|
|
*/
|
||
|
|
router.get(
|
||
|
|
"/:tableName/columns",
|
||
|
|
authenticateToken,
|
||
|
|
async (req: AuthenticatedRequest, res) => {
|
||
|
|
try {
|
||
|
|
const { tableName } = req.params;
|
||
|
|
|
||
|
|
// 입력값 검증
|
||
|
|
if (!tableName || typeof tableName !== "string") {
|
||
|
|
return res.status(400).json({
|
||
|
|
success: false,
|
||
|
|
message: "테이블명이 필요합니다.",
|
||
|
|
error: "INVALID_TABLE_NAME",
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
// SQL 인젝션 방지를 위한 테이블명 검증
|
||
|
|
if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(tableName)) {
|
||
|
|
return res.status(400).json({
|
||
|
|
success: false,
|
||
|
|
message: "유효하지 않은 테이블명입니다.",
|
||
|
|
error: "INVALID_TABLE_NAME",
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
console.log(`📋 컬럼 정보 조회: ${tableName}`);
|
||
|
|
|
||
|
|
// 컬럼 정보 조회
|
||
|
|
const result = await dataService.getTableColumns(tableName);
|
||
|
|
|
||
|
|
if (!result.success) {
|
||
|
|
return res.status(400).json(result);
|
||
|
|
}
|
||
|
|
|
||
|
|
console.log(
|
||
|
|
`✅ 컬럼 정보 조회 성공: ${tableName}, ${result.data?.length || 0}개 컬럼`
|
||
|
|
);
|
||
|
|
|
||
|
|
return res.json(result);
|
||
|
|
} catch (error) {
|
||
|
|
console.error("컬럼 정보 조회 오류:", error);
|
||
|
|
return res.status(500).json({
|
||
|
|
success: false,
|
||
|
|
message: "컬럼 정보 조회 중 오류가 발생했습니다.",
|
||
|
|
error: error instanceof Error ? error.message : "Unknown error",
|
||
|
|
});
|
||
|
|
}
|
||
|
|
}
|
||
|
|
);
|
||
|
|
|
||
|
|
export default router;
|