ERP-node/backend-node/src/services/collectionService.ts

297 lines
8.3 KiB
TypeScript

// 수집 관리 서비스
// 작성일: 2024-12-23
import { query, queryOne, transaction } from "../database/db";
import {
DataCollectionConfig,
CollectionFilter,
CollectionJob,
CollectionHistory,
} from "../types/collectionManagement";
export class CollectionService {
/**
* 수집 설정 목록 조회
*/
static async getCollectionConfigs(
filter: CollectionFilter
): Promise<DataCollectionConfig[]> {
const whereConditions: string[] = ["company_code = $1"];
const values: any[] = [filter.company_code || "*"];
let paramIndex = 2;
if (filter.config_name) {
whereConditions.push(`config_name ILIKE $${paramIndex++}`);
values.push(`%${filter.config_name}%`);
}
if (filter.source_connection_id) {
whereConditions.push(`source_connection_id = $${paramIndex++}`);
values.push(filter.source_connection_id);
}
if (filter.collection_type) {
whereConditions.push(`collection_type = $${paramIndex++}`);
values.push(filter.collection_type);
}
if (filter.is_active) {
whereConditions.push(`is_active = $${paramIndex++}`);
values.push(filter.is_active === "Y");
}
if (filter.search) {
whereConditions.push(
`(config_name ILIKE $${paramIndex} OR description ILIKE $${paramIndex})`
);
values.push(`%${filter.search}%`);
paramIndex++;
}
const configs = await query<any>(
`SELECT * FROM data_collection_configs
WHERE ${whereConditions.join(" AND ")}
ORDER BY created_date DESC`,
values
);
return configs.map((config: any) => ({
...config,
is_active: config.is_active ? "Y" : "N",
})) as DataCollectionConfig[];
}
/**
* 수집 설정 상세 조회
*/
static async getCollectionConfigById(
id: number
): Promise<DataCollectionConfig | null> {
const config = await queryOne<any>(
`SELECT * FROM data_collection_configs WHERE id = $1`,
[id]
);
if (!config) return null;
return {
...config,
is_active: config.is_active ? "Y" : "N",
} as DataCollectionConfig;
}
/**
* 수집 설정 생성
*/
static async createCollectionConfig(
data: DataCollectionConfig
): Promise<DataCollectionConfig> {
const { id, collection_options, ...createData } = data;
const config = await queryOne<any>(
`INSERT INTO data_collection_configs
(config_name, company_code, source_connection_id, collection_type,
collection_options, schedule_cron, is_active, description,
created_by, updated_by, created_date, updated_date)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, NOW(), NOW())
RETURNING *`,
[
createData.config_name,
createData.company_code,
createData.source_connection_id,
createData.collection_type,
collection_options ? JSON.stringify(collection_options) : null,
createData.schedule_cron,
data.is_active,
createData.description,
createData.created_by,
createData.updated_by,
]
);
return {
...config,
is_active: config.is_active ? "Y" : "N",
} as DataCollectionConfig;
}
/**
* 수집 설정 수정
*/
static async updateCollectionConfig(
id: number,
data: Partial<DataCollectionConfig>
): Promise<DataCollectionConfig> {
const updateFields: string[] = ["updated_date = NOW()"];
const values: any[] = [];
let paramIndex = 1;
if (data.config_name !== undefined) {
updateFields.push(`config_name = $${paramIndex++}`);
values.push(data.config_name);
}
if (data.source_connection_id !== undefined) {
updateFields.push(`source_connection_id = $${paramIndex++}`);
values.push(data.source_connection_id);
}
if (data.collection_type !== undefined) {
updateFields.push(`collection_type = $${paramIndex++}`);
values.push(data.collection_type);
}
if (data.collection_options !== undefined) {
updateFields.push(`collection_options = $${paramIndex++}`);
values.push(
data.collection_options ? JSON.stringify(data.collection_options) : null
);
}
if (data.schedule_cron !== undefined) {
updateFields.push(`schedule_cron = $${paramIndex++}`);
values.push(data.schedule_cron);
}
if (data.is_active !== undefined) {
updateFields.push(`is_active = $${paramIndex++}`);
values.push(data.is_active);
}
if (data.description !== undefined) {
updateFields.push(`description = $${paramIndex++}`);
values.push(data.description);
}
if (data.updated_by !== undefined) {
updateFields.push(`updated_by = $${paramIndex++}`);
values.push(data.updated_by);
}
const config = await queryOne<any>(
`UPDATE data_collection_configs
SET ${updateFields.join(", ")}
WHERE id = $${paramIndex}
RETURNING *`,
[...values, id]
);
return {
...config,
is_active: config.is_active ? "Y" : "N",
} as DataCollectionConfig;
}
/**
* 수집 설정 삭제
*/
static async deleteCollectionConfig(id: number): Promise<void> {
await query(`DELETE FROM data_collection_configs WHERE id = $1`, [id]);
}
/**
* 수집 작업 실행
*/
static async executeCollection(configId: number): Promise<CollectionJob> {
const config = await queryOne<any>(
`SELECT * FROM data_collection_configs WHERE id = $1`,
[configId]
);
if (!config) {
throw new Error("수집 설정을 찾을 수 없습니다.");
}
if (!config.is_active) {
throw new Error("비활성화된 수집 설정입니다.");
}
// 수집 작업 기록 생성
const job = await queryOne<any>(
`INSERT INTO data_collection_jobs
(config_id, job_status, started_at, created_date)
VALUES ($1, $2, NOW(), NOW())
RETURNING *`,
[configId, "running"]
);
// 실제 수집 작업 실행 로직은 여기에 구현
// 현재는 시뮬레이션으로 처리
setTimeout(async () => {
try {
// 수집 작업 시뮬레이션
await new Promise((resolve) => setTimeout(resolve, 3000));
const recordsCollected = Math.floor(Math.random() * 1000) + 100;
await query(
`UPDATE data_collection_jobs
SET job_status = $1, completed_at = NOW(), records_processed = $2
WHERE id = $3`,
["completed", recordsCollected, job.id]
);
} catch (error) {
await query(
`UPDATE data_collection_jobs
SET job_status = $1, completed_at = NOW(), error_message = $2
WHERE id = $3`,
[
"failed",
error instanceof Error ? error.message : "알 수 없는 오류",
job.id,
]
);
}
}, 0);
return job as CollectionJob;
}
/**
* 수집 작업 목록 조회
*/
static async getCollectionJobs(configId?: number): Promise<CollectionJob[]> {
let sql = `
SELECT j.*, c.config_name, c.collection_type
FROM data_collection_jobs j
LEFT JOIN data_collection_configs c ON j.config_id = c.id
`;
const values: any[] = [];
if (configId) {
sql += ` WHERE j.config_id = $1`;
values.push(configId);
}
sql += ` ORDER BY j.started_at DESC`;
const jobs = await query<any>(sql, values);
return jobs as CollectionJob[];
}
/**
* 수집 이력 조회
*/
static async getCollectionHistory(
configId: number
): Promise<CollectionHistory[]> {
const history = await query<any>(
`SELECT * FROM data_collection_jobs
WHERE config_id = $1
ORDER BY started_at DESC
LIMIT 50`,
[configId]
);
return history.map((item: any) => ({
id: item.id,
config_id: item.config_id,
status: item.job_status,
collection_date: item.started_at,
started_at: item.started_at,
completed_at: item.completed_at,
execution_time_ms:
item.completed_at && item.started_at
? new Date(item.completed_at).getTime() -
new Date(item.started_at).getTime()
: null,
records_collected: item.records_processed || 0,
result_message: `${item.records_processed || 0}개의 레코드가 처리되었습니다.`,
error_message: item.error_message,
})) as CollectionHistory[];
}
}