[프로그래머스] Node기반 REST API 구현(10)

Lina Hongbi Ko·2024년 10월 15일
0

Programmers_BootCamp

목록 보기
35/76
post-thumbnail

2024년 10월 15일

✏️ conn.execute vs conn.query

  • 지난 시간에 이어서 쿼리들을 await로 순서대로 진행 시키게 하고, 결과값을 받아보자
  • 그런데 우리는 베이스를 풀(createPool)해 온게 아니라서 query()를 쓰지 못하고, execute()를 사용해야 한다.
    *참고사이트: https://sidorares.github.io/node-mysql2/docs
// OrderController.js

// const conn = require("../mariadb"); // db 모듈
const mariadb = require("mysql2/promise");
const { StatusCodes } = require("http-status-codes"); // status code 모듈

const order = async (req, res) => {
  const conn = await mariadb.createConnection({
    host: "127.0.0.1",
    user: "root",
    password: "root",
    database: "Bookshop",
    dateStrings: true,
  });

  const { items, delivery, totalQuantity, totalPrice, userId, firstBookTitle } = req.body;

  // (1) delivery에 Insert
  let sql = "INSERT INTO delivery (address, receiver, contact) VALUES (?, ?, ?)";
  let values = [delivery.address, delivery.receiver, delivery.contact];

  let [results] = await conn.execute(sql, values);
  let delivery_id = results.insertId;

  // (2) orders에 Insert
  sql = `INSERT INTO orders (book_title, total_quantity, 
  total_price, user_id, delivery_id) VALUES (?, ?, ?, ?, ?)`;
  values = [firstBookTitle, totalQuantity, totalPrice, userId, delivery_id];

  [results] = await conn.execute(sql, values);
  let order_id = results.insertId;

  // (3) orderedBook에 Insert
  sql = `INSERT INTO orderedBook (order_id, book_id, quantity) VALUES ?`;

  values = [];
  items.forEach((item) => {
    values.push([order_id, item.book_id, item.quantity]);
  });

  [results] = await conn.query(sql, [values]);
  // 이중배열을 넘겨줄땐 execute가 아닌 query를 써야함

  return res.status(StatusCodes.OK).json(results);
};

POSTMAN) POST + localhost:9999/orders +

{
    "items" : [
        {
            "book_id" : 3,
            "quantity" : 1
        },
        {
            "book_id" : 4,
            "quantity" : 1
        },
        {
            "book_id" : 8,
            "quantity" : 1
        }
    ],
    "delivery" : {
        "address" : "서울시 중구",
        "receiver" : "김영호",
        "contact" : "010-1111-1111"
    },
    "firstBookTitle" : "book1",
    "totalQuantity" : 3,
    "totalPrice" : 60000,
    "userId" : 1
}

✏️ 테이블 delete, truncate 차이

  • 데이터베이스 테이블 데이터 전체 delete하기
  • MySQL 데이터 삭제하는 방법
    1. DELETE
      • DELETE FROM 테이블명 (WEHRE 조건);
        • 조건이 없으면 모든 행 삭제됨 (테이블은 남아 있음)
        • 조건이 있으면 조건에 맞는 행만 삭제
    2. DROP
      • DROP TABLE 테이블명;
      • 테이블을 통째로 삭제
    3. TRUNCATE
      • TRUNCATE 테이블명;
      • 조건에 상관없이 모든 행이 삭제됨 (테이블은 남아 있음)
      • DELETE랑 기능이 같은데 왜 구분해서 써야 하나?
        - 똑같지 않음!
        *테이블을 지울때는 제약 조건을 잘 따져야함(FK를 들고 있는 애부터 삭제하는 것이 좋음)
        • 워크벤치 : DELETE FROM orderedBook;

          그리고 값을 insert하면 Id는 auto increment가 적용되었기 때문에 계속 숫자가 증가한 채로 이어진다.

        • 워크벤치 : TRUNCATE orderedBook;

        값을 insert하면 id가 초기화 된다. → auto increment를 초기화해줌 → 구분하는 이유!!

