
๐ฏ ์๋ธ ์ฟผ๋ฆฌ๋ฅผ ํตํด ํ ์ด๋ธ์ ์ปฌ๋ผ์ ์ถ๊ฐํฉ๋๋ค.
books ํ
์ด๋ธ SELECT ์์ ์นผ๋ผ์ผ๋ก ๋๊ฒจ์ค ๋ id ์ด๋ฆ์ด ์ค๋ณต๋์ด category_id๋ก ์ด๋ฆ์ ๋ณ๊ฒฝํด์ฃผ์์ต๋๋ค.
category_id integer [primary key]
category_name varchar
likes๋ likes ํ
์ด๋ธ์์ ๊ฐ์ ธ์ ์นผ๋ผ์ผ๋ก ์ถ๊ฐํ ๊ฒ์ด๊ธฐ ๋๋ฌธ์ ์ญ์ ํ์์ต๋๋ค.
Table books {
id integer [primary key]
title varchar
img integer
category_id integer
form varchar
isbn varchar
summary text
detail text
author varchar
pages integer
contents text
price integer
pub_date date
}
์กฐ๊ฑด์ ํด๋นํ๋ ํ์ ๊ฐ์๋ฅผ ๋ฐํํฉ๋๋ค.
SELECT COUNT(*) FROM ํ
์ด๋ธ๋ช
WHERE ์นผ๋ผ1์ด๋ฆ = ์นผ๋ผ2์ด๋ฆ
์กฐ๊ฑด์ ๋ง์กฑํ๋ ํ์ด ์กด์ฌํ๋ฉด 1 ์๋๋ฉด 0์ ๋ฐํํฉ๋๋ค.
SELECT EXISTS (SELECT 1 FROM ํ
์ด๋ธ๋ช
WHERE ์นผ๋ผ1์ด๋ฆ = ? AND ์นผ๋ผ2์ด๋ฆ = ?)
๐ค ์
SELECT 1์ ์ฐ๋๊ฑธ๊น?
EXISTS์์๋ ์กด์ฌ ์ฌ๋ถ๋ง์ ํ๋จํ๊ธฐ ๋๋ฌธ์*์ ํตํด ๋ชจ๋ ์นผ๋ผ์ ๊ฐ์ ธ์ค๋ ๊ฒ์ ๋นํจ์จ์ ์ด๊ธฐ ๋๋ฌธ์ ๋๋ค.
์๋ธ ์ฟผ๋ฆฌ๋ ๋ค๋ฅธ ์ฟผ๋ฆฌ ๋ด๋ถ์์ ์คํ๋๋ SQL ์ฟผ๋ฆฌ๋ฅผ ์๋ฏธํฉ๋๋ค.
๋ณ์นญ์ด ์๋ก์ด ์นผ๋ผ์ผ๋ก ์ถ๊ฐ๋์ด ํ ์ด๋ธ์ ๋ฐํํ๊ฒ ๋ฉ๋๋ค.
SELECT *, (SELECT count(*) FROM ํ
์ด๋ธ๋ช
WHERE ์นผ๋ผ1์ด๋ฆ = ์นผ๋ผ2์ด๋ฆ0) AS ๋ณ์นญ FROM ํ
์ด๋ธ๋ช

