배치 UPSERT 기능 및 고정값 매핑 버그 수정

This commit is contained in:
dohyeons
2025-12-04 17:26:29 +09:00
parent 7a2f80b646
commit ef3b85f343
9 changed files with 1176 additions and 576 deletions

View File

@@ -10,6 +10,9 @@ export interface BatchConfig {
cron_schedule: string;
is_active?: string;
company_code?: string;
save_mode?: 'INSERT' | 'UPSERT'; // 저장 모드 (기본: INSERT)
conflict_key?: string; // UPSERT 시 충돌 기준 컬럼명
auth_service_name?: string; // REST API 인증에 사용할 토큰 서비스명
created_date?: Date;
created_by?: string;
updated_date?: Date;
@@ -386,6 +389,26 @@ export class BatchAPI {
throw error;
}
}
/**
* auth_tokens 테이블의 서비스명 목록 조회
*/
static async getAuthServiceNames(): Promise<string[]> {
try {
const response = await apiClient.get<{
success: boolean;
data: string[];
}>(`/batch-management/auth-services`);
if (response.data.success) {
return response.data.data || [];
}
return [];
} catch (error) {
console.error("인증 서비스 목록 조회 오류:", error);
return [];
}
}
}
// BatchJob export 추가 (이미 위에서 interface로 정의됨)

View File

@@ -5,7 +5,7 @@ import { apiClient } from "./client";
// 배치관리 전용 타입 정의
export interface BatchConnectionInfo {
type: 'internal' | 'external';
type: "internal" | "external";
id?: number;
name: string;
db_type?: string;
@@ -39,9 +39,7 @@ class BatchManagementAPIClass {
*/
static async getAvailableConnections(): Promise<BatchConnectionInfo[]> {
try {
const response = await apiClient.get<BatchApiResponse<BatchConnectionInfo[]>>(
`${this.BASE_PATH}/connections`
);
const response = await apiClient.get<BatchApiResponse<BatchConnectionInfo[]>>(`${this.BASE_PATH}/connections`);
if (!response.data.success) {
throw new Error(response.data.message || "커넥션 목록 조회에 실패했습니다.");
@@ -58,15 +56,15 @@ class BatchManagementAPIClass {
* 특정 커넥션의 테이블 목록 조회
*/
static async getTablesFromConnection(
connectionType: 'internal' | 'external',
connectionId?: number
connectionType: "internal" | "external",
connectionId?: number,
): Promise<string[]> {
try {
let url = `${this.BASE_PATH}/connections/${connectionType}`;
if (connectionType === 'external' && connectionId) {
if (connectionType === "external" && connectionId) {
url += `/${connectionId}`;
}
url += '/tables';
url += "/tables";
const response = await apiClient.get<BatchApiResponse<string[]>>(url);
@@ -85,13 +83,13 @@ class BatchManagementAPIClass {
* 특정 테이블의 컬럼 정보 조회
*/
static async getTableColumns(
connectionType: 'internal' | 'external',
connectionType: "internal" | "external",
tableName: string,
connectionId?: number
connectionId?: number,
): Promise<BatchColumnInfo[]> {
try {
let url = `${this.BASE_PATH}/connections/${connectionType}`;
if (connectionType === 'external' && connectionId) {
if (connectionType === "external" && connectionId) {
url += `/${connectionId}`;
}
url += `/tables/${encodeURIComponent(tableName)}/columns`;
@@ -120,14 +118,16 @@ class BatchManagementAPIClass {
apiUrl: string,
apiKey: string,
endpoint: string,
method: 'GET' | 'POST' | 'PUT' | 'DELETE' = 'GET',
method: "GET" | "POST" | "PUT" | "DELETE" = "GET",
paramInfo?: {
paramType: 'url' | 'query';
paramType: "url" | "query";
paramName: string;
paramValue: string;
paramSource: 'static' | 'dynamic';
paramSource: "static" | "dynamic";
},
requestBody?: string
requestBody?: string,
authServiceName?: string, // DB에서 토큰 가져올 서비스명
dataArrayPath?: string, // 데이터 배열 경로 (예: response, data.items)
): Promise<{
fields: string[];
samples: any[];
@@ -139,7 +139,7 @@ class BatchManagementAPIClass {
apiKey,
endpoint,
method,
requestBody
requestBody,
};
// 파라미터 정보가 있으면 추가
@@ -150,11 +150,23 @@ class BatchManagementAPIClass {
requestData.paramSource = paramInfo.paramSource;
}
const response = await apiClient.post<BatchApiResponse<{
fields: string[];
samples: any[];
totalCount: number;
}>>(`${this.BASE_PATH}/rest-api/preview`, requestData);
// DB에서 토큰 가져올 서비스명 추가
if (authServiceName) {
requestData.authServiceName = authServiceName;
}
// 데이터 배열 경로 추가
if (dataArrayPath) {
requestData.dataArrayPath = dataArrayPath;
}
const response = await apiClient.post<
BatchApiResponse<{
fields: string[];
samples: any[];
totalCount: number;
}>
>(`${this.BASE_PATH}/rest-api/preview`, requestData);
if (!response.data.success) {
throw new Error(response.data.message || "REST API 미리보기에 실패했습니다.");
@@ -167,6 +179,24 @@ class BatchManagementAPIClass {
}
}
/**
* 인증 서비스명 목록 조회
*/
static async getAuthServiceNames(): Promise<string[]> {
try {
const response = await apiClient.get<BatchApiResponse<string[]>>(`${this.BASE_PATH}/auth-services`);
if (!response.data.success) {
throw new Error(response.data.message || "인증 서비스 목록 조회에 실패했습니다.");
}
return response.data.data || [];
} catch (error) {
console.error("인증 서비스 목록 조회 오류:", error);
throw error;
}
}
/**
* REST API 배치 저장
*/
@@ -176,15 +206,17 @@ class BatchManagementAPIClass {
cronSchedule: string;
description?: string;
apiMappings: any[];
}): Promise<{ success: boolean; message: string; data?: any; }> {
authServiceName?: string;
dataArrayPath?: string; // REST API 응답에서 데이터 배열 경로
saveMode?: "INSERT" | "UPSERT";
conflictKey?: string;
}): Promise<{ success: boolean; message: string; data?: any }> {
try {
const response = await apiClient.post<BatchApiResponse<any>>(
`${this.BASE_PATH}/rest-api/save`, batchData
);
const response = await apiClient.post<BatchApiResponse<any>>(`${this.BASE_PATH}/rest-api/save`, batchData);
return {
success: response.data.success,
message: response.data.message || "",
data: response.data.data
data: response.data.data,
};
} catch (error) {
console.error("REST API 배치 저장 오류:", error);
@@ -193,4 +225,4 @@ class BatchManagementAPIClass {
}
}
export const BatchManagementAPI = BatchManagementAPIClass;
export const BatchManagementAPI = BatchManagementAPIClass;