diff options
Diffstat (limited to 'lib/items-ship/service.ts')
| -rw-r--r-- | lib/items-ship/service.ts | 416 |
1 files changed, 0 insertions, 416 deletions
diff --git a/lib/items-ship/service.ts b/lib/items-ship/service.ts deleted file mode 100644 index 37b623c1..00000000 --- a/lib/items-ship/service.ts +++ /dev/null @@ -1,416 +0,0 @@ -// src/lib/items-ship/service.ts
-"use server"; // Next.js 서버 액션에서 직접 import하려면 (선택)
-
-import { revalidateTag, unstable_noStore } from "next/cache";
-import db from "@/db/db";
-
-import { filterColumns } from "@/lib/filter-columns";
-import { unstable_cache } from "@/lib/unstable-cache";
-import { getErrorMessage } from "@/lib/handle-error";
-
-import { asc, desc, ilike, and, or, eq, count, inArray, sql } from "drizzle-orm";
-import { GetItemsSchema, UpdateItemSchema, ShipbuildingItemCreateData, TypedItemCreateData } from "./validations";
-import { Item, items, itemShipbuilding } from "@/db/schema/items";
-import { deleteItemById, deleteItemsByIds, findAllItems, insertItem, updateItem } from "./repository";
-
-/* -----------------------------------------------------
- 1) 조회 관련
------------------------------------------------------ */
-
-/**
- * 복잡한 조건으로 Item 목록을 조회 (+ pagination) 하고,
- * 총 개수에 따라 pageCount를 계산해서 리턴.
- * Next.js의 unstable_cache를 사용해 일정 시간 캐시.
- */
-export async function getShipbuildingItems(input: GetItemsSchema) {
- return unstable_cache(
- async () => {
- try {
- const offset = (input.page - 1) * input.perPage;
-
- // advancedTable 모드면 filterColumns()로 where 절 구성
- const advancedWhere = filterColumns({
- table: items,
- filters: input.filters,
- joinOperator: input.joinOperator,
- });
-
- let globalWhere;
- if (input.search) {
- const s = `%${input.search}%`;
- globalWhere = or(
- ilike(items.itemCode, s),
- ilike(items.itemName, s),
- ilike(items.description, s)
- );
- }
-
- const finalWhere = and(
- advancedWhere,
- globalWhere
- );
-
- const where = finalWhere;
-
- const orderBy =
- input.sort.length > 0
- ? input.sort.map((item) =>
- item.desc ? desc(items[item.id]) : asc(items[item.id])
- )
- : [asc(items.createdAt)];
-
- // 조선 아이템 테이블과 기본 아이템 테이블 조인하여 조회
- const result = await db.select({
- id: itemShipbuilding.id,
- itemId: itemShipbuilding.itemId,
- workType: itemShipbuilding.workType,
- shipTypes: itemShipbuilding.shipTypes,
- itemCode: items.itemCode,
- itemName: items.itemName,
- description: items.description,
- createdAt: items.createdAt,
- updatedAt: items.updatedAt,
- })
- .from(itemShipbuilding)
- .innerJoin(items, eq(itemShipbuilding.itemId, items.id))
- .where(where)
- .orderBy(...orderBy)
- .offset(offset)
- .limit(input.perPage);
-
- // 전체 데이터 개수 조회
- const [{ count: total }] = await db.select({
- count: count()
- })
- .from(itemShipbuilding)
- .innerJoin(items, eq(itemShipbuilding.itemId, items.id))
- .where(where);
-
- const pageCount = Math.ceil(Number(total) / input.perPage);
-
- return { data: result, pageCount };
- } catch (err) {
- console.error("Error fetching shipbuilding items:", err);
- return { data: [], pageCount: 0 };
- }
- },
- [JSON.stringify(input)],
- {
- revalidate: 3600,
- tags: ["items"],
- }
- )();
-}
-
-/* -----------------------------------------------------
- 2) 생성(Create)
------------------------------------------------------ */
-
-/**
- * Item 생성 - 아이템 타입에 따라 해당 테이블에 데이터 삽입
- */
-export async function createShipbuildingItem(input: TypedItemCreateData) {
- unstable_noStore()
-
- try {
- if (!input.itemCode || !input.itemName) {
- return {
- success: false,
- message: "아이템 코드와 아이템 명은 필수입니다",
- data: null,
- error: "필수 필드 누락"
- }
- }
-
- let result: unknown[] = []
-
- result = await db.transaction(async (tx) => {
- const existingItem = await tx.query.items.findFirst({
- where: eq(items.itemCode, input.itemCode),
- })
-
- let itemId: number
- let itemResult
-
- if (existingItem) {
- itemResult = await updateItem(tx, existingItem.id, {
- itemName: input.itemName,
- description: input.description,
- })
- itemId = existingItem.id
- } else {
- itemResult = await insertItem(tx, {
- itemCode: input.itemCode,
- itemName: input.itemName,
- description: input.description,
- })
- itemId = itemResult[0].id
- }
-
- const shipData = input as ShipbuildingItemCreateData;
- const typeResult = await tx.insert(itemShipbuilding).values({
- itemId: itemId,
- workType: shipData.workType ? (shipData.workType as '기장' | '전장' | '선실' | '배관' | '철의') : '기장',
- shipTypes: shipData.shipTypes || ''
- }).returning();
-
- return [...itemResult, ...typeResult]
- })
-
- revalidateTag("items")
-
- return {
- success: true,
- data: result[0] || null,
- error: null
- }
- } catch (err) {
- console.error("아이템 생성/업데이트 오류:", err)
-
- if (err instanceof Error && err.message.includes("unique constraint")) {
- return {
- success: false,
- message: "이미 존재하는 아이템 코드입니다",
- data: null,
- error: "중복 키 오류"
- }
- }
-
- return {
- success: false,
- message: getErrorMessage(err),
- data: null,
- error: getErrorMessage(err)
- }
- }
-}
-
-/**
- * Excel import를 위한 조선 아이템 생성 함수
- * 하나의 아이템 코드에 대해 여러 선종을 처리 (1:N 관계)
- */
-export async function createShipbuildingImportItem(input: {
- itemCode: string;
- itemName: string;
- workType: '기장' | '전장' | '선실' | '배관' | '철의';
- description?: string | null;
- shipTypes: Record<string, boolean>;
-}) {
- unstable_noStore();
-
- try {
-
- if (!input.itemCode || !input.itemName) {
- return {
- success: false,
- message: "아이템 코드와 아이템 명은 필수입니다",
- data: null,
- error: "필수 필드 누락"
- }
- }
- let results: any[] = []
- results = await db.transaction(async (tx) => {
- // 1. itemCode 정규화해서 직접 쿼리
- const existRows = await tx.select().from(items)
- .where(eq(items.itemCode, input.itemCode));
- const existingItem = existRows[0];
-
- console.log('DB에서 직접 조회한 기존 아이템:', existingItem);
-
- let itemId: number;
-
- if (existingItem) {
- // 이미 있으면 업데이트
- await updateItem(tx, existingItem.id, {
- itemName: input.itemName,
- description: input.description,
- });
- itemId = existingItem.id;
- console.log('기존 아이템 업데이트, id:', itemId);
- } else {
- // 없으면 새로 생성
- // 현재 가장 큰 ID 값 가져오기
- const maxIdResult = await tx.select({ maxId: sql`MAX(id)` }).from(items);
- const maxId = maxIdResult[0]?.maxId || 0;
- const newId = Number(maxId) + 1;
- console.log('새 아이템 생성을 위한 ID 계산:', { maxId, newId });
-
- // 새 ID로 아이템 생성
- const insertResult = await tx.insert(items).values({
- id: newId,
- itemCode: input.itemCode,
- itemName: input.itemName,
- description: input.description,
- }).returning();
-
- itemId = insertResult[0].id;
- console.log('새 아이템 생성 완료, id:', itemId);
- }
-
- const createdItems = [];
- for (const shipType of Object.keys(input.shipTypes)) {
- // 그대로 선종명 string으로 저장
- const existShip = await tx.select().from(itemShipbuilding)
- .where(
- and(
- eq(itemShipbuilding.itemId, itemId),
- eq(itemShipbuilding.shipTypes, shipType)
- )
- );
- if (!existShip[0]) {
- const shipbuildingResult = await tx.insert(itemShipbuilding).values({
- itemId: itemId,
- workType: input.workType,
- shipTypes: shipType
- }).returning();
- createdItems.push({
- ...shipbuildingResult[0]
- });
- console.log('조선아이템 생성:', shipType, shipbuildingResult[0]);
- } else {
- console.log('이미 존재하는 조선아이템:', shipType);
- }
- }
- return createdItems;
- });
-
- revalidateTag("items");
-
- return {
- success: true,
- data: results,
- error: null
- }
- } catch (err) {
- // DB에 실제로 존재하는 itemCode 목록도 함께 출력
- const allCodes = await db.select({ code: items.itemCode }).from(items);
- console.error("아이템 import 오류:", err);
- console.error("DB에 존재하는 모든 itemCode:", allCodes.map(x => x.code));
- return {
- success: false,
- message: getErrorMessage(err),
- data: null,
- error: getErrorMessage(err)
- }
- }
-}
-
-/* -----------------------------------------------------
- 3) 업데이트
------------------------------------------------------ */
-
-// 업데이트 타입 정의 인터페이스
-interface UpdateShipbuildingItemInput extends UpdateItemSchema {
- id: number;
- workType?: string;
- shipTypes?: string;
- itemCode?: string;
- itemName?: string;
- description?: string;
-}
-
-/** 단건 업데이트 */
-export async function modifyShipbuildingItem(input: UpdateShipbuildingItemInput) {
- unstable_noStore();
- try {
- await db.transaction(async (tx) => {
- // 기본 아이템 테이블 업데이트
- const [item] = await updateItem(tx, input.id, {
- itemCode: input.itemCode,
- itemName: input.itemName,
- description: input.description,
- });
-
- // 조선 아이템 테이블 업데이트
- if (input.workType || input.shipTypes) {
- await tx.update(itemShipbuilding)
- .set({
- workType: input.workType as '기장' | '전장' | '선실' | '배관' | '철의',
- shipTypes: input.shipTypes
- })
- .where(eq(itemShipbuilding.itemId, item.id));
- }
-
- return item;
- });
-
- revalidateTag("items");
- return { data: null, error: null };
- } catch (err) {
- return { data: null, error: getErrorMessage(err) };
- }
-}
-
-/* -----------------------------------------------------
- 4) 삭제
------------------------------------------------------ */
-
-// 삭제 타입 정의 인터페이스
-interface DeleteItemInput {
- id: number;
-}
-
-interface DeleteItemsInput {
- ids: number[];
-}
-
-/** 단건 삭제 */
-export async function removeShipbuildingItem(input: DeleteItemInput) {
- unstable_noStore();
- try {
- await db.transaction(async (tx) => {
- const item = await tx.query.items.findFirst({
- where: eq(items.id, input.id),
- });
-
- if (!item) {
- throw new Error("아이템을 찾을 수 없습니다.");
- }
-
- // 조선 아이템 테이블에서 먼저 삭제
- await tx.delete(itemShipbuilding)
- .where(eq(itemShipbuilding.itemId, input.id));
-
- // 기본 아이템 테이블에서 삭제
- await deleteItemById(tx, input.id);
- });
-
- revalidateTag("items");
-
- return { data: null, error: null };
- } catch (err) {
- return { data: null, error: getErrorMessage(err) };
- }
-}
-
-/** 복수 삭제 */
-export async function removeShipbuildingItems(input: DeleteItemsInput) {
- unstable_noStore();
- try {
- await db.transaction(async (tx) => {
- if (input.ids.length > 0) {
- // 조선 아이템 테이블에서 먼저 삭제
- await tx.delete(itemShipbuilding)
- .where(inArray(itemShipbuilding.itemId, input.ids));
-
- // 기본 아이템 테이블에서 삭제
- await deleteItemsByIds(tx, input.ids);
- }
- });
-
- revalidateTag("items");
-
- return { data: null, error: null, success: true, message: "아이템이 성공적으로 삭제되었습니다." };
- } catch (err) {
- return { data: null, error: getErrorMessage(err), success: false, message: "아이템 삭제 중 오류가 발생했습니다." };
- }
-}
-
-export async function getAllShipbuildingItems(): Promise<Item[]> {
- try {
- return await findAllItems();
- } catch (error) {
- console.error("Failed to get items:", error);
- throw new Error("Failed to get items");
- }
-}
|
