"use server"; import { sql, SQL } from "drizzle-orm"; import db from "@/db/db"; import { MATERIAL_MASTER_PART_MATL } from "@/db/schema/MDG/mdg"; export interface MaterialSearchItem { materialCode: string; // 자재코드 (MATNR) materialName: string; // 자재명 (ZZNAME) displayText: string; // 애플리케이션 레벨에서 계산된 필드 } export interface MaterialSearchResult { success: boolean; data: MaterialSearchItem[]; pagination: { page: number; perPage: number; total: number; pageCount: number; hasNextPage: boolean; hasPrevPage: boolean; }; } /** * 자재 검색 함수 - MATERIAL_MASTER_PART_MATL 테이블에서 검색 (페이지네이션) * 사용자는 자재코드를 직접 입력하여 검색함 (자재명이 아닌 자재코드만 검색 대상) * 자재 레코드가 수억개 수준이므로 항상 페이지네이션 사용 */ export async function searchMaterialsForSelector( query: string, page: number = 1, perPage: number = 10 ): Promise { try { const offset = (page - 1) * perPage; // 검색 조건 - 자재코드(MATNR)로만 검색 let searchWhere: SQL | undefined; if (query.trim()) { const searchPattern = `%${query.trim()}%`; searchWhere = sql`${MATERIAL_MASTER_PART_MATL.MATNR} ILIKE ${searchPattern}`; } const { data, total } = await db.transaction(async (tx) => { // 데이터 조회 - MATNR과 ZZNAME만 선택 const data = await tx .select({ materialCode: MATERIAL_MASTER_PART_MATL.MATNR, materialName: MATERIAL_MASTER_PART_MATL.ZZNAME, }) .from(MATERIAL_MASTER_PART_MATL) .where(searchWhere) .orderBy(MATERIAL_MASTER_PART_MATL.MATNR) .limit(perPage) .offset(offset); // 총 개수 조회 const countResult = await tx .select({ count: sql`count(*)` }) .from(MATERIAL_MASTER_PART_MATL) .where(searchWhere); const total = countResult[0]?.count || 0; return { data: data.map((row) => ({ materialCode: row.materialCode || '', materialName: row.materialName || '', displayText: `${row.materialCode || ''} - ${row.materialName || ''}`, // 애플리케이션 레벨에서 생성 })), total, }; }); const pageCount = Math.ceil(total / perPage); return { success: true, data, pagination: { page, perPage, total, pageCount, hasNextPage: page < pageCount, hasPrevPage: page > 1, }, }; } catch (error) { console.error("자재 검색 오류:", error); return { success: false, data: [], pagination: { page: 1, perPage: 10, total: 0, pageCount: 0, hasNextPage: false, hasPrevPage: false, }, }; } } /** * Dialog용 자재 목록 조회 함수 - 페이지네이션 * Dialog에서는 효율적인 사용자 경험을 위해 10개씩 페이지네이션하여 조회 * 자재 레코드가 수억개 수준이므로 무한 스크롤이나 전체 로드가 아닌 페이지네이션 사용 */ export async function searchMaterialsForDialog( query: string, page: number = 1, perPage: number = 10 ): Promise<{ success: boolean; data: MaterialSearchItem[]; pagination: { page: number; perPage: number; total: number; pageCount: number; hasNextPage: boolean; hasPrevPage: boolean; }; error?: string; }> { try { const result = await searchMaterialsForSelector(query, page, perPage); return { success: result.success, data: result.data, pagination: result.pagination, error: result.success ? undefined : "검색 중 오류가 발생했습니다.", }; } catch (error) { console.error("Dialog용 자재 검색 오류:", error); return { success: false, data: [], pagination: { page: 1, perPage: 10, total: 0, pageCount: 0, hasNextPage: false, hasPrevPage: false, }, error: "데이터를 불러오는데 실패했습니다.", }; } }