diff options
| author | dujinkim <dujin.kim@dtsolution.co.kr> | 2025-05-29 05:17:13 +0000 |
|---|---|---|
| committer | dujinkim <dujin.kim@dtsolution.co.kr> | 2025-05-29 05:17:13 +0000 |
| commit | 37f55540833c2d5894513eca9fc8f7c6233fc2d2 (patch) | |
| tree | 6807978e7150358b3444c33b825c83e2c9cda8e8 /lib/sedp | |
| parent | 4b9bdb29e637f67761beb2db7f75dab0432d6712 (diff) | |
(대표님) 0529 14시 16분 변경사항 저장 (Vendor Data, Docu)
Diffstat (limited to 'lib/sedp')
| -rw-r--r-- | lib/sedp/sync-object-class.ts | 248 |
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 |
