diff options
Diffstat (limited to 'lib/sedp/sync-object-class.ts')
| -rw-r--r-- | lib/sedp/sync-object-class.ts | 257 |
1 files changed, 245 insertions, 12 deletions
diff --git a/lib/sedp/sync-object-class.ts b/lib/sedp/sync-object-class.ts index 1cf0c23b..0a76c592 100644 --- a/lib/sedp/sync-object-class.ts +++ b/lib/sedp/sync-object-class.ts @@ -40,7 +40,12 @@ interface SyncResult { count?: number; error?: string; } - +interface TagType { + TYPE_ID: string; + DESC: string; + PROJ_NO: string; + // 기타 필드들... +} // 오브젝트 클래스 데이터 가져오기 async function getObjectClasses(projectCode: string, token:string): Promise<ObjectClass[]> { try { @@ -55,7 +60,8 @@ async function getObjectClasses(projectCode: string, token:string): Promise<Obje 'ProjectNo': projectCode }, body: JSON.stringify({ - ContainDeleted: true + ProjectNo:projectCode, + ContainDeleted: false }) } ); @@ -95,11 +101,171 @@ async function verifyTagTypes(projectId: number, tagTypeCodes: string[]): Promis } } -// 데이터베이스에 오브젝트 클래스 저장 (upsert 사용) -async function saveObjectClassesToDatabase(projectId: number, classes: ObjectClass[]): Promise<number> { +async function saveTagTypesToDatabase(allTagTypes: TagType[], projectCode: string): Promise<void> { + try { + if (allTagTypes.length === 0) { + console.log(`프로젝트 ${projectCode}에 저장할 태그 타입이 없습니다.`); + return; + } + + // 프로젝트 코드로 프로젝트 ID 조회 + const projectResult = await db.select({ id: projects.id }) + .from(projects) + .where(eq(projects.code, projectCode)) + .limit(1); + + if (projectResult.length === 0) { + throw new Error(`프로젝트 코드 ${projectCode}에 해당하는 프로젝트를 찾을 수 없습니다.`); + } + + const projectId = projectResult[0].id; + + // 현재 프로젝트의 모든 태그 타입 조회 + const existingTagTypes = await db.select() + .from(tagTypes) + .where(eq(tagTypes.projectId, projectId)); + + // 코드 기준으로 맵 생성 + const existingTagTypeMap = new Map( + existingTagTypes.map(type => [type.code, type]) + ); + + // API에 있는 코드 목록 + const apiTagTypeCodes = new Set(allTagTypes.map(type => type.TYPE_ID)); + + // 삭제할 코드 목록 + const codesToDelete = existingTagTypes + .map(type => type.code) + .filter(code => !apiTagTypeCodes.has(code)); + + // 새로 추가할 항목 + const toInsert = []; + + // 업데이트할 항목 + const toUpdate = []; + + // 태그 타입 데이터 처리 + for (const tagType of allTagTypes) { + // 데이터베이스 레코드 준비 + const record = { + code: tagType.TYPE_ID, + projectId: projectId, + description: tagType.DESC, + updatedAt: new Date() + }; + + // 이미 존재하는 코드인지 확인 + if (existingTagTypeMap.has(tagType.TYPE_ID)) { + // 업데이트 항목에 추가 + toUpdate.push(record); + } else { + // 새로 추가할 항목에 추가 (createdAt 필드 추가) + toInsert.push({ + ...record, + createdAt: new Date() + }); + } + } + + // 트랜잭션 실행 + + // 1. 새 항목 삽입 + if (toInsert.length > 0) { + await db.insert(tagTypes).values(toInsert); + console.log(`프로젝트 ID ${projectId}에 ${toInsert.length}개의 새 태그 타입 추가 완료`); + } + + // 2. 기존 항목 업데이트 + for (const item of toUpdate) { + await db.update(tagTypes) + .set({ + description: item.description, + updatedAt: item.updatedAt + }) + .where( + and( + eq(tagTypes.code, item.code), + eq(tagTypes.projectId, item.projectId) + ) + ); + } + + if (toUpdate.length > 0) { + console.log(`프로젝트 ID ${projectId}의 ${toUpdate.length}개 태그 타입 업데이트 완료`); + } + + // 3. 더 이상 존재하지 않는 항목 삭제 + if (codesToDelete.length > 0) { + for (const code of codesToDelete) { + await db.delete(tagTypes) + .where( + and( + eq(tagTypes.code, code), + eq(tagTypes.projectId, projectId) + ) + ); + } + console.log(`프로젝트 ID ${projectId}에서 ${codesToDelete.length}개의 태그 타입 삭제 완료`); + } + + console.log(`프로젝트 ${projectCode}(ID: ${projectId})의 태그 타입 동기화 완료`); + } catch (error) { + console.error(`태그 타입 저장 실패 (프로젝트: ${projectCode}):`, error); + throw error; + } +} + +async function getAllTagTypes(projectCode: string, token: string): Promise<TagType[]> { + try { + console.log(`프로젝트 ${projectCode}의 모든 태그 타입 가져오기 시작`); + + const response = await fetch( + `${SEDP_API_BASE_URL}/TagType/Get`, + { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'accept': '*/*', + 'ApiKey': token, + 'ProjectNo': projectCode + }, + body: JSON.stringify({ + ProjectNo: projectCode, + ContainDeleted: false + }) + } + ); + + if (!response.ok) { + throw new Error(`태그 타입 요청 실패: ${response.status} ${response.statusText}`); + } + + const data = await response.json(); + + // 결과가 배열인지 확인 + if (Array.isArray(data)) { + return data; + } else { + // 단일 객체인 경우 배열로 변환 + return [data]; + } + } catch (error) { + console.error('태그 타입 목록 가져오기 실패:', error); + throw error; + } +} + +// 4. 기존 함수 수정 - saveObjectClassesToDatabase +async function saveObjectClassesToDatabase( + projectId: number, + classes: ObjectClass[], + projectCode: string, + token: string, + skipTagTypeSync: boolean = false // 태그 타입 동기화를 건너뛸지 여부 +): Promise<number> { try { // null이 아닌 TAG_TYPE_ID만 필터링 - const validClasses = classes.filter(cls => cls.TAG_TYPE_ID !== null); + const validClasses = classes.filter(cls => cls.TAG_TYPE_ID !== null && cls.TAG_TYPE_ID !== "") ; if (validClasses.length === 0) { console.log(`프로젝트 ID ${projectId}에 저장할 유효한 오브젝트 클래스가 없습니다.`); @@ -109,6 +275,25 @@ async function saveObjectClassesToDatabase(projectId: number, classes: ObjectCla // 모든 태그 타입 ID 목록 추출 const tagTypeCodes = validClasses.map(cls => cls.TAG_TYPE_ID!); + // skipTagTypeSync가 true인 경우 태그 타입 동기화 단계 건너뜀 + if (!skipTagTypeSync) { + // 태그 타입이 없는 경우를 대비해 태그 타입 정보 먼저 가져와서 저장 + console.log(`프로젝트 ID ${projectId}의 태그 타입 동기화 시작...`); + + try { + // 프로젝트의 모든 태그 타입 가져오기 + const allTagTypes = await getAllTagTypes(projectCode, token); + + // 태그 타입 저장 + await saveTagTypesToDatabase(allTagTypes, projectCode); + } catch (error) { + console.error(`프로젝트 ${projectCode}의 태그 타입 동기화 실패:`, error); + // 에러가 발생해도 계속 진행 + } + + console.log(`프로젝트 ID ${projectId}의 태그 타입 동기화 완료`); + } + // 존재하는 태그 타입 확인 const existingTagTypeCodes = await verifyTagTypes(projectId, tagTypeCodes); @@ -122,6 +307,7 @@ async function saveObjectClassesToDatabase(projectId: number, classes: ObjectCla return 0; } + // 이하 기존 코드와 동일 // 현재 프로젝트의 오브젝트 클래스 코드 가져오기 const existingClasses = await db.select() .from(tagClasses) @@ -223,7 +409,7 @@ async function saveObjectClassesToDatabase(projectId: number, classes: ObjectCla } } -// 메인 동기화 함수 +// 5. 메인 동기화 함수 수정 export async function syncObjectClasses() { try { console.log('오브젝트 클래스 동기화 시작:', new Date().toISOString()); @@ -234,15 +420,55 @@ export async function syncObjectClasses() { // 2. 모든 프로젝트 가져오기 const allProjects = await db.select().from(projects); - // 3. 각 프로젝트에 대해 오브젝트 클래스 동기화 + // 3. 모든 프로젝트에 대해 먼저 태그 타입 동기화 (바로 이 부분이 추가됨) + console.log('모든 프로젝트의 태그 타입 동기화 시작...'); + + const tagTypeResults = await Promise.allSettled( + allProjects.map(async (project: Project) => { + try { + console.log(`프로젝트 ${project.code}의 태그 타입 동기화 시작...`); + // 프로젝트의 모든 태그 타입 가져오기 + const allTagTypes = await getAllTagTypes(project.code, token); + + // 태그 타입 저장 + await saveTagTypesToDatabase(allTagTypes, project.code); + console.log(`프로젝트 ${project.code}의 태그 타입 동기화 완료`); + + return { + project: project.code, + success: true, + count: allTagTypes.length + }; + } catch (error) { + console.error(`프로젝트 ${project.code}의 태그 타입 동기화 실패:`, error); + return { + project: project.code, + success: false, + error: error instanceof Error ? error.message : String(error) + }; + } + }) + ); + + // 태그 타입 동기화 결과 집계 + const tagTypeSuccessCount = tagTypeResults.filter( + result => result.status === 'fulfilled' && result.value.success + ).length; + + const tagTypeFailCount = tagTypeResults.length - tagTypeSuccessCount; + + console.log(`모든 프로젝트의 태그 타입 동기화 완료: ${tagTypeSuccessCount}개 성공, ${tagTypeFailCount}개 실패`); + + // 4. 각 프로젝트에 대해 오브젝트 클래스 동기화 (태그 타입 동기화는 건너뜀) const results = await Promise.allSettled( allProjects.map(async (project: Project) => { try { // 오브젝트 클래스 데이터 가져오기 const objectClasses = await getObjectClasses(project.code, token); - // 데이터베이스에 저장 - const count = await saveObjectClassesToDatabase(project.id, objectClasses); + // 데이터베이스에 저장 (skipTagTypeSync를 true로 설정하여 태그 타입 동기화 건너뜀) + const count = await saveObjectClassesToDatabase(project.id, objectClasses, project.code, token, true); + return { project: project.code, success: true, @@ -291,10 +517,17 @@ export async function syncObjectClasses() { console.log(`오브젝트 클래스 동기화 완료: ${successCount}개 프로젝트 성공 (총 ${totalItems}개 항목), ${failCount}개 프로젝트 실패`); + // 전체 결과에 태그 타입 동기화 결과도 포함 return { - success: successCount, - failed: failCount, - items: totalItems, + tagTypeSync: { + success: tagTypeSuccessCount, + failed: tagTypeFailCount + }, + objectClassSync: { + success: successCount, + failed: failCount, + items: totalItems + }, timestamp: new Date().toISOString() }; } catch (error) { |
