2024-09-16 CH-3 개인과제 (아이템 시뮬레이터 구현) 도전기능 완료 3-3

MOON·2024년 9월 16일
0

내일배움캠프 과제

목록 보기
9/36

이젠 팀프로젝트 과제도 있기에 빠르게 도전기능을 완성해보았습니다. 리팩토링이 좀 덜 되어있지만
팀과제를 하기전에 도전기능을 경험해보면 좋을 거 같아 빠르게 연습할겸 해보았습니다.

캐릭터가 장착한 아이템 목록 조회 API

router.get('/equipments/:characterId', async (req, res, next) => {
  try {
    const { characterId } = await joiSchema.characterIdSchema().validateAsync(req.params);

    const character = await prisma.characters.findUnique({
      where: {
        characterId: characterId, // 어차피 현재 characterId는 고유하다
      },
    });
    // 캐릭터가 있는지 확인
    if (!character) return res.status(404).json({ message: '캐릭터가 존재하지 않습니다.' });

    const equipments = await prisma.equipments.findMany({
      where: {
        characterId: characterId,
      },
    });

    for (let i = 0; i < equipments.length; i++) {
      const item = await prisma.items.findFirst({
        select: { itemName: true },
        where: { itemCode: equipments[i].itemCode },
      });

      equipments[i].itemName = item.itemName;
    }

    return res.status(200).json({ equipments: equipments });
  } catch (err) {
    next(err);
  }
});

아이템 장착 API

router.post('/equipments/:characterId', authMiddleware, async (req, res, next) => {
  try {
    const { characterId } = await joiSchema.characterIdSchema().validateAsync(req.params);
    const { itemCode } = await joiSchema.itemCodeSchema().validateAsync(req.body);
    const userId = req.user.userId;

    const character = await prisma.characters.findUnique({
      where: {
        characterId: characterId, // 어차피 현재 characterId는 고유하다
      },
    });
    // 캐릭터가 있는지 확인
    if (!character) return res.status(404).json({ message: '캐릭터가 존재하지 않습니다.' });
    if (userId !== character.userId) return res.status(409).json({ message: '현재 계정의 캐릭터가 아닙니다.' });

    const isequipItem = await prisma.equipments.findFirst({
      where: {
        characterId: characterId,
        itemCode: itemCode,
      },
    });
    if (isequipItem) return res.status(409).json({ message: '이미 장착중인 아이템입니다.' });

    const isInventoryItem = await prisma.inventories.findFirst({
      where: {
        characterId: characterId,
        itemCode: itemCode,
      },
    });

    // 인벤토리 안에 장착할 아이템이 있는지
    if (!isInventoryItem) return res.status(404).json({ message: '인벤토리에 장착할 아이템이 존재하지 않습니다.' });

    const renewalcharacter = await prisma.$transaction(
      async (tx) => {
        await tx.equipments.create({
          data: {
            characterId: characterId,
            itemCode: itemCode,
          },
        });

        const itemInfo = await tx.items.findFirst({
          where: { itemCode: itemCode },
        });

        const inventoryItem = await tx.inventories.update({
          data: {
            count: isInventoryItem.count - 1, // 다음에는 한번 inventories컬럼에 isUse라는 사용여부 컬럼을 추가해서 해야겠다
          },
          where: {
            inventoryId: isInventoryItem.inventoryId,
          },
        });

        if (inventoryItem.count === 0) {
          await tx.inventories.delete({
            where: {
              inventoryId: isInventoryItem.inventoryId,
            },
          });
        }

        const renewalcharacter = await tx.characters.update({
          where: { characterId: characterId },
          data: {
            health: character.health + itemInfo.health,
            power: character.power + itemInfo.power,
          },
          select: {
            characterName: true,
            health: true,
            power: true,
          },
        });
        return renewalcharacter;
      },
      {
        isolationLevel: Prisma.TransactionIsolationLevel.ReadCommitted, // DB가 커밋된 후
      },
    );

    return res.status(200).json({ message: renewalcharacter });
  } catch (err) {
    next(err);
  }
});

아이템 탈착 API

