diff options
Diffstat (limited to 'lib/docu-list-rule/document-class/service.ts')
| -rw-r--r-- | lib/docu-list-rule/document-class/service.ts | 167 |
1 files changed, 130 insertions, 37 deletions
diff --git a/lib/docu-list-rule/document-class/service.ts b/lib/docu-list-rule/document-class/service.ts index 99d85ea5..a1bb14a7 100644 --- a/lib/docu-list-rule/document-class/service.ts +++ b/lib/docu-list-rule/document-class/service.ts @@ -3,7 +3,7 @@ import { revalidatePath } from "next/cache" import db from "@/db/db" import { documentClasses, documentClassOptions, codeGroups } from "@/db/schema/docu-list-rule" -import { eq, desc, asc, sql } from "drizzle-orm" +import { eq, desc, asc, sql, and } from "drizzle-orm" // Document Class 목록 조회 (A Class, B Class 등) export async function getDocumentClassCodeGroups(input: { @@ -69,7 +69,7 @@ export async function getDocumentClassCodeGroups(input: { } // 정렬 (안전한 필드 체크 적용) - let orderBy = sql`${documentClasses.createdAt} DESC` + let orderBy = sql`${documentClasses.code} ASC` if (sort && sort.length > 0) { const sortField = sort[0] // 안전성 체크: 필드가 실제 테이블에 존재하는지 확인 @@ -274,8 +274,34 @@ export async function updateDocumentClassCodeGroup(input: { } // Document Class 삭제 +// Document Class의 옵션 개수 조회 +export async function getDocumentClassOptionsCount(documentClassId: number) { + try { + const result = await db + .select({ count: sql<number>`count(*)` }) + .from(documentClassOptions) + .where(eq(documentClassOptions.documentClassId, documentClassId)) + + return { + success: true, + count: result[0]?.count || 0 + } + } catch (error) { + console.error("Error getting document class options count:", error) + return { + success: false, + count: 0 + } + } +} + export async function deleteDocumentClassCodeGroup(id: number) { try { + // 먼저 해당 Document Class의 옵션들을 삭제 + await db + .delete(documentClassOptions) + .where(eq(documentClassOptions.documentClassId, id)) + // 삭제할 Document Class의 codeGroupId 확인 const documentClassToDelete = await db .select({ codeGroupId: documentClasses.codeGroupId }) @@ -310,7 +336,7 @@ export async function deleteDocumentClassCodeGroup(id: number) { return { success: true, data: deletedDocumentClass, - message: "Document Class deleted successfully" + message: "Document Class and its options deleted successfully" } } catch (error) { console.error("Error deleting document class:", error) @@ -322,22 +348,57 @@ export async function deleteDocumentClassCodeGroup(id: number) { } // Document Class 옵션 목록 조회 -export async function getDocumentClassSubOptions(documentClassId: number) { +export async function getDocumentClassSubOptions(documentClassId: number, input?: { + page?: number + perPage?: number + search?: string + sort?: Array<{ id: string; desc: boolean }> + filters?: Array<{ id: string; value: string }> + joinOperator?: "and" | "or" +}) { try { + const { page = 1, perPage = 1000, sort, search } = input || {} + const offset = (page - 1) * perPage + + // 기본 조건: documentClassId + let whereConditions = eq(documentClassOptions.documentClassId, documentClassId) + + // 검색 조건 + if (search) { + const searchTerm = `%${search}%` + whereConditions = sql`${whereConditions} AND ( + ${documentClassOptions.optionCode} ILIKE ${searchTerm} OR + ${documentClassOptions.description} ILIKE ${searchTerm} + )` + } + + // 정렬 (안전한 필드 체크 적용) + let orderBy = sql`${documentClassOptions.optionCode} ASC` + if (sort && sort.length > 0) { + const sortField = sort[0] + // 안전성 체크: 필드가 실제 테이블에 존재하는지 확인 + if (sortField && sortField.id && typeof sortField.id === "string" && sortField.id in documentClassOptions) { + const direction = sortField.desc ? sql`DESC` : sql`ASC` + const col = documentClassOptions[sortField.id as keyof typeof documentClassOptions] + orderBy = sql`${col} ${direction}` + } + } + const data = await db .select({ id: documentClassOptions.id, documentClassId: documentClassOptions.documentClassId, - optionValue: documentClassOptions.optionValue, + description: documentClassOptions.description, optionCode: documentClassOptions.optionCode, - sortOrder: documentClassOptions.sortOrder, isActive: documentClassOptions.isActive, createdAt: documentClassOptions.createdAt, updatedAt: documentClassOptions.updatedAt, }) .from(documentClassOptions) - .where(eq(documentClassOptions.documentClassId, documentClassId)) - .orderBy(asc(documentClassOptions.sortOrder), asc(documentClassOptions.optionValue)) + .where(whereConditions) + .orderBy(orderBy) + .limit(perPage) + .offset(offset) return { success: true, @@ -356,7 +417,7 @@ export async function getDocumentClassSubOptions(documentClassId: number) { // Document Class 옵션 생성 export async function createDocumentClassOptionItem(input: { documentClassId: number - optionValue: string + optionCode: string }) { try { // Document Class 정보 조회하여 Value 가져오기 @@ -373,30 +434,27 @@ export async function createDocumentClassOptionItem(input: { } } - // Value에서 클래스명 추출 (예: "A Class" → "A") - const classValue = documentClass[0].value - const className = classValue.split(' ')[0] // "A Class"에서 "A" 추출 - // 자동으로 optionCode 생성 (예: "A_OP_01", "A_OP_02" 등) - const existingOptions = await db - .select({ optionCode: documentClassOptions.optionCode }) + + // 사용자가 입력한 코드를 그대로 사용 + const userOptionCode = input.optionCode.toUpperCase().trim() + + // 같은 Document Class 내에서 코드 중복 체크 + const existingOption = await db + .select({ id: documentClassOptions.id }) .from(documentClassOptions) - .where(eq(documentClassOptions.documentClassId, input.documentClassId)) - .orderBy(desc(documentClassOptions.optionCode)) - - let newOptionCode = `${className}_OP_01` - if (existingOptions.length > 0) { - const lastOption = existingOptions[0] - if (lastOption.optionCode) { - // "A_OP_01" 형태에서 숫자 추출 - const match = lastOption.optionCode.match(/_OP_(\d+)$/) - if (match) { - const lastNumber = parseInt(match[1]) || 0 - newOptionCode = `${className}_OP_${String(lastNumber + 1).padStart(2, '0')}` - } else { - // 기존 형식이 다른 경우 01부터 시작 - newOptionCode = `${className}_OP_01` - } + .where( + and( + eq(documentClassOptions.documentClassId, input.documentClassId), + eq(documentClassOptions.optionCode, userOptionCode) + ) + ) + .limit(1) + + if (existingOption.length > 0) { + return { + success: false, + error: "이미 존재하는 코드입니다." } } @@ -404,9 +462,8 @@ export async function createDocumentClassOptionItem(input: { .insert(documentClassOptions) .values({ documentClassId: input.documentClassId, - optionValue: input.optionValue, - optionCode: newOptionCode, - sortOrder: 0, + description: userOptionCode, // 코드값을 description에도 자동 설정 + optionCode: userOptionCode, isActive: true, }) .returning({ id: documentClassOptions.id }) @@ -430,13 +487,49 @@ export async function createDocumentClassOptionItem(input: { // Document Class 옵션 수정 export async function updateDocumentClassOption(input: { id: number - optionValue: string + optionCode: string }) { try { + const userOptionCode = input.optionCode.toUpperCase().trim() + + // 기존 옵션 조회하여 documentClassId 가져오기 + const currentOption = await db + .select({ documentClassId: documentClassOptions.documentClassId }) + .from(documentClassOptions) + .where(eq(documentClassOptions.id, input.id)) + .limit(1) + + if (!currentOption.length) { + return { + success: false, + error: "옵션을 찾을 수 없습니다." + } + } + + // 같은 Document Class 내에서 코드 중복 체크 (자신 제외) + const existingOption = await db + .select({ id: documentClassOptions.id }) + .from(documentClassOptions) + .where( + and( + eq(documentClassOptions.documentClassId, currentOption[0].documentClassId), + eq(documentClassOptions.optionCode, userOptionCode) + ) + ) + .limit(1) + + if (existingOption.length > 0 && existingOption[0].id !== input.id) { + return { + success: false, + error: "이미 존재하는 코드입니다." + } + } + const [updatedOption] = await db .update(documentClassOptions) .set({ - optionValue: input.optionValue, + description: userOptionCode, // 코드값을 description에도 자동 설정 + optionCode: userOptionCode, updatedAt: new Date(), }) .where(eq(documentClassOptions.id, input.id)) @@ -480,4 +573,4 @@ export async function deleteDocumentClassOption(id: number) { error: "Failed to delete document class option" } } -}
\ No newline at end of file +}
\ No newline at end of file |