✏️ SET FOREIGN_KEY_CHECKS = 0;

  • 다른 데이터의 PK를 FK로 가져다 쓰는 경우 TRUNCATE가 안된다 (에러코드: 1701)

  • 어떻게 해결할까?

  • 왜 이런 에러가 발생하는 것인가 ? → orders 테이블의 PK를 orderedBook 테이블의 FK로 써서 제약조건을 확인하기 때문

  • 지금은 제약 조건 보지 말자 명령 (FK 없애지 말고)

    • SET FOREIGN_KEY_CHECKS = 0;
  • 그다음 TRUNCATE orders;

  • TRUNCATE delivery;

  • 이제 제약 조건 보자고 명령 (FK 체크 다시해주자
    • SET FOREIGN_KEY_CHECKS = 1;
    • 나중에 제약조건 봐야할 상황이 오니까 다시 체크해줘야함!

✏️ cartItemId Delete

  • 선택한 장바구니 상품 목록 조회에서 select한 cartItemId 들을 보내줄 것임(request) → 주문 상품 목록을 보여줌(id(장바구니 id), bookId, title, summary, quantity, price) (response) → 그리고 이 목록에서 장바구니 id를 주문하기를 할 때 얘를 이용할 수 있음
  • 주문을 완료하면 주문하려고 담은 cartItems 테이블의 도서들은 삭제 되어야함
    • DELETE FROM cartItems WHERE id IN (1, 2, 3);
// const conn = require("../mariadb"); // db 모듈
const mariadb = require("mysql2/promise");
const { StatusCodes } = require("http-status-codes"); // status code 모듈

const order = async (req, res) => {
  const conn = await mariadb.createConnection({
    host: "127.0.0.1",
    user: "root",
    password: "root",
    database: "Bookshop",
    dateStrings: true,
  });

  const { items, delivery, totalQuantity, totalPrice, userId, firstBookTitle } = req.body;
    
  let result = await deleteCartItems(conn);

  return res.status(StatusCodes.OK).json(result);
};

const deleteCartItems = async (conn) => {
  let sql = `DELETE FROM cartItems WHERE id IN (?)`;
  let values = [1, 2, 3];

  let result = await conn.query(sql, [values]); // 이중배열은 execute가 아닌 query로 받아야함
  return result;
};

POSTMAN) POST + localhost:9999/orders +

{
    "items" : [
        {   
            "book_id" : 3,
            "quantity" : 1
        },
        {
            "book_id" : 4,
            "quantity" : 1
        },
        {
            "book_id" : 8,
            "quantity" : 1
        }
    ],
    "delivery" : {
        "address" : "서울시 중구",
        "receiver" : "김영호",
        "contact" : "010-1111-1111"
    },
    "firstBookTitle" : "book1",
    "totalQuantity" : 3,
    "totalPrice" : 60000,
    "userId" : 1
}

✏️ 주문하기 마무리

  • 주문하기 API를 다시 수정하자

파란글씨의 items를 cartItems 테이블에서 bookId, quantity을 받아와서 select하고 그 결과 insert할 것임

// const conn = require("../mariadb"); // db 모듈
const mariadb = require("mysql2/promise");
const { StatusCodes } = require("http-status-codes"); // status code 모듈