๐ ์์ ํ ๋ถ๋ถ์ ์ฃผํฉ์ ๊ธ์จ๋ก ๋ํ๋ ๋๋ค.
Method : GET
URL :/books?limit=๊ฐ์¤tPage=ํ์ด์ง๋ฒํธ
HTTP Status Code : 200 Ok
Request Body : x
Response Body :
[
{
"id" : ๋์ id,
"title": "๋์ ์ ๋ชฉ",
"img" : ์ด๋ฏธ์ง id,
"summary" : "์์ฝ ์ค๋ช
",
"author" : "๋์ ์๊ฐ",
"price" : ๊ฐ๊ฒฉ,
"likes" : ์ข์์ ์,
"pub_date" : "์ถ๊ฐ ๋ ์ง"
},
{
"id" : ๋์ id,
"title": "๋์ ์ ๋ชฉ",
"img" : ์ด๋ฏธ์ง id,
"summary" : "์์ฝ ์ค๋ช
",
"author" : "๋์ ์๊ฐ",
"price" : ๊ฐ๊ฒฉ,
"likes" : ์ข์์ ์,
"pub_date" : "์ถ๊ฐ ๋ ์ง"
},
...
]
Method : GET
URL : /books/:id
HTTP Status Code : 200 Ok
Request Body
{
"email": "์ฌ์ฉ์๊ฐ ์
๋ ฅํ ์ด๋ฉ์ผ",
"password" : "์ฌ์ฉ์๊ฐ ์
๋ ฅํ ๋น๋ฐ๋ฒํธ"
}
{
"id" : ๋์ id,
"title": "๋์ ์ ๋ชฉ",
"img" : ์ด๋ฏธ์ง id,
"category_name" : "์นดํ
๊ณ ๋ฆฌ",
"form" : "ํฌ๋งท",
"isbn" : "isbn",
"summary" : "์์ฝ ์ค๋ช
",
"detail" : "์์ธํ ์ค๋ช
",
"author" : "๋์ ์๊ฐ",
"pages" : ์ชฝ ์,
"contents" : "๋ชฉ์ฐจ",
"price" : ๊ฐ๊ฒฉ,
"likes" : ์ข์์ ์,
"liked" : boolean,
"pub_date" : "์ถ๊ฐ ๋ ์ง"
}
Method : GET
URL : /books?categoryId=:categoryId&news={boolean}
HTTP Status Code : 200 Ok
Request Body : x
Response Body :
[
{
"id" : ๋์ id,
"title": "๋์ ์ ๋ชฉ",
"img" : ์ด๋ฏธ์ง id,
"summary" : "์์ฝ ์ค๋ช
",
"author" : "๋์ ์๊ฐ",
"price" : ๊ฐ๊ฒฉ,
"likes" : ์ข์์ ์,
"pub_date" : "์ถ๊ฐ ๋ ์ง"
},
{
"id" : ๋์ id,
"title": "๋์ ์ ๋ชฉ",
"img" : ์ด๋ฏธ์ง id,
"summary" : "์์ฝ ์ค๋ช
",
"author" : "๋์ ์๊ฐ",
"price" : ๊ฐ๊ฒฉ,
"likes" : ์ข์์ ์,
"pub_date" : "์ถ๊ฐ ๋ ์ง"
},
...
]
news๊ฐ true์ผ ๋ ์ ๊ฐ ์กฐํ ๊ธฐ์ค์ ์ถ๊ฐ์ผ๋ก๋ถํฐ 1๋ฌ ์ด๋ด
Method : POST
URL : /likes/:bookId
HTTP Status Code : 200 Ok
Request Body : token > header "authorization"
Response Body : x
TODO : ์ถํ api ์์ , ํ์ฌ๋ ํ ํฐ์ผ๋ก ํ์ง ์๊ณ ,userId๋ฅผ body๊ฐ์ผ๋ก ๋ฐ์์ ์ฒ๋ฆฌ
Method : DELETE
URL : /likes/:bookId
HTTP Status Code : 200 Ok
Request Body : token > header "authorization"
Response Body : x
TODO : ์ถํ api ์์ , ํ์ฌ๋ ํ ํฐ์ผ๋ก ํ์ง ์๊ณ ,userId๋ฅผ body๊ฐ์ผ๋ก ๋ฐ์์ ์ฒ๋ฆฌ
const conn = require('../mariadb');
const { StatusCodes } = require('http-status-codes');
const addLike = (req, res) => {
const likedBookId = req.params.id;
const { userId } = req.body;
const sql = 'INSERT INTO likes (user_id, liked_book_id) VALUES (?, ?)';
const values = [userId, likedBookId];
conn.query(sql, values, (err, result) => {
if (err) {
console.log(err);
return res.status(StatusCodes.BAD_REQUEST).end();
}
return res.status(StatusCodes.CREATED).json(result);
});
};
const removeLike = (req, res) => {
const likedBookId = req.params.id;
const { userId } = req.body;
const sql = 'DELETE FROM likes WHERE user_id =? AND liked_book_id = ?';
const values = [userId, likedBookId];
conn.query(sql, values, (err, result) => {
if (err) {
console.log(err);
return res.status(StatusCodes.BAD_REQUEST).end();
}
return res.status(StatusCodes.OK).json(result);
});
};
module.exports = {
addLike,
removeLike,
};
addLike : likes ํ
์ด๋ธ์ user_id ์ liked_book_id๋ฅผ ์ ์ฅํฉ๋๋ค.
removeLike : likes ํ
์ด๋ธ์์ user_id ์ liked_book_id๋ฅผ ์ญ์ ํฉ๋๋ค.
const conn = require('../mariadb');
const { StatusCodes } = require('http-status-codes');
const allBooks = (req, res) => {
const { news, limit, currentPage, categoryId } = req.query;
const offset = limit * (currentPage - 1);
let sql =
'SELECT *, (SELECT count(*) FROM likes WHERE liked_book_id = books.id) AS likes FROM books';
let values = [];
if (categoryId && news) {
sql +=
' WHERE category_id = ? AND pub_date BETWEEN DATE_SUB(NOW(), INTERVAL 1 MONTH) AND NOW()';
values.push(categoryId);
} else if (categoryId) {
sql += ' WHERE category_id = ?';
values.push(categoryId);
} else if (news) {
sql +=
' WHERE pub_date BETWEEN DATE_SUB(NOW(), INTERVAL 1 MONTH) AND NOW()';
}
sql += ' LIMIT ? OFFSET ?';
values.push(parseInt(limit), offset);
conn.query(sql, values, (err, result) => {
if (err) {
console.log(err);
return res.status(StatusCodes.BAD_REQUEST).end();
}
if (result.length) {
return res.status(StatusCodes.OK).json(result);
} else {
return res.status(StatusCodes.NOT_FOUND).end();
}
});
};
const bookDetail = (req, res) => {
const id = parseInt(req.params.id);
const { userId } = req.body;
const sql = `SELECT *,
(SELECT count(*) FROM likes WHERE liked_book_id = books.id) AS likes,
(SELECT EXISTS (SELECT 1 FROM likes WHERE user_id = ? AND liked_book_id = ?)) AS liked
FROM books
LEFT JOIN categories
ON books.category_id = categories.category_id
WHERE books.id = ?`;
const values = [userId, id, id];
conn.query(sql, values, (err, result) => {
if (err) {
console.log(err);
return res.status(StatusCodes.BAD_REQUEST).end();
}
if (result[0]) {
return res.status(StatusCodes.OK).json(result);
} else {
return res.status(StatusCodes.NOT_FOUND).end();
}
});
};
module.exports = {
allBooks,
bookDetail,
};
allBooks : books ํ
์ด๋ธ์์ ๋ชจ๋ ์ปฌ๋ผ์ ๊ฐ์ ธ์ค๋ฉด์, likes ํ
์ด๋ธ์์ ํด๋น ์ฑ
์ ์ข์์ ๊ฐ์(likes)๋ฅผ ์กฐํํฉ๋๋ค.bookDetail : books ํ
์ด๋ธ์์ ๋ชจ๋ ์นผ๋ผ์ ๊ฐ์ ธ์ค๋ฉด์, likes ํ
์ด๋ธ์์ ํด๋น ์ฑ
์ ์ข์์ ๊ฐ์์ ์ ์ ๊ฐ ํด๋น ์ฑ
์ ์ข์์๋ฅผ ํ๋์ง(liked) ์ฌ๋ถ๋ฅผ ์กฐํํฉ๋๋ค.ํ ์ด๋ธ์ ์กฐ์ธํ์ง ์์๋ ์๋ธ ์ฟผ๋ฆฌ์ ์นผ๋ผ ๋ณ์นญ์ผ๋ก ์ํ๋ ๋ฐ์ดํฐ๋ฅผ ํจ์จ์ ์ผ๋ก ๊ฐ์ ธ์ฌ ์ ์์ด ํธ๋ฆฌํ์ต๋๋ค.