웹 풀사이클 데브코스 TIL 9주차 DAY 5

갱갱·2024년 1월 22일
0

데브코스 TIL

목록 보기
24/24
post-thumbnail

프로그래머스 데브코스, 국비지원교육, 코딩부트캠프

🚩 프로그래머스 데브코스 웹 풀사이클 과정 9주차 DAY 5


주문하기 관련 기능을 구현했다. 관련 데이터베이스 테이블도 세 개나 연관 관계인데다 post로 보내는 방식도 이래저래 꼬여 있어서 SQL문을 짜는 걸 고민을 많이 했다. 오류도 얼마나 많이 났던지... 그래도 SQL문을 어떻게 만들어야 하는지 고민하는 과정에서 실력이 좀 괜찮아진 것 같다. 마침 과거의 내가 SQL 시험을 신청하는 바람에 공부를 해야했는데...ㅋ

💡Express로 주문하기 구현하기


먼저 주문하기 기능과 직접적으로 관련이 있는 테이블은 delivery, orderedBook, orders다. 테이블명에서부터 알 수 있지만 orderedBook은 주문한 책을 저장하는 테이블이고 delivery는 배송지 관련 데이터를 저장하는 테이블, orders는 기타 주문 관련 내용을 저장하는 테이블이다.
즉 주문을 하면 세 테이블에 모두 저장이 되도록 해야한다.

const order = async (req, res) => {
    const connection = await conn.getConnection();
    const { items, delivery, totalQuantity, totalPrice, userId, firstBookTitle } = camelcaseKeys(req.body);
    const sqlInsertDelivery = `insert into delivery (address, receiver, contact) values (?, ?, ?)`;
    const valuesDelivery = [delivery.address, delivery.receiver, delivery.contact];
    const sqlInsertOrder = `insert into orders (book_title, total_quantity, total_price, user_id, delivery_id) values (?, ?, ?, ?, ?)`;
    const sqlInsertOrderedBook = `insert into orderedBook (order_id, book_id, quantity) values (?, ?, ?)`;

    try {
        const [rowsDelivery] = await connection.query(sqlInsertDelivery, valuesDelivery);
        const deliveryId = rowsDelivery.insertId;

        const valuesOrder = [firstBookTitle, totalQuantity, totalPrice, userId, deliveryId];
        const [rowsOrder] = await connection.query(sqlInsertOrder, valuesOrder);
        const orderId = rowsOrder.insertId;

        for (const item of items) {
            const valuesOrderItem = [orderId, item.book_id, item.quantity];
            await connection.query(sqlInsertOrderedBook, valuesOrderItem);
        }

        return res.status(StatusCodes.OK).json({
            message: '주문이 성공적으로 처리되었습니다.',
        });
    } catch (err) {
        console.log(err);
        return res.status(StatusCodes.INTERNAL_SERVER_ERROR).json({
            message: '주문 중 에러가 발생하였습니다.',
        });
    } finally {
        connection.release();
    }
};

POST 요청 시 body 값은 위 사진과 같다.

  1. 먼저 delivery 테이블에 배송지 관련 내용을 저장한다.
  2. 배송지 저장 후 order 테이블에 주문 관련 데이터를 저장한다.
  3. 이후 item 객체 내 데이터들을 for문으로 돌려가면서 하나씩 저장해준다.

일단은 이렇게 구현을 하긴 했는데... 위 코드에는 문제가 좀 있다.
우선 delivery, order, orderedBook 테이블 각각 insert를 하기 때문에 예를 들어 order 시 문제가 생기면 delivery 테이블에만 데이터가 들어가고 이후 테이블에는 데이터가 입력이 안 된다. 이와 비슷한 문제로 현재 items 내의 주문 도서들이 for문으로 들어가고 있는데 중간에 에러가 발생한다면 도서가 몇 개만 저장이 되고 그대로 종료되게 된다. 이 경우에는 만약 에러가 발생했을 때 아예 처음으로 돌아가 데이터가 입력이 되지 않도록 하는 게 좋을 것 같다고 멘토님이 조언해주셨다.

