377 lines
10 KiB
TypeScript
377 lines
10 KiB
TypeScript
// 외부 DB 연결 API 라우트
|
|
// 작성일: 2024-12-17
|
|
|
|
import { Router, Response } from "express";
|
|
import { ExternalDbConnectionService } from "../services/externalDbConnectionService";
|
|
import {
|
|
ExternalDbConnection,
|
|
ExternalDbConnectionFilter,
|
|
} from "../types/externalDbTypes";
|
|
import { authenticateToken } from "../middleware/authMiddleware";
|
|
import { AuthenticatedRequest } from "../types/auth";
|
|
|
|
const router = Router();
|
|
|
|
/**
|
|
* GET /api/external-db-connections
|
|
* 외부 DB 연결 목록 조회
|
|
*/
|
|
/**
|
|
* GET /api/external-db-connections/types/supported
|
|
* 지원하는 DB 타입 목록 조회
|
|
*/
|
|
router.get(
|
|
"/types/supported",
|
|
authenticateToken,
|
|
async (req: AuthenticatedRequest, res: Response) => {
|
|
try {
|
|
const { DB_TYPE_OPTIONS, DB_TYPE_DEFAULTS } = await import(
|
|
"../types/externalDbTypes"
|
|
);
|
|
|
|
return res.status(200).json({
|
|
success: true,
|
|
data: {
|
|
types: DB_TYPE_OPTIONS,
|
|
defaults: DB_TYPE_DEFAULTS,
|
|
},
|
|
message: "지원하는 DB 타입 목록을 조회했습니다.",
|
|
});
|
|
} catch (error) {
|
|
console.error("DB 타입 목록 조회 오류:", error);
|
|
return res.status(500).json({
|
|
success: false,
|
|
message: "서버 내부 오류가 발생했습니다.",
|
|
error: error instanceof Error ? error.message : "알 수 없는 오류",
|
|
});
|
|
}
|
|
}
|
|
);
|
|
|
|
router.get(
|
|
"/",
|
|
authenticateToken,
|
|
async (req: AuthenticatedRequest, res: Response) => {
|
|
try {
|
|
const filter: ExternalDbConnectionFilter = {
|
|
db_type: req.query.db_type as string,
|
|
is_active: req.query.is_active as string,
|
|
company_code: req.query.company_code as string,
|
|
search: req.query.search as string,
|
|
};
|
|
|
|
// 빈 값 제거
|
|
Object.keys(filter).forEach((key) => {
|
|
if (!filter[key as keyof ExternalDbConnectionFilter]) {
|
|
delete filter[key as keyof ExternalDbConnectionFilter];
|
|
}
|
|
});
|
|
|
|
const result = await ExternalDbConnectionService.getConnections(filter);
|
|
|
|
if (result.success) {
|
|
return res.status(200).json(result);
|
|
} else {
|
|
return res.status(400).json(result);
|
|
}
|
|
} catch (error) {
|
|
console.error("외부 DB 연결 목록 조회 오류:", error);
|
|
return res.status(500).json({
|
|
success: false,
|
|
message: "서버 내부 오류가 발생했습니다.",
|
|
error: error instanceof Error ? error.message : "알 수 없는 오류",
|
|
});
|
|
}
|
|
}
|
|
);
|
|
|
|
|
|
/**
|
|
* GET /api/external-db-connections/:id
|
|
* 특정 외부 DB 연결 조회
|
|
*/
|
|
router.get(
|
|
"/:id",
|
|
authenticateToken,
|
|
async (req: AuthenticatedRequest, res: Response) => {
|
|
try {
|
|
const id = parseInt(req.params.id);
|
|
|
|
if (isNaN(id)) {
|
|
return res.status(400).json({
|
|
success: false,
|
|
message: "유효하지 않은 ID입니다.",
|
|
});
|
|
}
|
|
|
|
const result = await ExternalDbConnectionService.getConnectionById(id);
|
|
|
|
if (result.success) {
|
|
return res.status(200).json(result);
|
|
} else {
|
|
return res.status(404).json(result);
|
|
}
|
|
} catch (error) {
|
|
console.error("외부 DB 연결 조회 오류:", error);
|
|
return res.status(500).json({
|
|
success: false,
|
|
message: "서버 내부 오류가 발생했습니다.",
|
|
error: error instanceof Error ? error.message : "알 수 없는 오류",
|
|
});
|
|
}
|
|
}
|
|
);
|
|
|
|
/**
|
|
* POST /api/external-db-connections
|
|
* 새 외부 DB 연결 생성
|
|
*/
|
|
router.post(
|
|
"/",
|
|
authenticateToken,
|
|
async (req: AuthenticatedRequest, res: Response) => {
|
|
try {
|
|
const connectionData: ExternalDbConnection = req.body;
|
|
|
|
// 사용자 정보 추가
|
|
if (req.user) {
|
|
connectionData.created_by = req.user.userId;
|
|
connectionData.updated_by = req.user.userId;
|
|
}
|
|
|
|
const result =
|
|
await ExternalDbConnectionService.createConnection(connectionData);
|
|
|
|
if (result.success) {
|
|
return res.status(201).json(result);
|
|
} else {
|
|
return res.status(400).json(result);
|
|
}
|
|
} catch (error) {
|
|
console.error("외부 DB 연결 생성 오류:", error);
|
|
return res.status(500).json({
|
|
success: false,
|
|
message: "서버 내부 오류가 발생했습니다.",
|
|
error: error instanceof Error ? error.message : "알 수 없는 오류",
|
|
});
|
|
}
|
|
}
|
|
);
|
|
|
|
/**
|
|
* PUT /api/external-db-connections/:id
|
|
* 외부 DB 연결 수정
|
|
*/
|
|
router.put(
|
|
"/:id",
|
|
authenticateToken,
|
|
async (req: AuthenticatedRequest, res: Response) => {
|
|
try {
|
|
const id = parseInt(req.params.id);
|
|
|
|
if (isNaN(id)) {
|
|
return res.status(400).json({
|
|
success: false,
|
|
message: "유효하지 않은 ID입니다.",
|
|
});
|
|
}
|
|
|
|
const updateData: Partial<ExternalDbConnection> = req.body;
|
|
|
|
// 사용자 정보 추가
|
|
if (req.user) {
|
|
updateData.updated_by = req.user.userId;
|
|
}
|
|
|
|
const result = await ExternalDbConnectionService.updateConnection(
|
|
id,
|
|
updateData
|
|
);
|
|
|
|
if (result.success) {
|
|
return res.status(200).json(result);
|
|
} else {
|
|
return res.status(400).json(result);
|
|
}
|
|
} catch (error) {
|
|
console.error("외부 DB 연결 수정 오류:", error);
|
|
return res.status(500).json({
|
|
success: false,
|
|
message: "서버 내부 오류가 발생했습니다.",
|
|
error: error instanceof Error ? error.message : "알 수 없는 오류",
|
|
});
|
|
}
|
|
}
|
|
);
|
|
|
|
/**
|
|
* DELETE /api/external-db-connections/:id
|
|
* 외부 DB 연결 삭제 (물리 삭제)
|
|
*/
|
|
router.delete(
|
|
"/:id",
|
|
authenticateToken,
|
|
async (req: AuthenticatedRequest, res: Response) => {
|
|
try {
|
|
const id = parseInt(req.params.id);
|
|
|
|
if (isNaN(id)) {
|
|
return res.status(400).json({
|
|
success: false,
|
|
message: "유효하지 않은 ID입니다.",
|
|
});
|
|
}
|
|
|
|
const result = await ExternalDbConnectionService.deleteConnection(id);
|
|
|
|
if (result.success) {
|
|
return res.status(200).json(result);
|
|
} else {
|
|
return res.status(404).json(result);
|
|
}
|
|
} catch (error) {
|
|
console.error("외부 DB 연결 삭제 오류:", error);
|
|
return res.status(500).json({
|
|
success: false,
|
|
message: "서버 내부 오류가 발생했습니다.",
|
|
error: error instanceof Error ? error.message : "알 수 없는 오류",
|
|
});
|
|
}
|
|
}
|
|
);
|
|
|
|
/**
|
|
* POST /api/external-db-connections/:id/test
|
|
* 데이터베이스 연결 테스트 (ID 기반)
|
|
*/
|
|
router.post(
|
|
"/:id/test",
|
|
authenticateToken,
|
|
async (req: AuthenticatedRequest, res: Response) => {
|
|
try {
|
|
const id = parseInt(req.params.id);
|
|
|
|
if (isNaN(id)) {
|
|
return res.status(400).json({
|
|
success: false,
|
|
message: "유효하지 않은 연결 ID입니다.",
|
|
error: {
|
|
code: "INVALID_ID",
|
|
details: "연결 ID는 숫자여야 합니다.",
|
|
},
|
|
});
|
|
}
|
|
|
|
// 테스트용 비밀번호가 제공된 경우 사용
|
|
const testData = req.body.password ? { password: req.body.password } : undefined;
|
|
const result = await ExternalDbConnectionService.testConnectionById(id, testData);
|
|
|
|
return res.status(200).json({
|
|
success: result.success,
|
|
data: result,
|
|
message: result.message,
|
|
});
|
|
} catch (error) {
|
|
console.error("연결 테스트 오류:", error);
|
|
return res.status(500).json({
|
|
success: false,
|
|
message: "연결 테스트 중 서버 오류가 발생했습니다.",
|
|
error: {
|
|
code: "SERVER_ERROR",
|
|
details: error instanceof Error ? error.message : "알 수 없는 오류",
|
|
},
|
|
});
|
|
}
|
|
}
|
|
);
|
|
|
|
/**
|
|
* POST /api/external-db-connections/:id/execute
|
|
* SQL 쿼리 실행
|
|
*/
|
|
router.post(
|
|
"/:id/execute",
|
|
authenticateToken,
|
|
async (req: AuthenticatedRequest, res: Response) => {
|
|
try {
|
|
const id = parseInt(req.params.id);
|
|
const { query } = req.body;
|
|
|
|
if (!query?.trim()) {
|
|
return res.status(400).json({
|
|
success: false,
|
|
message: "쿼리가 입력되지 않았습니다."
|
|
});
|
|
}
|
|
|
|
const result = await ExternalDbConnectionService.executeQuery(id, query);
|
|
return res.json(result);
|
|
} catch (error) {
|
|
console.error("쿼리 실행 오류:", error);
|
|
return res.status(500).json({
|
|
success: false,
|
|
message: "쿼리 실행 중 오류가 발생했습니다.",
|
|
error: error instanceof Error ? error.message : "알 수 없는 오류"
|
|
});
|
|
}
|
|
}
|
|
);
|
|
|
|
/**
|
|
* GET /api/external-db-connections/:id/tables
|
|
* 데이터베이스 테이블 목록 조회
|
|
*/
|
|
router.get(
|
|
"/:id/tables",
|
|
authenticateToken,
|
|
async (req: AuthenticatedRequest, res: Response) => {
|
|
try {
|
|
const id = parseInt(req.params.id);
|
|
const result = await ExternalDbConnectionService.getTables(id);
|
|
return res.json(result);
|
|
} catch (error) {
|
|
console.error("테이블 목록 조회 오류:", error);
|
|
return res.status(500).json({
|
|
success: false,
|
|
message: "테이블 목록 조회 중 오류가 발생했습니다.",
|
|
error: error instanceof Error ? error.message : "알 수 없는 오류"
|
|
});
|
|
}
|
|
}
|
|
);
|
|
|
|
/**
|
|
* GET /api/external-db-connections/:id/tables/:tableName/columns
|
|
* 특정 테이블의 컬럼 정보 조회
|
|
*/
|
|
router.get(
|
|
"/:id/tables/:tableName/columns",
|
|
authenticateToken,
|
|
async (req: AuthenticatedRequest, res: Response) => {
|
|
try {
|
|
const id = parseInt(req.params.id);
|
|
const tableName = req.params.tableName;
|
|
|
|
if (!tableName) {
|
|
return res.status(400).json({
|
|
success: false,
|
|
message: "테이블명이 입력되지 않았습니다."
|
|
});
|
|
}
|
|
|
|
const result = await ExternalDbConnectionService.getTableColumns(id, tableName);
|
|
return res.json(result);
|
|
} catch (error) {
|
|
console.error("테이블 컬럼 조회 오류:", error);
|
|
return res.status(500).json({
|
|
success: false,
|
|
message: "테이블 컬럼 조회 중 오류가 발생했습니다.",
|
|
error: error instanceof Error ? error.message : "알 수 없는 오류"
|
|
});
|
|
}
|
|
}
|
|
);
|
|
|
|
|
|
export default router;
|