237 lines
5.5 KiB
TypeScript
237 lines
5.5 KiB
TypeScript
import { query, queryOne } from "../database/db";
|
|
|
|
export interface DataflowDiagram {
|
|
diagram_id: number;
|
|
diagram_name: string;
|
|
relationships: any; // JSON 타입
|
|
company_code: string;
|
|
created_at?: Date;
|
|
updated_at?: Date;
|
|
created_by?: string;
|
|
updated_by?: string;
|
|
}
|
|
|
|
export interface CreateDataflowDiagramData {
|
|
diagram_name: string;
|
|
relationships: any;
|
|
company_code: string;
|
|
created_by?: string;
|
|
}
|
|
|
|
export interface UpdateDataflowDiagramData {
|
|
diagram_name?: string;
|
|
relationships?: any;
|
|
updated_by?: string;
|
|
}
|
|
|
|
export class DataflowDiagramService {
|
|
/**
|
|
* 관계도 목록 조회 (페이지네이션)
|
|
*/
|
|
async getDataflowDiagrams(
|
|
companyCode: string,
|
|
page: number = 1,
|
|
size: number = 20,
|
|
searchTerm: string = ""
|
|
) {
|
|
const skip = (page - 1) * size;
|
|
|
|
const whereClause: any = {
|
|
company_code: companyCode,
|
|
};
|
|
|
|
if (searchTerm) {
|
|
whereClause.diagram_name = {
|
|
contains: searchTerm,
|
|
mode: "insensitive",
|
|
};
|
|
}
|
|
|
|
// WHERE 절 구성
|
|
const whereParts: string[] = ["company_code = $1"];
|
|
const params: any[] = [companyCode];
|
|
|
|
if (searchTerm) {
|
|
whereParts.push("diagram_name ILIKE $2");
|
|
params.push(`%${searchTerm}%`);
|
|
}
|
|
|
|
const whereSQL = whereParts.join(" AND ");
|
|
|
|
const [diagrams, totalResult] = await Promise.all([
|
|
query<DataflowDiagram>(
|
|
`SELECT * FROM dataflow_diagrams
|
|
WHERE ${whereSQL}
|
|
ORDER BY created_at DESC
|
|
LIMIT $${params.length + 1} OFFSET $${params.length + 2}`,
|
|
[...params, size, skip]
|
|
),
|
|
queryOne<{ count: string }>(
|
|
`SELECT COUNT(*) as count FROM dataflow_diagrams WHERE ${whereSQL}`,
|
|
params
|
|
),
|
|
]);
|
|
|
|
const total = parseInt(totalResult?.count || "0", 10);
|
|
|
|
return {
|
|
diagrams,
|
|
pagination: {
|
|
page,
|
|
size,
|
|
total,
|
|
totalPages: Math.ceil(total / size),
|
|
},
|
|
};
|
|
}
|
|
|
|
/**
|
|
* 특정 관계도 조회
|
|
*/
|
|
async getDataflowDiagramById(
|
|
diagramId: number,
|
|
companyCode: string
|
|
): Promise<DataflowDiagram | null> {
|
|
return await queryOne<DataflowDiagram>(
|
|
`SELECT * FROM dataflow_diagrams
|
|
WHERE diagram_id = $1 AND company_code = $2`,
|
|
[diagramId, companyCode]
|
|
);
|
|
}
|
|
|
|
/**
|
|
* 관계도 생성
|
|
*/
|
|
async createDataflowDiagram(
|
|
data: CreateDataflowDiagramData
|
|
): Promise<DataflowDiagram> {
|
|
const result = await queryOne<DataflowDiagram>(
|
|
`INSERT INTO dataflow_diagrams
|
|
(diagram_name, relationships, company_code, created_by, created_at, updated_at)
|
|
VALUES ($1, $2, $3, $4, NOW(), NOW())
|
|
RETURNING *`,
|
|
[
|
|
data.diagram_name,
|
|
JSON.stringify(data.relationships),
|
|
data.company_code,
|
|
data.created_by || null,
|
|
]
|
|
);
|
|
return result!;
|
|
}
|
|
|
|
/**
|
|
* 관계도 수정
|
|
*/
|
|
async updateDataflowDiagram(
|
|
diagramId: number,
|
|
companyCode: string,
|
|
data: UpdateDataflowDiagramData
|
|
): Promise<DataflowDiagram | null> {
|
|
// 먼저 해당 관계도가 존재하는지 확인
|
|
const existingDiagram = await this.getDataflowDiagramById(
|
|
diagramId,
|
|
companyCode
|
|
);
|
|
if (!existingDiagram) {
|
|
return null;
|
|
}
|
|
|
|
// 동적 UPDATE 쿼리 생성
|
|
const updateFields: string[] = ["updated_at = NOW()"];
|
|
const params: any[] = [];
|
|
let paramIndex = 1;
|
|
|
|
if (data.diagram_name !== undefined) {
|
|
updateFields.push(`diagram_name = $${paramIndex++}`);
|
|
params.push(data.diagram_name);
|
|
}
|
|
if (data.relationships !== undefined) {
|
|
updateFields.push(`relationships = $${paramIndex++}`);
|
|
params.push(JSON.stringify(data.relationships));
|
|
}
|
|
if (data.updated_by !== undefined) {
|
|
updateFields.push(`updated_by = $${paramIndex++}`);
|
|
params.push(data.updated_by);
|
|
}
|
|
|
|
params.push(diagramId);
|
|
|
|
return await queryOne<DataflowDiagram>(
|
|
`UPDATE dataflow_diagrams
|
|
SET ${updateFields.join(", ")}
|
|
WHERE diagram_id = $${paramIndex}
|
|
RETURNING *`,
|
|
params
|
|
);
|
|
}
|
|
|
|
/**
|
|
* 관계도 삭제
|
|
*/
|
|
async deleteDataflowDiagram(
|
|
diagramId: number,
|
|
companyCode: string
|
|
): Promise<boolean> {
|
|
// 먼저 해당 관계도가 존재하는지 확인
|
|
const existingDiagram = await this.getDataflowDiagramById(
|
|
diagramId,
|
|
companyCode
|
|
);
|
|
if (!existingDiagram) {
|
|
return false;
|
|
}
|
|
|
|
await query(`DELETE FROM dataflow_diagrams WHERE diagram_id = $1`, [
|
|
diagramId,
|
|
]);
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* 관계도 복제
|
|
*/
|
|
async copyDataflowDiagram(
|
|
diagramId: number,
|
|
companyCode: string,
|
|
newName?: string,
|
|
createdBy?: string
|
|
): Promise<DataflowDiagram | null> {
|
|
const originalDiagram = await this.getDataflowDiagramById(
|
|
diagramId,
|
|
companyCode
|
|
);
|
|
if (!originalDiagram) {
|
|
return null;
|
|
}
|
|
|
|
// 복제본 이름 생성
|
|
let copyName = newName;
|
|
if (!copyName) {
|
|
// "(1)", "(2)" 형식으로 이름 생성
|
|
const baseName = originalDiagram.diagram_name;
|
|
let counter = 1;
|
|
|
|
while (true) {
|
|
copyName = `${baseName} (${counter})`;
|
|
const existing = await queryOne<DataflowDiagram>(
|
|
`SELECT * FROM dataflow_diagrams
|
|
WHERE company_code = $1 AND diagram_name = $2`,
|
|
[companyCode, copyName]
|
|
);
|
|
|
|
if (!existing) break;
|
|
counter++;
|
|
}
|
|
}
|
|
|
|
return await this.createDataflowDiagram({
|
|
diagram_name: copyName,
|
|
relationships: originalDiagram.relationships,
|
|
company_code: companyCode,
|
|
created_by: createdBy,
|
|
});
|
|
}
|
|
}
|