5 분 소요

내가 코드 작업한 곳

이번 주 작업

gatcha 시스템

원시적인 형태의 가챠 시스템을 구현했다.
캐릭터 리스트 가운데 가운데 하나를 랜덤하게 얻을 수 있는 구조로 작업했다.
필요하다면 나중에 gatcha의 확률 테이블을 별도로 만들어서 관리해도 되겠다.

router.post('/gatcha',authMiddleware, async (req, res, next) => {
    try {
        //const players = await prisma.users.findMany({});
        //유저 정보를 전부 받아온 다음
        //user의 id를 parse하자.
        const user = req.user;
        let [playerName, cash] = await prisma.$transaction(async (tx) => {
            let playerList = await tx.players.findMany({

            });

            let random_count = Math.floor(Math.random() * playerList.length);


            let userteam = await tx.userTeams.create({
                data: {
                    players : {
                        connect : {
                            id : playerList[random_count].id
                        }
                    },
                    user : {
                        connect : {
                            id : user.id
                        }
                    },
                },

            })

            const updatedUser = await tx.userAccount.update({
                where : {
                    userId : user.id
                },
                data: {
                    cash: {
                        decrement: gatchaPay
                    }
                }
            })

            if(updatedUser.cash < 0)
            {
                return res.status(404).json({ Message: ` No Money ` })
            }

            return [playerList[random_count], updatedUser.cash]
        })
        return res.status(200).json({ Message: ` ${playerName.playerName} 을(를) 뽑았습니다. 잔액 ${cash} ` })
    }
    catch (err) {
        next(err);
    }


})

squad 시스템

유저 한 명당 1개의 스쿼드를 가질 수 있다는 조건 하에 squad를 작성했다.
처음에는 body에서 각각의 인덱스를 하나씩 입력 하는 방식으로 작업했으나, 어차피 인덱스만 보내면 된다는 지적을 받고 리스트 형태로 보내게 되었다.
작업 도중에 table이 한 번 바뀌었는데, 기존엔 squad라는 테이블을 별도로 만들어 관리했으나 나중에 다른 테이블과의 연결을 위해서 squad 테이블을 지우고 대신 teams 테이블에 isspuad 변수를 넣었다.

router.post('/squads', authMiddleware, async (req,res,next) => {
    try{
        const {squadList} = req.body;
        const user = req.user;
        
        for(let i of squadList) {
            if(typeof i != 'number') {
                throw new Error("입력 값이 잘못되었습니다.");
            }
        }

        //teams 내에 현재 로그인한 유저의 것이며 isSquad가 참인 것을 모두 조회한다.
        //그것들을 모두 squad 해제시킨다.
        //그 다음 지정 받은 index를 베이스로 값을 가져오도록 하자.
        const squadTransaction = await prisma.$transaction(async (tx) => {
            //먼저 teams 내의 squad 에서 user의 팀을 해제한다.
            const updatedTeam = await tx.userTeams.updateMany({
                where : {
                    AND : {
                        userId : user.id,
                        isSquad : true,
                    },
                },
                data : {
                    isSquad : false,
                },
            });

            //다음 입력 받은 인덱스를 받아 팀을 만든다.
            const updatingTeam = await tx.userTeams.updateMany({
                where : {
                    AND : {
                        userId : user.id,
                        id : {
                            in : squadList,
                        },
                    },
                },
                data : {
                    isSquad : true,
                },
            });

            const check = await tx.userTeams.findMany({
                where : {
                    userId : user.id,
                    AND : {
                        isSquad : true,
                    },
                },
            });

            if(!updatingTeam) {
                throw new Error("업데이트가 되지 않았습니다.")
            }

            if(check.length !== 3) {
                throw new Error("숫자가 다릅니다.")
            }
        });

        return res.status(200).json({message : "스쿼드 편성 완료!"});
        
    } catch(err){
        if(err === "invaildIndex") {
            res.status(404).json({message : "확실치 않은 인덱스!"});
        }
        else {
            next(err);
        }
    }
});

이적 시장 테이블 관련

기본 과제가 해결이 된 뒤 추가적으로 이적 시장을 추가하여 작업했다.
이적 시장은 등록(jwt 인증 필요), 구매(인증 필요), 조회(전체/캐릭터), 등록 취소(인증 필요)가 있다.
처음엔 userteams에서 데이터를 삭제한 뒤 이 안에 넣자는 방안이 제시되었으나 삭제를 통한 데이터 훼손 위험이 있으므로 user의 id 값만 바꾸는 방식으로 바꾸었다.

등록

