JavaScript/Node JS

Java Script(16)-MySQL DBMS node.js연동

두설날 2024. 5. 8. 10:52

*이 글을 읽기전에 작성자 개인의견이 있으니, 다른 블로그와 교차로 읽는것을 권장합니다.*

ORM(객체 관계 매핑, Object Relational Mapping)
- 객체 지향 프로그래밍 언어에서 사용되는 객체와 관계형 데이터베이스 간의 불일치를 해결하기 위한 기술
- 객체 모델과 관계형 데이터베이스의 테이블 간의 매핑을 수행하여 개발자가 SQL 쿼리 대신 객체 지향 코드를 사용할 수 있도록 함


ODM(객체 문서 매핑, Object Document Mapping)
- NoSQL 데이터베이스와 객체 지향 프로그래밍 언어 간의 매핑을 제공하는 기술
- 주로 문서 지향 데이터베이스(MongoDB)와 함께 사용


현재 작업중인 브랜치를 확인
- 목록을 확인

    git branch

- * 표시가 되어 있는 것이 현재 작업중인 브랜치

branch 생성하기
git branch 브랜치이름

branch 전환하기
git switch 브랜치이름
git checkout 브랜치이름

branch 생성과 동시에 전환하기
git checkout -b 브랜치이름

use kdt;

create table users (
	id int auto_increment primary key,
	username varchar(50) unique not null,
    password varchar(150) not null,
    name varchar(50) not null,
    email varchar(50) not null,
    url varchar(200) 
);

drop table tweets;
create table tweets (
	id int auto_increment primary key,
    userId int,
    createdAt datetime default now(),
    text varchar(2000) not null,
    foreign key(userId) references users(id) 
);

select * from users;
select * from tweets;
// package.json 파일
{
  "name": "server",
  "version": "1.0.0",
  "description": "",
  "main": "app.js",
  "type": "module",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "nodemon app"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "nodemon": "^3.1.0"
  },
  "dependencies": {
    "bcrypt": "^5.1.1",
    "dotenv": "^16.4.5",
    "express": "^4.19.2",
    "express-validator": "^7.0.1",
    "jsonwebtoken": "^9.0.2",
    "morgan": "^1.10.0",
    "mysql2": "^3.9.7",
    "socket.io": "^4.7.5"
  }
}

 

// app.js파일
import express from "express";
import morgan from "morgan";
import tweetsRouter from './router/tweets.js';
import authRouter from './router/auth.js';
import { config } from "./config.js";
import { db } from './db/database.js';

const app = express();

app.use(express.json());
app.use(morgan("dev"));

app.use('/tweets', tweetsRouter);
app.use('/auth', authRouter);

app.use((req, res, next) => {
    res.sendStatus(404);
});

// DB 연결 테스트!
// db.getConnection().then(connection => console.log(connection));

