// app/api/table/items/infinite/route.ts import { NextRequest, NextResponse } from "next/server"; import { getItemsInfinite, type GetItemsInfiniteInput } from "@/lib/items/service"; // URL 파라미터를 GetItemsInfiniteInput으로 변환하는 헬퍼 함수 function parseUrlParamsToInfiniteInput(searchParams: URLSearchParams): GetItemsInfiniteInput { // 무한 스크롤 관련 파라미터 const cursor = searchParams.get("cursor") || undefined; const limit = parseInt(searchParams.get("limit") || "50"); // 기존 searchParamsCache와 동일한 필드들 const itemCode = searchParams.get("itemCode") || ""; const itemName = searchParams.get("itemName") || ""; const description = searchParams.get("description") || ""; const parentItemCode = searchParams.get("parentItemCode") || ""; const itemLevel = parseInt(searchParams.get("itemLevel") || "5"); const deleteFlag = searchParams.get("deleteFlag") || ""; const unitOfMeasure = searchParams.get("unitOfMeasure") || ""; const steelType = searchParams.get("steelType") || ""; const gradeMaterial = searchParams.get("gradeMaterial") || ""; const changeDate = searchParams.get("changeDate") || ""; const baseUnitOfMeasure = searchParams.get("baseUnitOfMeasure") || ""; // 고급 필터링 관련 const search = searchParams.get("search") || ""; const joinOperator = searchParams.get("joinOperator") || "and"; // 필터 파라미터 파싱 let filters: any[] = []; const filtersParam = searchParams.get("filters"); if (filtersParam) { try { filters = JSON.parse(filtersParam); } catch (e) { console.warn("Invalid filters parameter:", e); filters = []; } } // 정렬 파라미터 파싱 let sort: Array<{ id: string; desc: boolean }> = []; const sortParam = searchParams.get("sort"); if (sortParam) { try { sort = JSON.parse(sortParam); } catch (e) { console.warn("Invalid sort parameter:", e); // 기본 정렬 sort = [{ id: "createdAt", desc: true }]; } } else { // 정렬이 없으면 기본 정렬 sort = [{ id: "createdAt", desc: true }]; } // 플래그 파라미터 파싱 let flags: string[] = []; const flagsParam = searchParams.get("flags"); if (flagsParam) { try { flags = JSON.parse(flagsParam); } catch (e) { console.warn("Invalid flags parameter:", e); flags = []; } } // searchParamsCache의 모든 필드를 포함한 입력 객체 생성 return { // 무한 스크롤 관련 cursor, limit, // 기본 필터 필드들 (searchParamsCache와 동일) itemCode, itemName, description, parentItemCode, itemLevel, deleteFlag, unitOfMeasure, steelType, gradeMaterial, changeDate, baseUnitOfMeasure, // 고급 필터링 search, filters, joinOperator: joinOperator as "and" | "or", // 정렬 sort, // 플래그 flags, }; } export async function GET(request: NextRequest) { try { const searchParams = request.nextUrl.searchParams; console.log('API Request URL:', request.url); console.log('Search Params:', Object.fromEntries(searchParams.entries())); // URL 파라미터를 서비스 입력으로 변환 const input = parseUrlParamsToInfiniteInput(searchParams); console.log('Parsed Input:', JSON.stringify(input, null, 2)); // 무한 스크롤 서비스 함수 호출 const result = await getItemsInfinite(input); console.log('Service Result:', { dataCount: result.data.length, hasNextPage: result.hasNextPage, nextCursor: result.nextCursor, total: result.total, }); // 응답에 메타데이터 추가 const response = { mode: 'infinite' as const, ...result, meta: { table: 'items', displayName: 'Package Items', requestedLimit: input.limit || 50, actualLimit: Math.min(input.limit || 50, 100), maxPageSize: 100, cursor: input.cursor || null, apiVersion: '1.0', timestamp: new Date().toISOString(), supportedFields: [ 'itemCode', 'itemName', 'description', 'parentItemCode', 'itemLevel', 'deleteFlag', 'unitOfMeasure', 'steelType', 'gradeMaterial', 'changeDate', 'baseUnitOfMeasure' ], searchableFields: [ 'itemLevel', 'itemCode', 'itemName', 'description', 'parentItemCode', 'unitOfMeasure', 'steelType', 'gradeMaterial', 'baseUnitOfMeasure', 'changeDate' ], } }; return NextResponse.json(response); } catch (error) { console.error("Items infinite API error:", error); return NextResponse.json({ mode: 'infinite' as const, data: [], hasNextPage: false, nextCursor: null, total: 0, error: { message: "Failed to fetch items", details: error instanceof Error ? error.message : 'Unknown error', timestamp: new Date().toISOString(), stack: process.env.NODE_ENV === 'development' ? (error instanceof Error ? error.stack : undefined) : undefined, } }, { status: 500 }); } } // OPTIONS 메서드로 API 정보 제공 export async function OPTIONS() { return NextResponse.json({ table: 'items', displayName: 'Package Items', mode: 'infinite', supportedMethods: ['GET'], maxPageSize: 100, defaultPageSize: 50, // 지원되는 모든 파라미터 supportedParams: { // 무한 스크롤 관련 cursor: { type: 'string', description: 'Cursor for pagination' }, limit: { type: 'number', description: 'Number of items per page', max: 100, default: 50 }, // 기본 필터 필드들 itemCode: { type: 'string', description: 'Item code filter' }, itemName: { type: 'string', description: 'Item name filter' }, description: { type: 'string', description: 'Description filter' }, parentItemCode: { type: 'string', description: 'Parent item code filter' }, itemLevel: { type: 'number', description: 'Item level filter', default: 5 }, deleteFlag: { type: 'string', description: 'Delete flag filter' }, unitOfMeasure: { type: 'string', description: 'Unit of measure filter' }, steelType: { type: 'string', description: 'Steel type filter' }, gradeMaterial: { type: 'string', description: 'Grade material filter' }, changeDate: { type: 'string', description: 'Change date filter' }, baseUnitOfMeasure: { type: 'string', description: 'Base unit of measure filter' }, // 고급 필터링 search: { type: 'string', description: 'Global search across all fields' }, filters: { type: 'json', description: 'Advanced filters array' }, joinOperator: { type: 'string', enum: ['and', 'or'], default: 'and' }, // 정렬 sort: { type: 'json', description: 'Sort configuration array' }, // 플래그 flags: { type: 'json', description: 'Feature flags array' }, }, // 사용 예시 examples: { basic: '/api/table/items/infinite?limit=50', withSearch: '/api/table/items/infinite?limit=50&search=steel', withFilters: '/api/table/items/infinite?limit=50&itemCode=ABC&steelType=carbon', withCursor: '/api/table/items/infinite?cursor=123&limit=50', withSort: '/api/table/items/infinite?limit=50&sort=[{"id":"itemName","desc":false}]', advanced: '/api/table/items/infinite?limit=50&search=test&filters=[{"id":"itemLevel","operator":"eq","value":"1"}]&joinOperator=and&sort=[{"id":"createdAt","desc":true}]' }, apiVersion: '1.0', documentation: '/docs/api/items/infinite', compatibility: { searchParamsCache: 'full', dataTable: 'full', advancedFilters: 'full', } }); }