summaryrefslogtreecommitdiff
path: root/lib/approval-log/service.ts
diff options
context:
space:
mode:
Diffstat (limited to 'lib/approval-log/service.ts')
-rw-r--r--lib/approval-log/service.ts160
1 files changed, 91 insertions, 69 deletions
diff --git a/lib/approval-log/service.ts b/lib/approval-log/service.ts
index 5690e0f9..64ae40a2 100644
--- a/lib/approval-log/service.ts
+++ b/lib/approval-log/service.ts
@@ -10,6 +10,7 @@ import {
or,
sql,
} from 'drizzle-orm';
+import { unstable_cache } from 'next/cache';
import db from '@/db/db';
import { approvalLogs } from '@/db/schema/knox/approvals';
@@ -39,85 +40,106 @@ interface ListInput {
sort?: Array<{ id: string; desc: boolean }>;
}
+/**
+ * 결재 로그 목록 조회 (캐시 적용)
+ *
+ * 캐시 태그: 'approval-logs'
+ * 캐시 무효화: /api/revalidate/approval 호출 시
+ */
export async function getApprovalLogList(input: ListInput) {
- const offset = (input.page - 1) * input.perPage;
+ // 캐시 키 생성 (검색/필터/정렬 조건 포함)
+ const cacheKey = `approval-logs-${JSON.stringify(input)}`;
+
+ return unstable_cache(
+ async () => {
+ const offset = (input.page - 1) * input.perPage;
- /* ------------------------------------------------------------------
- * WHERE 절 구성
- * ----------------------------------------------------------------*/
- const advancedWhere = filterColumns({
- table: approvalLogs,
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- filters: (input.filters ?? []) as any,
- joinOperator: (input.joinOperator ?? 'and') as 'and' | 'or',
- });
+ /* ------------------------------------------------------------------
+ * WHERE 절 구성
+ * ----------------------------------------------------------------*/
+ const advancedWhere = filterColumns({
+ table: approvalLogs,
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ filters: (input.filters ?? []) as any,
+ joinOperator: (input.joinOperator ?? 'and') as 'and' | 'or',
+ });
- // 전역 검색 (subject, content, emailAddress, userId)
- let globalWhere;
- if (input.search) {
- const s = `%${input.search}%`;
- globalWhere = or(
- ilike(approvalLogs.subject, s),
- ilike(approvalLogs.content, s),
- ilike(approvalLogs.emailAddress, s),
- ilike(approvalLogs.userId, s),
- );
- }
+ // 전역 검색 (subject, content, emailAddress, userId)
+ let globalWhere;
+ if (input.search) {
+ const s = `%${input.search}%`;
+ globalWhere = or(
+ ilike(approvalLogs.subject, s),
+ ilike(approvalLogs.content, s),
+ ilike(approvalLogs.emailAddress, s),
+ ilike(approvalLogs.userId, s),
+ );
+ }
- let where = eq(approvalLogs.isDeleted, false); // 기본적으로 삭제되지 않은 것만 조회
+ let where = eq(approvalLogs.isDeleted, false); // 기본적으로 삭제되지 않은 것만 조회
- if (advancedWhere && globalWhere) {
- where = and(where, advancedWhere, globalWhere);
- } else if (advancedWhere) {
- where = and(where, advancedWhere);
- } else if (globalWhere) {
- where = and(where, globalWhere);
- }
+ if (advancedWhere && globalWhere) {
+ const combined = and(where, advancedWhere, globalWhere);
+ if (combined) where = combined;
+ } else if (advancedWhere) {
+ const combined = and(where, advancedWhere);
+ if (combined) where = combined;
+ } else if (globalWhere) {
+ const combined = and(where, globalWhere);
+ if (combined) where = combined;
+ }
- /* ------------------------------------------------------------------
- * ORDER BY 절 구성
- * ----------------------------------------------------------------*/
- let orderBy;
- try {
- orderBy = input.sort && input.sort.length > 0
- ? input.sort
- .map((item) => {
- if (!item || !item.id || typeof item.id !== 'string') return null;
- if (!(item.id in approvalLogs)) return null;
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
- // @ts-ignore
- const col = approvalLogs[item.id];
- return item.desc ? desc(col) : asc(col);
- })
- .filter((v): v is Exclude<typeof v, null> => v !== null)
- : [desc(approvalLogs.createdAt)];
- } catch {
- orderBy = [desc(approvalLogs.createdAt)];
- }
+ /* ------------------------------------------------------------------
+ * ORDER BY 절 구성
+ * ----------------------------------------------------------------*/
+ let orderBy;
+ try {
+ orderBy = input.sort && input.sort.length > 0
+ ? input.sort
+ .map((item) => {
+ if (!item || !item.id || typeof item.id !== 'string') return null;
+ if (!(item.id in approvalLogs)) return null;
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
+ // @ts-ignore
+ const col = approvalLogs[item.id];
+ return item.desc ? desc(col) : asc(col);
+ })
+ .filter((v): v is Exclude<typeof v, null> => v !== null)
+ : [desc(approvalLogs.createdAt)];
+ } catch {
+ orderBy = [desc(approvalLogs.createdAt)];
+ }
- /* ------------------------------------------------------------------
- * 데이터 조회
- * ----------------------------------------------------------------*/
- const data = await db
- .select()
- .from(approvalLogs)
- .where(where)
- .orderBy(...orderBy)
- .limit(input.perPage)
- .offset(offset);
+ /* ------------------------------------------------------------------
+ * 데이터 조회
+ * ----------------------------------------------------------------*/
+ const data = await db
+ .select()
+ .from(approvalLogs)
+ .where(where)
+ .orderBy(...orderBy)
+ .limit(input.perPage)
+ .offset(offset);
- const totalResult = await db
- .select({ count: count() })
- .from(approvalLogs)
- .where(where);
+ const totalResult = await db
+ .select({ count: count() })
+ .from(approvalLogs)
+ .where(where);
- const total = totalResult[0]?.count ?? 0;
- const pageCount = Math.ceil(total / input.perPage);
+ const total = totalResult[0]?.count ?? 0;
+ const pageCount = Math.ceil(total / input.perPage);
- return {
- data,
- pageCount,
- };
+ return {
+ data,
+ pageCount,
+ };
+ },
+ [cacheKey],
+ {
+ tags: ['approval-logs'], // 캐시 태그
+ revalidate: 60, // 60초마다 자동 재검증 (폴백)
+ }
+ )();
}
// ----------------------------------------------------