app.listen(config.host.port
// config.js 파일
import dotenv from 'dotenv';

dotenv.config();

function required(key, defaultValue=undefined){
    const value = process.env[key] || defaultValue; // or: 앞의 값이 true로 판별되면 앞의 값이 대입되고 값이 false로 판별되면 뒤에 값이 대입됨
    if(value == null){
        throw new Error(`키 ${key}는 undefined!!`);
    }
    return value;
}

export const config = {
    jwt: {
        secretKey: required('JWT_SECRET'),
        expiresInSec: parseInt(required('JWT_EXPIRES_SEC', 172800))
    },
    bcrypt: {
        saltRounds: parseInt(required('BCRYPT_SALT_ROUNDS', 10))
    },
    host: {
        port: parseInt(required('HOST_PORT', 8080))
    },
    db: {
        host: required('DB_HOST'),
        user: required('DB_USER'),
        database: required('DB_DATABASE'),
        password: required('DB_PASSWORD'),
        port: required('DB_PORT')
    }
}
// controller > auth.js 파일
import * as authRepository from '../data/auth.js';
import bcrypt from 'bcrypt';
import jwt from 'jsonwebtoken';
import { config } from '../config.js';


function createJwtToken(id){
    return jwt.sign({id}, config.jwt.secretKey, {expiresIn: config.jwt.expiresInSec});
}


export async function signup(req, res, next){
    const {username, password, name, email, url} = req.body;
    const found = await authRepository.findByUsername(username);
    if(found){
        return res.status(409).json({message:`${username}이 이미 있습니다`});
    }
    const hashed = await bcrypt.hash(password, config.bcrypt.saltRounds);
    const userId = await authRepository.createUser({username, hashed, name, email, url});
    const token = createJwtToken(userId);
    res.status(201).json({token, username});
}

export async function login(req, res, next){
    const {username, password} = req.body;
    // const user = await authRepository.login(username);
    const user = await authRepository.findByUsername(username);
    console.log(user);
    if(!user){
        return res.status(401).json({message: `아이디를 찾을 수 없음`});
    }
    const isValidpassword = await bcrypt.compareSync(password, user.password);
    if(!isValidpassword){
        return res.status(401).json({message: `비밀번호가 틀렸음`});
    }
    const token = createJwtToken(user.id);
    res.status(200).json({token, username});
}

// export async function verify(req, res, next){
//     const token = req.header['Token'];
//     if(token){
//         res.status(200).json(token);
//     }
// }

export async function me(req, res, next){
    const user = await authRepository.findById(req.userId);
    console.log(user);
    if(!user){
        return res.status(404).json({message: `일치하는 사용자가 없음`});
    }
    res.status(200).json({token: req.token, username: user.username});
}
// controller > tweet.js 파일
import * as tweetRepository from '../data/tweet.js';

// 여러 트윗을 가져오는 함수
export async function getTweets(req, res){
    const username = req.query.username;
    const data = await (username ? tweetRepository.getAllByUsername(username)
                                 : tweetRepository.getAll());
    res.status(200).json(data);
}

// 하나의 트윗을 가져오는 함수
export async function getTweet(req, res, next) {
    const id = req.params.id;
    const tweet = await tweetRepository.getById(id);
    if(tweet){
        res.status(200).json(tweet);
    }else{
        res.status(404).json({message: `${id}의 트윗이 없습니다`})
    }
}

// 트윗을 생성하는 함수
export async function createTweet(req, res, next) {
    const { text } = req.body;
    const tweet = await tweetRepository.create(text, req.userId);
    res.status(201).json(tweet);
}

// 트윗을 변경하는 함수
export async function updateTweet(req, res, next) {
    const id = req.params.id;
    const text = req.body.text;
    const tweet = await tweetRepository.update(id, text);
    if(tweet){
        res.status(201).json(tweet);
    }else{
        res.status(404).json({message: `${id}의 트윗이 없습니다`})
    }
}

// 트윗을 삭제하는 함수
export async function deleteTweet(req, res, next) {
    const id = req.params.id;
    await tweetRepository.remove(id);
    res.sendStatus(204);
}
// data > auth.js 파일
import { db } from '../db/database.js';

// 아이디(username) 중복검사
export async function findByUsername(username){
    return db.execute('select * from users where username = ?', [username]).then((result) => {
        console.log(result);
        return result[0][0];
    });
}

// id 중복검사
export async function findById(id){
    return db.execute('select * from users where id = ?', [id]).then((result) => {
        console.log(result);
        return result[0][0];
    });
}

export async function createUser(user){
    console.log(user);
    const {username, hashed, name, email, url} = user;
    return db.execute('insert into users (username, password, name, email, url) values (?, ?, ?, ?, ?)', [username, hashed, name, email, url]).then((result) => {
        console.log(result);    // result[0].insertId
        return result[0].insertId;
    });
}

// export async function login(username){
//     const user = users.find((user) => user.username === username)
//     return user;
// }
// data > tweet.js 파일
import { db } from '../db/database.js';

const SELECT_JOIN = 'select tw.id, tw.text, tw.createdAt, tw.userId, us.username, us.name, us.email, us.url from tweets as tw join users as us on tw.userId = us.id';

const ORDER_DESC = 'order by tw.createdAt desc';

// 모든 트윗을 리턴
export async function getAll() {
    return db.execute(`${SELECT_JOIN} ${ORDER_DESC}`).then((result) => {
        console.log(result);
        return result;
    });
}

// 해당 아이디에 대한 트윗을 리턴
export async function getAllByUsername(username){
    return db.execute(`${SELECT_JOIN} where username = ? ${ORDER_DESC}`, [username]).then((result) => {
        console.log(result);
        return result;
    });
}

// 글번호에 대한 트윗을 리턴
export async function getById(id){
    return db.execute(`${SELECT_JOIN} where tw.id = ? ${ORDER_DESC}`, [id]).then((result) => {
        console.log(result);
        return result;
    });
}

// 트윗을 작성
export async function create(text, userId){
    return db.execute('insert into tweets (text, userId) values (?, ?)', [text, userId]).then((result) => {
        console.log(result);
        return getById(result[0].insertId);
    });
}

// 트윗을 변경
export async function update(id, text){
    return db.execute('update tweets set text = ? where id = ?', [text, id]).then((result) => {
        console.log(result);
        return getById(id);
    });
}

// 트윗을 삭제
export async function remove(id){
    return db.execute('delete from tweets where id = ?', [id]);
}
// db > database.js 파일
import mysql from 'mysql2';
import { config } from '../config.js';

const pool = mysql.createPool({
    host: config.db.host,
    port: config.db.port,
    user: config.db.user,
    database: config.db.database,
    password: config.db.password
});

export const db = pool.promise();