summaryrefslogtreecommitdiff
path: root/lib/docu-list-rule/document-class/service.ts
diff options
context:
space:
mode:
author0-Zz-ang <s1998319@gmail.com>2025-08-04 14:59:15 +0900
committer0-Zz-ang <s1998319@gmail.com>2025-08-04 14:59:15 +0900
commit59b5715ebb3e1fd7bd4eb02ce50399715734f865 (patch)
tree39ccd16482c1b90b6583ead73384822157254d88 /lib/docu-list-rule/document-class/service.ts
parentf0213de0d2fb5fcb931b3ddaddcbb6581cab5d28 (diff)
(박서영) docu-list-rule detail sheet 컴포넌트 추가 및 검색 필터 기능 오류 수정
Diffstat (limited to 'lib/docu-list-rule/document-class/service.ts')
-rw-r--r--lib/docu-list-rule/document-class/service.ts167
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