summaryrefslogtreecommitdiff
path: root/lib/tags
diff options
context:
space:
mode:
authordujinkim <dujin.kim@dtsolution.co.kr>2025-04-02 09:54:08 +0000
committerdujinkim <dujin.kim@dtsolution.co.kr>2025-04-02 09:54:08 +0000
commitdfdfae3018f8499240f48d28ce634f4a5c56e006 (patch)
tree4493b172c061fa5bf4e94c083788110eb1507f6d /lib/tags
parent21a72eeddc74cf775e2a76e2c569de970bd62a7f (diff)
벤더 코멘트 처리
Diffstat (limited to 'lib/tags')
-rw-r--r--lib/tags/service.ts153
-rw-r--r--lib/tags/table/add-tag-dialog.tsx5
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