💡 Express로 주문 내역 전체 조회 구현하기


const getOrders = async (req, res) => {
    const connection = await conn.getConnection();
    const { userId } = camelcaseKeys(req.body);
    const sql = `select * from orders where user_id=?`;
    const values = [userId];

    try {
        const [rows] = await connection.query(sql, values);

        if (rows.length === 0) {
            return res.status(StatusCodes.NOT_FOUND).json({
                message: '주문 내역이 없습니다.',
            });
        }

        return res.status(StatusCodes.OK).json(rows);
    } catch (err) {
        console.log(err);
        return res.status(StatusCodes.INTERNAL_SERVER_ERROR).json({
            message: '주문 내역 조회 중 에러가 발생하였습니다.',
        });
    } finally {
        connection.release();
    }
};

유저의 주문 내역을 조회하는 코드다. 그냥 데이터베이스에서 select만 제대로 해주면 된다. 근데... 이거 쓰면서 생각한 건데 전체 조회 시 주문 내역이 없는게 에러가 될 수 없는데 난 왜 에러로 만든 거냐?😕 그냥 빈 배열만 반환하면 되잖아...

💡 Express로 주문 내역 상세 조회 구현하기


const getOrderDetail = async (req, res) => {
    const connection = await conn.getConnection();
    const { userId } = camelcaseKeys(req.body);
    const orderId = req.params.id;
    const sql = `select * from orders where id=? and user_id=?`;
    const values = [orderId, userId];

    try {
        const [rows] = await connection.query(sql, values);

        if (rows.length === 0) {
            return res.status(StatusCodes.NOT_FOUND).json({
                message: '주문 내역이 없습니다.',
            });
        }

        return res.status(StatusCodes.OK).json(rows);
    } catch (err) {
        console.log(err);
        return res.status(StatusCodes.INTERNAL_SERVER_ERROR).json({
            message: '주문 내역 조회 중 에러가 발생하였습니다.',
        });
    } finally {
        connection.release();
    }
};

이것도 위 코드와 비슷하다. 그냥 하나의 주문 내역만 자세히 보여주면 끝이다.

💡Express로 주문 내역 삭제 구현하기


const deleteOrder = async (req, res) => {
    const connection = await conn.getConnection();
    const orderId = req.params.id;
    const sqlSelectOrder = `select * from orders where id=?`;
    const sqlDeleteOrderedBook = `delete from orderedBook where order_id=?`;
    const sqlDeleteOrder = `delete from orders where id=?`;
    const sqlDeleteDelivery = `delete from delivery where id=?`;

    try {
        const [rowsOrder] = await connection.query(sqlSelectOrder, orderId);
        if (rowsOrder.length === 0) {
            return res.status(StatusCodes.NOT_FOUND).json({
                message: '주문 내역이 존재하지 않습니다.',
            });
        }

        await connection.query(sqlDeleteOrderedBook, orderId);

        const deliveryId = rowsOrder[0].delivery_id;

        await connection.query(sqlDeleteOrder, orderId);
        await connection.query(sqlDeleteDelivery, deliveryId);

        return res.status(StatusCodes.OK).json({
            message: '주문이 성공적으로 삭제되었습니다.',
        });
    } catch (err) {
        console.log(err);
        return res.status(StatusCodes.INTERNAL_SERVER_ERROR).json({
            message: '주문 삭제 중 에러가 발생하였습니다.',
        });
    } finally {
        connection.release();
    }
};

먼저 주문 내역이 존재하는지 확인하고 차례대로 관련 데이터베이스를 모두 삭제해준다. 근데 이것도 중간에 에러가 발생하면 하나 혹은 두 개 테이블에서만 데이터가 삭제될 수 있기 때문에 좀 더 방법을 고민해봐야 할 것 같다.

profile
괜찮은 개발자가 되어 보자

0개의 댓글