router.delete('/equipments/:characterId', authMiddleware, async (req, res, next) => {
  try {
    const { characterId } = await joiSchema.characterIdSchema().validateAsync(req.params);
    const { itemCode } = await joiSchema.itemCodeSchema().validateAsync(req.body);
    const userId = req.user.userId;

    const character = await prisma.characters.findUnique({
      where: {
        characterId: characterId, // 어차피 현재 characterId는 고유하다
      },
    });
    // 캐릭터가 있는지 확인
    if (!character) return res.status(404).json({ message: '캐릭터가 존재하지 않습니다.' });
    if (userId !== character.userId) return res.status(409).json({ message: '현재 계정의 캐릭터가 아닙니다.' });

    // 해당 인벤토리에 탈착할려는 아이템이 있는지 체크하기 위한 변수
    const isInventoryItem = await prisma.inventories.findFirst({
      where: {
        characterId: characterId,
        itemCode: itemCode,
      },
    });

    const isequipItem = await prisma.equipments.findFirst({
      where: {
        characterId: characterId,
        itemCode: itemCode,
      },
    });
    if (!isequipItem) return res.status(409).json({ message: '장착 중인 아이템이 아닙니다.' });

    const renewalcharacter = await prisma.$transaction(
      async (tx) => {
        // 장비DB에서 삭제
        await tx.equipments.delete({
          where: {
            equipmentId: isequipItem.equipmentId,
          },
        });

        // 인벤토리에 갯수 수정 및 추가
        if (!isInventoryItem) {
          await tx.inventories.create({
            data: {
              characterId: characterId,
              itemCode: itemCode,
              count: 1,
            },
          });
        } else {
          await tx.inventories.update({
            data: {
              count: isInventoryItem.count + 1, // 다음에는 한번 inventories컬럼에 isUse라는 사용여부 컬럼을 추가해서 해야겠다
            },
            where: {
              inventoryId: isInventoryItem.inventoryId,
            },
          });
        }

        const itemInfo = await tx.items.findFirst({
          where: { itemCode: itemCode },
        });

        const renewalcharacter = await tx.characters.update({
          where: { characterId: characterId },
          data: {
            health: character.health - itemInfo.health,
            power: character.power - itemInfo.power,
          },
          select: {
            characterName: true,
            health: true,
            power: true,
          },
        });

        return renewalcharacter;
      },
      {
        isolationLevel: Prisma.TransactionIsolationLevel.ReadCommitted, // DB가 커밋된 후
      },
    );

    return res.status(200).json({ message: renewalcharacter });
  } catch (err) {
    next(err);
  }
});

게임 머니를 버는 API

router.get('/game/:characterId', authMiddleware, async (req, res, next) => {
  try {
    const { characterId } = await joiSchema.characterIdSchema().validateAsync(req.params);
    const userId = req.user.userId;
    const moneyToBuy = 1000;

    const character = await prisma.characters.findUnique({
      where: { characterId: characterId },
    });
    // 캐릭터가 있는지 확인
    if (!character) return res.status(404).json({ message: '캐릭터가 존재하지 않습니다.' });
    if (userId !== character.userId) return res.status(409).json({ message: '현재 계정의 캐릭터가 아닙니다.' });

    const renewalcharacter = await prisma.characters.update({
      data: {
        money: character.money + moneyToBuy,
      },
      where: { characterId: characterId },
    });

    return res.status(200).json({
      message: '돈을 벌었었습니다..',
      money: renewalcharacter.money,
    });
  } catch (err) {
    next(err);
  }
});

다소 리펙토링이 필요해 보이지만 일단 구현에 중점을 두면서 작성하였습니다.
도전기능을 하면서 여러 구조들도 생각해 보면서 테이블 모델링도 좀 더 신경써서 필요한 컬럼도 생각해 봐야겠더라구요. 그래도 여러가지 생각하면서 좋은 경험을 해보았네요. 굿!!

그리고 이젠 팀과제에 집중해서 할려고 합니다. 다음은 팀과제에서 뵙겠습니다. 그럼 이만...

오늘도 화이팅이고 내일도 화이팅!

profile
안녕하세요

0개의 댓글