const order = async (req, res) => {
  const conn = await mariadb.createConnection({
    host: "127.0.0.1",
    user: "root",
    password: "root",
    database: "Bookshop",
    dateStrings: true,
  });

  const { items, delivery, totalQuantity, totalPrice, userId, firstBookTitle } =
    req.body;

  //(1) delivery에 Insert
  let sql =
    "INSERT INTO delivery (address, receiver, contact) VALUES (?, ?, ?)";
  let values = [delivery.address, delivery.receiver, delivery.contact];

  let [results] = await conn.execute(sql, values);
  let delivery_id = results.insertId;

  // (2) orders에 Insert
  sql = `INSERT INTO orders (book_title, total_quantity, total_price, user_id, delivery_id) VALUES (?, ?, ?, ?, ?)`;
  values = [firstBookTitle, totalQuantity, totalPrice, userId, delivery_id];

  [results] = await conn.execute(sql, values);
  let order_id = results.insertId;

  // (2-1) items를 가지고, 장바구니에서 book_id, quantity 조회
  sql = `SELECT book_id, quantity FROM cartItems WHERE id IN (?)`;
  let [orderItems, fields] = await conn.query(sql, [items]); // [rows, fields]

  // (3) orderedBook에 Insert
  sql = `INSERT INTO orderedBook (order_id, book_id, quantity) VALUES ?`;

  values = [];
  orderItems.forEach((item) => {
    values.push([order_id, item.book_id, item.quantity]);
  });

  [results] = await conn.query(sql, [values]);
  // 이중배열을 넘겨줄땐 execute가 아닌 query를 써야함

  let result = await deleteCartItems(conn, items);

  return res.status(StatusCodes.OK).json(result);
};

const deleteCartItems = async (conn, items) => {
  let sql = `DELETE FROM cartItems WHERE id IN (?)`;

  let result = await conn.query(sql, [items]);
  return result;
};
// 이중배열을 넘겨줄땐 execute가 아닌 query를 써야함
// 그리고 배열을 넘겨줄땐 배열로 감싸서 넘겨야함

POSTMAN) POST + localhost:9999/orders +

{
    "items" : [1, 2, 3],
    "delivery" : {
        "address" : "서울시 중구",
        "receiver" : "김영호",
        "contact" : "010-1111-1111"
    },
    "firstBookTitle" : "book1",
    "totalQuantity" : 3,
    "totalPrice" : 60000,
    "userId" : 1
}

✏️ 주문 내역 조회

  • 쿼리문부터 생각해보자
  • SELECT orders.id, book_title, total_quantity, total_price, created_at, address, receiver, contact FROM orders LEFT JOIN delivery ON orders.delivery_id = delivery.id;

  • API 구현
// mariadb.js

// mysql 모듈 소환
const mariadb = require("mysql2");

// DB와 연결 통로 생성
const connection = mariadb.createConnection({
  host: "127.0.0.1",
  user: "root",
  password: "root",
  database: "Bookshop",
  dateStrings: true,
});

module.exports = connection;
// OrderController.js

const getOrders = async (req, res) => {
  const conn = await mariadb.createConnection({
    host: "127.0.0.1",
    user: "root",
    password: "root",
    database: "Bookshop",
    dateStrings: true,
  });

  let sql = `SELECT orders.id, book_title, total_quantity, total_price, 
  created_at, address, receiver, contact FROM orders LEFT JOIN delivery 
  ON orders.delivery_id = delivery.id;`;

  let [rows, fields] = await conn.query(sql);
  return res.status(StatusCodes.OK).json(rows);
};

POSTMAN) GET + localhost:9999/orders

✏️ 주문 상세 조회

// OrderController.js

const getOrderDetail = async (req, res) => {
  const { id } = req.params;
  const conn = await mariadb.createConnection({
    host: "127.0.0.1",
    user: "root",
    password: "root",
    database: "Bookshop",
    dateStrings: true,
  });

  let sql = `SELECT book_id, book_title, author, price, quantity FROM orderedBook LEFT JOIN books ON orderedBook.book_id = books.id WHERE order_id=?`;

  let [rows, field] = await conn.query(sql, id);
  return res.status(StatusCodes.OK).json(rows);
};

POSTMAN) GET + localhost:9999/orders/1

🍏🍎 오늘의 느낀점 : 이중 배열 사용할때 꼭 대괄호 넣는거 잊지 말기, 그리고 아직 이중 배열을 넣는 promise객체를 반환하는 쿼리는 나오지 않았으므로 query를 써야함(execute와 query와 관련된 오류 나오면 바꾸는 시도 해보고 참조해보기), async await 연습 많이 필요, truncate 쿼리쓸때는 항상 fk check = 0 만들고 하기.

profile
프론트엔드개발자가 되고 싶어서 열심히 땅굴 파는 자

0개의 댓글