summaryrefslogtreecommitdiff
path: root/lib/sedp
diff options
context:
space:
mode:
authordujinkim <dujin.kim@dtsolution.co.kr>2025-05-29 05:17:13 +0000
committerdujinkim <dujin.kim@dtsolution.co.kr>2025-05-29 05:17:13 +0000
commit37f55540833c2d5894513eca9fc8f7c6233fc2d2 (patch)
tree6807978e7150358b3444c33b825c83e2c9cda8e8 /lib/sedp
parent4b9bdb29e637f67761beb2db7f75dab0432d6712 (diff)
(대표님) 0529 14시 16분 변경사항 저장 (Vendor Data, Docu)
Diffstat (limited to 'lib/sedp')
-rw-r--r--lib/sedp/sync-object-class.ts248
1 files changed, 238 insertions, 10 deletions
diff --git a/lib/sedp/sync-object-class.ts b/lib/sedp/sync-object-class.ts
index 68b9384f..5fd3ebff 100644
--- a/lib/sedp/sync-object-class.ts
+++ b/lib/sedp/sync-object-class.ts
@@ -1,5 +1,5 @@
import db from "@/db/db";
-import { projects, tagClasses, tagTypes } from '@/db/schema';
+import { projects, tagClassAttributes, tagClasses, tagTypes } from '@/db/schema';
import { eq, and } from 'drizzle-orm';
import { getSEDPToken } from "./sedp-token";
@@ -13,7 +13,7 @@ interface ObjectClass {
DESC: string;
TAG_TYPE_ID: string | null;
PRT_CLS_ID: string | null;
- LNK_ATT: any[];
+ LNK_ATT: LinkAttribute[];
DELETED: boolean;
DEL_USER: string | null;
DEL_DTM: string | null;
@@ -40,12 +40,123 @@ interface SyncResult {
count?: number;
error?: string;
}
+
interface TagType {
TYPE_ID: string;
DESC: string;
PROJ_NO: string;
// 기타 필드들...
}
+
+interface LinkAttribute {
+ ATT_ID: string;
+ DEF_VAL: string;
+ UOM_ID: string;
+ SEQ: number;
+}
+
+// 태그 클래스 속성 저장 함수
+async function saveTagClassAttributes(
+ tagClassId: number,
+ attributes: LinkAttribute[]
+): Promise<void> {
+ try {
+ if (attributes.length === 0) {
+ console.log(`태그 클래스 ID ${tagClassId}에 저장할 속성이 없습니다.`);
+ return;
+ }
+
+ // 현재 태그 클래스의 모든 속성 조회
+ const existingAttributes = await db.select()
+ .from(tagClassAttributes)
+ .where(eq(tagClassAttributes.tagClassId, tagClassId));
+
+ // 속성 ID 기준으로 맵 생성
+ const existingAttributeMap = new Map(
+ existingAttributes.map(attr => [attr.attId, attr])
+ );
+
+ // API에 있는 속성 ID 목록
+ const apiAttributeIds = new Set(attributes.map(attr => attr.ATT_ID));
+
+ // 삭제할 속성 ID 목록
+ const attributeIdsToDelete = existingAttributes
+ .map(attr => attr.attId)
+ .filter(attId => !apiAttributeIds.has(attId));
+
+ // 새로 추가할 항목과 업데이트할 항목 분리
+ const toInsert = [];
+ const toUpdate = [];
+
+ for (const attr of attributes) {
+ const record = {
+ tagClassId: tagClassId,
+ attId: attr.ATT_ID,
+ defVal: attr.DEF_VAL,
+ uomId: attr.UOM_ID,
+ seq: attr.SEQ,
+ updatedAt: new Date()
+ };
+
+ if (existingAttributeMap.has(attr.ATT_ID)) {
+ // 업데이트 항목
+ toUpdate.push(record);
+ } else {
+ // 새로 추가할 항목
+ toInsert.push({
+ ...record,
+ createdAt: new Date()
+ });
+ }
+ }
+
+ // 1. 새 항목 삽입
+ if (toInsert.length > 0) {
+ await db.insert(tagClassAttributes).values(toInsert);
+ console.log(`태그 클래스 ID ${tagClassId}에 ${toInsert.length}개의 새 속성 추가 완료`);
+ }
+
+ // 2. 기존 항목 업데이트
+ for (const item of toUpdate) {
+ await db.update(tagClassAttributes)
+ .set({
+ defVal: item.defVal,
+ uomId: item.uomId,
+ seq: item.seq,
+ updatedAt: item.updatedAt
+ })
+ .where(
+ and(
+ eq(tagClassAttributes.tagClassId, item.tagClassId),
+ eq(tagClassAttributes.attId, item.attId)
+ )
+ );
+ }
+
+ if (toUpdate.length > 0) {
+ console.log(`태그 클래스 ID ${tagClassId}의 ${toUpdate.length}개 속성 업데이트 완료`);
+ }
+
+ // 3. 더 이상 존재하지 않는 항목 삭제
+ if (attributeIdsToDelete.length > 0) {
+ for (const attId of attributeIdsToDelete) {
+ await db.delete(tagClassAttributes)
+ .where(
+ and(
+ eq(tagClassAttributes.tagClassId, tagClassId),
+ eq(tagClassAttributes.attId, attId)
+ )
+ );
+ }
+ console.log(`태그 클래스 ID ${tagClassId}에서 ${attributeIdsToDelete.length}개의 속성 삭제 완료`);
+ }
+
+ } catch (error) {
+ console.error(`태그 클래스 속성 저장 실패 (태그 클래스 ID: ${tagClassId}):`, error);
+ throw error;
+ }
+}
+
// 오브젝트 클래스 데이터 가져오기
async function getObjectClasses(projectCode: string, token:string): Promise<ObjectClass[]> {
try {
@@ -255,7 +366,7 @@ async function getAllTagTypes(projectCode: string, token: string): Promise<TagTy
}
}
-// 4. 기존 함수 수정 - saveObjectClassesToDatabase
+// LNK_ATT 속성 처리가 포함된 오브젝트 클래스 저장 함수
async function saveObjectClassesToDatabase(
projectId: number,
classes: ObjectClass[],
@@ -307,7 +418,6 @@ async function saveObjectClassesToDatabase(
return 0;
}
- // 이하 기존 코드와 동일
// 현재 프로젝트의 오브젝트 클래스 코드 가져오기
const existingClasses = await db.select()
.from(tagClasses)
@@ -359,14 +469,31 @@ async function saveObjectClassesToDatabase(
// 트랜잭션 실행
let totalChanged = 0;
- // 1. 새 항목 삽입
+ // 1. 새 항목 삽입 및 속성 처리
if (toInsert.length > 0) {
- await db.insert(tagClasses).values(toInsert);
+ // returning을 사용하여 삽입된 레코드의 ID와 code를 가져옴
+ const insertedClasses = await db.insert(tagClasses)
+ .values(toInsert)
+ .returning({ id: tagClasses.id, code: tagClasses.code });
+
totalChanged += toInsert.length;
console.log(`프로젝트 ID ${projectId}에 ${toInsert.length}개의 새 오브젝트 클래스 추가 완료`);
+
+ // 새로 삽입된 각 클래스의 LNK_ATT 속성 처리
+ for (const insertedClass of insertedClasses) {
+ const originalClass = classesToSave.find(cls => cls.CLS_ID === insertedClass.code);
+ if (originalClass && originalClass.LNK_ATT && originalClass.LNK_ATT.length > 0) {
+ try {
+ await saveTagClassAttributes(insertedClass.id, originalClass.LNK_ATT);
+ } catch (error) {
+ console.error(`태그 클래스 ${insertedClass.code}의 속성 저장 실패:`, error);
+ // 속성 저장 실패해도 계속 진행
+ }
+ }
+ }
}
- // 2. 기존 항목 업데이트
+ // 2. 기존 항목 업데이트 및 속성 처리
for (const item of toUpdate) {
await db.update(tagClasses)
.set({
@@ -380,6 +507,30 @@ async function saveObjectClassesToDatabase(
eq(tagClasses.projectId, item.projectId)
)
);
+
+ // 업데이트된 클래스의 ID 조회
+ const updatedClass = await db.select({ id: tagClasses.id })
+ .from(tagClasses)
+ .where(
+ and(
+ eq(tagClasses.code, item.code),
+ eq(tagClasses.projectId, item.projectId)
+ )
+ )
+ .limit(1);
+
+ if (updatedClass.length > 0) {
+ const originalClass = classesToSave.find(cls => cls.CLS_ID === item.code);
+ if (originalClass && originalClass.LNK_ATT) {
+ try {
+ await saveTagClassAttributes(updatedClass[0].id, originalClass.LNK_ATT);
+ } catch (error) {
+ console.error(`태그 클래스 ${item.code}의 속성 업데이트 실패:`, error);
+ // 속성 업데이트 실패해도 계속 진행
+ }
+ }
+ }
+
totalChanged += 1;
}
@@ -387,7 +538,7 @@ async function saveObjectClassesToDatabase(
console.log(`프로젝트 ID ${projectId}의 ${toUpdate.length}개 오브젝트 클래스 업데이트 완료`);
}
- // 3. 더 이상 존재하지 않는 항목 삭제
+ // 3. 더 이상 존재하지 않는 항목 삭제 (CASCADE로 속성도 자동 삭제됨)
if (codesToDelete.length > 0) {
for (const code of codesToDelete) {
await db.delete(tagClasses)
@@ -409,7 +560,7 @@ async function saveObjectClassesToDatabase(
}
}
-// 5. 메인 동기화 함수 수정
+// 메인 동기화 함수
export async function syncObjectClasses() {
try {
console.log('오브젝트 클래스 동기화 시작:', new Date().toISOString());
@@ -420,7 +571,7 @@ export async function syncObjectClasses() {
// 2. 모든 프로젝트 가져오기
const allProjects = await db.select().from(projects);
- // 3. 모든 프로젝트에 대해 먼저 태그 타입 동기화 (바로 이 부분이 추가됨)
+ // 3. 모든 프로젝트에 대해 먼저 태그 타입 동기화
console.log('모든 프로젝트의 태그 타입 동기화 시작...');
const tagTypeResults = await Promise.allSettled(
@@ -467,6 +618,7 @@ export async function syncObjectClasses() {
const objectClasses = await getObjectClasses(project.code, token);
// 데이터베이스에 저장 (skipTagTypeSync를 true로 설정하여 태그 타입 동기화 건너뜀)
+ // 이 과정에서 LNK_ATT 속성도 함께 처리됨
const count = await saveObjectClassesToDatabase(project.id, objectClasses, project.code, token, true);
return {
@@ -534,4 +686,80 @@ export async function syncObjectClasses() {
console.error('오브젝트 클래스 동기화 중 오류 발생:', error);
throw error;
}
+}
+
+// 유틸리티 함수들 (필요시 사용)
+export async function getTagClassWithAttributes(tagClassId: number) {
+ const tagClass = await db.select()
+ .from(tagClasses)
+ .where(eq(tagClasses.id, tagClassId))
+ .limit(1);
+
+ if (tagClass.length === 0) {
+ return null;
+ }
+
+ const attributes = await db.select()
+ .from(tagClassAttributes)
+ .where(eq(tagClassAttributes.tagClassId, tagClassId))
+ .orderBy(tagClassAttributes.seq);
+
+ return {
+ ...tagClass[0],
+ attributes
+ };
+}
+
+export async function getProjectTagClassesWithAttributes(projectId: number) {
+ const result = await db.select({
+ // 태그 클래스 정보
+ id: tagClasses.id,
+ code: tagClasses.code,
+ label: tagClasses.label,
+ tagTypeCode: tagClasses.tagTypeCode,
+ createdAt: tagClasses.createdAt,
+ updatedAt: tagClasses.updatedAt,
+ // 속성 정보
+ attributeId: tagClassAttributes.id,
+ attId: tagClassAttributes.attId,
+ defVal: tagClassAttributes.defVal,
+ uomId: tagClassAttributes.uomId,
+ seq: tagClassAttributes.seq
+ })
+ .from(tagClasses)
+ .leftJoin(tagClassAttributes, eq(tagClasses.id, tagClassAttributes.tagClassId))
+ .where(eq(tagClasses.projectId, projectId))
+ .orderBy(tagClasses.code, tagClassAttributes.seq);
+
+ // 결과를 태그 클래스별로 그룹화
+ const groupedResult = result.reduce((acc, row) => {
+ const tagClassId = row.id;
+
+ if (!acc[tagClassId]) {
+ acc[tagClassId] = {
+ id: row.id,
+ code: row.code,
+ label: row.label,
+ tagTypeCode: row.tagTypeCode,
+ createdAt: row.createdAt,
+ updatedAt: row.updatedAt,
+ attributes: []
+ };
+ }
+
+ // 속성이 있는 경우에만 추가
+ if (row.attributeId) {
+ acc[tagClassId].attributes.push({
+ id: row.attributeId,
+ attId: row.attId,
+ defVal: row.defVal,
+ uomId: row.uomId,
+ seq: row.seq
+ });
+ }
+
+ return acc;
+ }, {} as Record<number, any>);
+
+ return Object.values(groupedResult);
} \ No newline at end of file