router.post('/transfermarket', authMiddleware, async (req, res, next) => {
    try {
        const { userTeamId, price } = req.body;
        const user = req.user;

        const marketPlace = await prisma.$transaction(async (tx) => {
            //삭제할 데이터가 있는지 확인 먼저 하자.
            const deletedTeams = await tx.userTeams.findUnique({
                where: {
                    id: userTeamId
                },
            });

            if (!deletedTeams) {
                throw new Error("해당 캐릭터가 존재하지 않습니다.");
            }

            if (deletedTeams.isSquad) {
                throw new Error("이미 팀 편성된 캐릭터입니다.")
            }

            if (deletedTeams.userId !== user.id) {
                throw new Error("다른 유저의 캐릭터입니다.")
            }

            const market = await tx.transferMarket.create({
                data: {
                    userTeamsId: deletedTeams.id,
                    price: price,
                },
            });

            return market;
        });

        return res.status(201).json({ data: marketPlace });
    } catch (err) {
        switch (err.message) {
            case "해당 캐릭터가 존재하지 않습니다.":
                return res.status(404).json({ error: "해당 캐릭터가 존재하지 않습니다." })
                break;
            case "이미 팀 편성된 캐릭터입니다.":
                return res.status(404).json({ error: "이미 팀 편성된 캐릭터입니다." })
                break;
            case "다른 유저의 캐릭터입니다.":
                return res.status(404).json({ error: "다른 유저의 캐릭터입니다." })
                break;
            default:
                next(err);
                break;
        }

    }
});

구매

router.post('/transfermarket/:marketId', authMiddleware, async (req, res, next) => {
    try {
        const { marketId } = req.params;
        const user = req.user;

        const purchased = await prisma.$transaction(async (tx) => {
            //돈이 있는지 검수한다.
            const userAccount = await tx.userAccount.findFirst({
                where: {
                    userId: user.id
                }
            })

            //먼저 경매장에서 제거한다.
            const deletedfromMarket = await tx.transferMarket.delete({
                where: {
                    id: parseInt(marketId, 10),
                },
            });

            if (userAccount.cash < deletedfromMarket.price) {
                throw new Error("돈이 부족합니다.");
            }

            if (!deleted) {
                throw new Error("범위 외 접근입니다.");
            }

            //판매자는 돈을 벌고
            await tx.userAccount.update({
                where: {
                    userId: deletedfromMarket.userId
                },
                data: {
                    cash: {
                        increment: deletedfromMarket.price,
                    },
                },
            });

            //구매자와 판매자의 정보를 변경하면 된다.
            await tx.userTeams.update({
                where: {
                    id: deletedfromMarket.userTeamsId
                },
                data: {
                    userId: user.id
                }
            })


            //구매한 사람의 돈은 줄어든다.
            await tx.userAccount.update({
                where: {
                    userId: user.id
                },
                data: {
                    cash: {
                        decrement: deletedfromMarket.price
                    },
                },
            });


            return inputUserTeams;
        });

        return res.status(201).json({ data: purchased });
    } catch (err) {
        switch (err.message) {
            case "돈이 부족합니다.":
                return res.status(404).json({ error: "돈이 부족합니다." });
                break;
            case "범위 외 접근입니다.":
                return res.status(404).json({ error: "범위 외 접근입니다." });
                break
            default:
                next(err);
                break;
        }

    }
});

조회

router.get('/transfermarket', async (req, res, next) => {
    try {
        //유저 팀즈에서 마켓에 등록된 것들을 모두 가져온다.
        const marketList = await prisma.userTeams.findMany({
            where: {
                TransferMarket: {
                    some: {}
                }
            },
            include: {
                TransferMarket: {
                    select : {
                        price : true
                    }
                }
            }
        });

        return res.status(201).json({ data: marketList });
    } catch (err) {
        next(err);
    }
});

등록 취소

router.delete('/transfermarket', authMiddleware, async (req, res, next) => {
    try {
        const { transferMarketId } = req.body;
        const user = req.user;

        const cancelMarketAndPushTeams = await prisma.$transaction(async (tx) => {
            //먼저 마켓에서 꺼내오자.
            const cancelMarket = await tx.transferMarket.delete({
                where: {
                    id: transferMarketId,
                },
            });

            if (!cancelMarket) {
                throw new Error("잘못된 접근입니다.");
            }

            const currentUserTeam = await tx.userTeams.findUnique({
                where: {
                    id: cancelMarket.userTeamsId
                }
            })

            if (currentUserTeam.userId !== user.id) {
                throw new Error("다른 유저의 것입니다.");
            }




            //teams를 지우지 않으면 되니까 아예 별도의 로직은 필요 없다.

            return currentUserTeam;
        });
        //취소된 것은 그냥 바로 teams에 들어오면 되는 거 아닌가.
        return res.status(201).json({ data: cancelMarketAndPushTeams });
    } catch (err) {
        switch (err.message) {
            case "잘못된 접근입니다.":
                return res.status(404).json({ error: "잘못된 접근입니다." });
                break;
            case "다른 유저의 것입니다.":
                return res.status(404).json({ error: "다른 유저의 것입니다." });
                break
            default:
                next(err);

        }
    }
});

화요일 과제

select book_id, count(*), avg(day(return_date) - day(due_date)) from book_rental
where due_date < return_date
group by book_id
order by book_id;