diff options
| author | dujinkim <dujin.kim@dtsolution.co.kr> | 2025-04-02 09:54:08 +0000 |
|---|---|---|
| committer | dujinkim <dujin.kim@dtsolution.co.kr> | 2025-04-02 09:54:08 +0000 |
| commit | dfdfae3018f8499240f48d28ce634f4a5c56e006 (patch) | |
| tree | 4493b172c061fa5bf4e94c083788110eb1507f6d /lib/tags | |
| parent | 21a72eeddc74cf775e2a76e2c569de970bd62a7f (diff) | |
벤더 코멘트 처리
Diffstat (limited to 'lib/tags')
| -rw-r--r-- | lib/tags/service.ts | 153 | ||||
| -rw-r--r-- | lib/tags/table/add-tag-dialog.tsx | 5 |
2 files changed, 101 insertions, 57 deletions
diff --git a/lib/tags/service.ts b/lib/tags/service.ts index efba2fd5..034c106f 100644 --- a/lib/tags/service.ts +++ b/lib/tags/service.ts @@ -7,7 +7,7 @@ import { createTagSchema, GetTagsSchema, updateTagSchema, UpdateTagSchema, type import { revalidateTag, unstable_noStore } from "next/cache"; import { filterColumns } from "@/lib/filter-columns"; import { unstable_cache } from "@/lib/unstable-cache"; -import { asc, desc, ilike, inArray, and, gte, lte, not, or, eq, sql, ne } from "drizzle-orm"; +import { asc, desc, ilike, inArray, and, gte, lte, not, or, eq, sql, ne ,count,isNull} from "drizzle-orm"; import { countTags, deleteTagById, deleteTagsByIds, insertTag, selectTags } from "./repository"; import { getErrorMessage } from "../handle-error"; import { getFormMappingsByTagType } from './form-mapping-service'; @@ -158,6 +158,7 @@ export async function createTag( const createdOrExistingForms: CreatedOrExistingForm[] = [] if (formMappings && formMappings.length > 0) { + console.log(selectedPackageId, formMappings) for (const formMapping of formMappings) { // 4-1) 이미 존재하는 폼인지 확인 const existingForm = await tx @@ -236,6 +237,8 @@ export async function createTag( } }) } catch (err: any) { + console.log("createTag error:", err) + console.error("createTag error:", err) return { error: getErrorMessage(err) } } @@ -540,12 +543,12 @@ function removeTagFromDataJson( export async function removeTags(input: RemoveTagsInput) { unstable_noStore() // React 서버 액션 무상태 함수 - + const { ids, selectedPackageId } = input - + try { await db.transaction(async (tx) => { - // 1) 삭제 대상 tag들을 미리 조회 (tagNo, tagType, class 등을 얻기 위함) + // 1) 삭제 대상 tag들을 미리 조회 const tagsToDelete = await tx .select({ id: tags.id, @@ -555,72 +558,112 @@ export async function removeTags(input: RemoveTagsInput) { }) .from(tags) .where(inArray(tags.id, ids)) - - // 2) 각 tag마다 관련된 formCode를 찾고, forms & formEntries 처리를 수행 - for (const tagInfo of tagsToDelete) { - const { tagNo, tagType, class: tagClass } = tagInfo - - // 2-1) tagTypeClassFormMappings(혹은 대응되는 로직)에서 formCode 목록 가져오기 - const formMappings = await getFormMappingsByTagType(tagType, tagClass) - if (!formMappings) continue - - // 2-2) 얻어온 formCode 리스트를 순회하면서, forms 테이블과 formEntries 테이블 처리 - for (const fm of formMappings) { - // (A) forms 테이블 삭제 - // - 조건: contractItemId=selectedPackageId, formCode=fm.formCode - await tx - .delete(forms) - .where( - and( - eq(forms.contractItemId, selectedPackageId), - eq(forms.formCode, fm.formCode) - ) + + // 2) 태그 타입과 클래스의 고유 조합 추출 + const uniqueTypeClassCombinations = [...new Set( + tagsToDelete.map(tag => `${tag.tagType}|${tag.class || ''}`) + )].map(combo => { + const [tagType, classValue] = combo.split('|'); + return { tagType, class: classValue || undefined }; + }); + + // 3) 각 태그 타입/클래스 조합에 대해 처리 + for (const { tagType, class: classValue } of uniqueTypeClassCombinations) { + // 3-1) 삭제 중인 태그들 외에, 동일한 태그 타입/클래스를 가진 다른 태그가 있는지 확인 + const otherTagsWithSameTypeClass = await tx + .select({ count: count() }) + .from(tags) + .where( + and( + eq(tags.tagType, tagType), + classValue ? eq(tags.class, classValue) : isNull(tags.class), + not(inArray(tags.id, ids)), // 현재 삭제 중인 태그들은 제외 + eq(tags.contractItemId, selectedPackageId) // 같은 contractItemId 내에서만 확인 ) - - // (B) formEntries 테이블 JSON에서 tagNo 제거 → 업데이트 - // - 예: formEntries 안에 (id, contractItemId, formCode, data(=json)) 칼럼 존재 가정 - const formEntryRecords = await tx - .select({ - id: formEntries.id, - data: formEntries.data, - }) - .from(formEntries) - .where( - and( - eq(formEntries.contractItemId, selectedPackageId), - eq(formEntries.formCode, fm.formCode) + ) + + // 3-2) 이 태그 타입/클래스에 연결된 폼 매핑 가져오기 + const formMappings = await getFormMappingsByTagType(tagType, classValue); + + if (!formMappings.length) continue; + + // 3-3) 이 태그 타입/클래스와 관련된 태그 번호 추출 + const relevantTagNos = tagsToDelete + .filter(tag => tag.tagType === tagType && + (classValue ? tag.class === classValue : !tag.class)) + .map(tag => tag.tagNo); + + // 3-4) 각 폼 코드에 대해 처리 + for (const formMapping of formMappings) { + // 다른 태그가 없다면 폼 삭제 + if (otherTagsWithSameTypeClass[0].count === 0) { + // 폼 삭제 + await tx + .delete(forms) + .where( + and( + eq(forms.contractItemId, selectedPackageId), + eq(forms.formCode, formMapping.formCode) + ) ) - ) - - // 여러 formEntries 레코드가 있을 수도 있어서 모두 처리 - for (const entry of formEntryRecords) { - const updatedJson = removeTagFromDataJson(entry.data, tagNo) - - // 변경이 있다면 업데이트 + + // formEntries 테이블에서도 해당 formCode 관련 데이터 삭제 await tx - .update(formEntries) - .set({ data: updatedJson }) - .where(eq(formEntries.id, entry.id)) + .delete(formEntries) + .where( + and( + eq(formEntries.contractItemId, selectedPackageId), + eq(formEntries.formCode, formMapping.formCode) + ) + ) + } + // 다른 태그가 있다면 formEntries 데이터에서 해당 태그 정보만 제거 + else if (relevantTagNos.length > 0) { + const formEntryRecords = await tx + .select({ + id: formEntries.id, + data: formEntries.data, + }) + .from(formEntries) + .where( + and( + eq(formEntries.contractItemId, selectedPackageId), + eq(formEntries.formCode, formMapping.formCode) + ) + ) + + // 각 formEntry에 대해 처리 + for (const entry of formEntryRecords) { + let updatedJson = entry.data; + + // 각 tagNo에 대해 JSON 데이터에서 제거 + for (const tagNo of relevantTagNos) { + updatedJson = removeTagFromDataJson(updatedJson, tagNo); + } + + // 변경이 있다면 업데이트 + await tx + .update(formEntries) + .set({ data: updatedJson }) + .where(eq(formEntries.id, entry.id)) + } } } } - - // 3) 마지막으로 실제로 tags 테이블에서 Tag들을 삭제 - // (Tag → forms → formEntries 순서대로 처리) + + // 4) 마지막으로 tags 테이블에서 태그들 삭제 await tx.delete(tags).where(inArray(tags.id, ids)) }) - - // 4) 캐시 무효화 - // revalidateTag("tags") + + // 5) 캐시 무효화 revalidateTag(`tags-${selectedPackageId}`) revalidateTag(`forms-${selectedPackageId}`) - + return { data: null, error: null } } catch (err) { return { data: null, error: getErrorMessage(err) } } } - // Updated service functions to support the new schema // 업데이트된 ClassOption 타입 diff --git a/lib/tags/table/add-tag-dialog.tsx b/lib/tags/table/add-tag-dialog.tsx index 3814761d..e1e176cf 100644 --- a/lib/tags/table/add-tag-dialog.tsx +++ b/lib/tags/table/add-tag-dialog.tsx @@ -112,7 +112,6 @@ export function AddTagDialog({ selectedPackageId }: AddTagDialogProps) { const fieldIdsRef = React.useRef<Record<string, string>>({}) const classOptionIdsRef = React.useRef<Record<string, string>>({}) - console.log(subFields) // --------------- // Load Class Options @@ -296,6 +295,7 @@ export function AddTagDialog({ selectedPackageId }: AddTagDialogProps) { try { const res = await createTag(tagData, selectedPackageId); if ("error" in res) { + console.log(res.error ) failedTags.push({ tag: row.tagNo, error: res.error }); } else { successfulTags.push(row.tagNo); @@ -311,8 +311,9 @@ export function AddTagDialog({ selectedPackageId }: AddTagDialogProps) { } if (failedTags.length > 0) { + console.log("Failed tags:", failedTags); + toast.error(`${failedTags.length}개의 태그 생성에 실패했습니다.`); - console.error("Failed tags:", failedTags); } // Refresh the page |
