- prisma ๋?
- prisma ์ค์น ๋ฐ ์ค์ ๋ฐฉ๋ฒ
- project ์ด๊ธฐ ์ธํ
- prisma folder ์์ฑ
- ์ฐ๊ฒฐํ database ์ ๋ณด ์ค์
- ์ฐ๊ฒฐํ๊ธฐ
- prisma client ์ค์น ๋ฐ ์์ฑ
- prisma๋ก data read, create ํด๋ณด๊ธฐ
prisma๋ node.js ์ Typescript๋ฅผ ์ํ ํ์์ ์ต์ ํธ๋ ๋์ ORM(Object Relational Mapping) open source ๊ธฐ์ ์ด๋ค. (๊ธฐ์กด ORM๊ธฐ์ ๋ก๋ Sequelize, typeORM ์ด ์๋ค.)
prisma๋ Heroku ์ฐฝ์ ์์ Graphql ๊ฐ๋ฐ์๊ฐ ํฉ์ํ์ฌ ๋ง๋ ๊ธฐ์ ์ด๊ธฐ์ ํนํ Graphql๊ณผ ์ ๋ง๋๋ค. Graphql ๋์ ์ ๊ณ ๋ คํ๋ค๋ฉด prisma๋ฅผ ์ ํํ๋ ๊ฒ์ด ์ข๋ค.
project ์ด๊ธฐ ์ธํ
๋จผ์ ํด์ผ ํ๋๊ฒ์ Node.js project ์ด๊ธฐ์ค์ ์ด๋ค.
npm init -y # package.json ์์ฑ
npm i @prisma/cli --save-dev # prisma command line interface ์ค์น
prisma folder ์์ฑ
prisma ๋ฅผ node.js์ ์ฐ๊ฒฐํ๋ ค๋ฉด ์ฐ์ prisma schema ํ์ผ๊ณผ env ํ์ผ์ ๋ง๋ค์ด์ผ ํ๋ค.
์๋ ๋ช ๋ น์ ์คํํด๋ณด์.npx prisma init
(npx๋ npm v5.2.2 ์ด์๋ถํฐ ์ง์ํ๋ ๊ธฐ๋ฅ์ผ๋ก ์กฐ๊ธ๋ ํจํค์ง ๊ด๋ฆฌ๋ฅผ ์ฝ๊ฒ ํด์ฃผ๋ ๊ฒ์ด ์ฃผ ๋ชฉ์ ์ด๋ค. npx๋ ์ฐจํ ์์ธํ ์์๋ณด์.)
์ ๋ช ๋ น์ ์คํํ๋ฉด ์คํํ ๊ฒฝ๋ก์์ 'prisma' ํด๋๊ฐ ์์ฑ๋๊ณ ๊ทธ ์์๋ 'schema.prisma'์ด ์์ฑ๋๋ค. ๊ทธ๋ฆฌ๊ณ 'prisma' ํด๋์ ๋์ผ ๊ฒฝ๋ก์ .env ํ์ผ์ด ์์ฑ๋๋ค.
schema.prisma : migration๋ Database table schema๊ฐ ์ ์๋๋ ํ์ผ(prisma ํต์ฌ)
.env : Database ์ ์์ ์ํ ํ๊ฒฝ๋ณ์๋ฅผ ์ค์ ํ๋ ์จ๊น ํ์ผ.
์ฐ๊ฒฐํ database ์ ๋ณด ์ค์
prisma/schema.prisma ํ์ผ์ ์ด๋ฉด ์๋์ ๊ฐ์ ์ฝ๋๊ฐ ๋์จ๋ค.
//This is your Prisma schema file, //learn more about it in the docs: https://pris.ly/d/prisma-schema datasource db { provider = "postgresql" // ์ฌ๊ธฐ๋ฅผ mysql๋ก ๋ณ๊ฒฝ url = env("DATABASE_URL") } generator client { provider = "prisma-client-js" }```
db์ provider๊ฐ default๋ก 'postgresql'๋ก ๋์ด์๋ค. ์ด๋ฅผ 'mysql'๋ก ๋ณ๊ฒฝํด์ผ ํ๋ค.
๊ทธ ๋ค์ .env ํ์ผ์ ์ด์ด๋ณด์// prisma/schema.prisma // Environment variables declared... // See the documentation for more detail: ... // Prisma supports the native connection... // See the documentation for all the connection string options:... DATABASE_URL="postgresql://johndoe:randompassword@localhost:5432/mydb?schema=public"```
.env์ 'DATABASE_URL'์ [์ฐ๊ฒฐํ sql ๋ชจ๋ธ๊ณผ ๊ณ์ , ํจ์ค์๋, ์ฌ์ฉํ database] ์ ๋ณด๋ฅผ ๋ฃ์ด์ค์ผ ํ๋ค. node project๋ฅผ ์ํด ์์ฑํ database ๊ธฐ์ค์ผ๋ก ์์ ํ๋ค.
// .env DATABASE_URL="mysql://node_blogs_user:{ํจ์ค์๋}@localhost:3306/node_blogs?schema=public"```
์ฐ๊ฒฐํ๊ธฐ
prisma๋ ์ต์ ๊ธฐ์ ์ด๋ค๋ณด๋ ์์ง schema๋ฅผ ๊ธฐ์ค์ผ๋ก ์ค์ Table์ ๋ง๋๋ ๊ฒ์ ์ทจ์ฝํ ๋ฏ ํ๋ค. ํด์ prisma ์ฐ๋์ ์ํด์ dbdiagram.io ๊ฐ์ tool์ ์ด์ฉํด ๋ชจ๋ธ๋งํ ๋ฐ์ดํฐ๋ฅผ sqlํ์ผ๋ก exportํ์ฌ database์ import ํ๋ ๊ณผ์ ์ด ๋จผ์ ํ์ํ๋ค.
์ค๋น๊ฐ ๋์๋ค๋ฉด ์๋ ๋ช ๋ น์ ์คํํ์.npx prisma introspect // ์ด ๋ช ๋ น์ด๋ .env ํ์ผ์์ ํ๊ฒฝ๋ณ์๋ก ์์ฑํ DATABASE_URL ์ ์ ์ํด์ // ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ํ ์ด๋ธ ์คํค๋ง๋ฅผ ๊ฒ์ฌํ ํ, schema.prisma ํ์ผ์ ๋ชจ๋ธ์ ์์ฑํ๋ค.```
์คํ์ด ์๋ฃ๋๋ฉด prisma/schema.prisma ์๋ ์๋์ฝ๋์ฒ๋ผ ํ์ผ database์ ์ ๋ณด๊ฐ ์ถ๊ฐ๋๋ค.
// prisma/schema.prisma generator client { provider = "prisma-client-js" } datasource db { provider = "mysql" url = env("DATABASE_URL") } model articles { id Int @id @default(autoincrement()) user_id Int title String body String status articles_status @default(DRAFT) created_at DateTime? @default(now()) updated_at DateTime? deleted_at DateTime? users users @relation(fields: [user_id], references: [id]) comments comments[] @@index([user_id], name: "user_id") } model comments { id Int @id @default(autoincrement()) article_id Int user_id Int body String created_at DateTime? @default(now()) updated_at DateTime? deleted_at DateTime? articles articles @relation(fields: [article_id], references: [id]) users users @relation(fields: [user_id], references: [id]) @@index([article_id], name: "article_id") @@index([user_id], name: "user_id") } model users { id Int @id @default(autoincrement()) email String @unique password String status users_status @default(ACTIVE) created_at DateTime? @default(now()) updated_at DateTime? deleted_at DateTime? articles articles[] comments comments[] } enum articles_status { DRAFT PUBLISHED DELETED } enum users_status { ACTIVE INACTIVE }```
prisma client ์ค์น ๋ฐ ์์ฑ
// ๋จผ์ client ๋ ธ๋ ๋ชจ๋ ํจํค์ง ์ค์น npm install @prisma/client npx prisma generate // ์ด ๋ช ๋ น์ด๋ npx prisma introspect ๋ช ๋ น์ด๋ฅผ ํตํด์ ์์ฑ๋ schema.prisma ํ์ผ์ ์ฝ์ด์ // node_modules/@prisma/client ํด๋ ์์ ์ฐ๋ฆฌ๊ฐ ์ฌ์ฉํ prisma client ์ฝ๋๋ฅผ ์์ฑ ํด ์ค๋ค.```
prisma๋ก mysql์ node_blogs database์ mapping์ด ๋์๋ค. ์ด์ node ์์์ ์ด๋ฅผ ์ด์ฉํด table์ ์ ์ดํด๋ณด์.
const bcrypt = require('bcryptjs') const jwt = require('jsonwebtoken') const {PrismaClient} = require('@prisma/client') const prisma = new PrismaClient() // SignUp (ํ์๊ฐ์ ) // 1. ์์ฒญ์๊ฐ email, password ๋ฑ์ ํ์ ์ ๋ณด๋ฅผ ๋ณด๋ด๋ฉด ์ด๋ฅผ ๋ฐ์ User table์ ์ถ๊ฐ app.post('/users/signup', (req, res) => { const {email, password} = req.body const hashedPassword = bcrypt.hash(password, 10) const createdUser = await prisma.users.create({ data : { email, password: hashedPassword, } }) res.status(201).json({createdUser}) }) // LogIn // 1. ์์ฒญ์์ email, password ์ฒดํฌ app.post('/users/login', async (req, res) => { try { const { email, password: inputPassword } = req.body const foundUser = await prisma.users.findOne({ where: { email } }) if (!foundUser) { const error = new Error('invalid input') error.statusCode = 400 throw error } const { id, password: hashedPassword } = foundUser const isValidPassword = await bcrypt.compare(inputPassword, hashedPassword) if (!isValidPassword) { const error = new Error('invalid input') error.statusCode = 400 throw error } const token = jwt.sign({ id }, 'node_blogs_secret_key', { expiresIn: '1h' }) res.status(200).json({ message: 'login success', token }) } catch (err) { res.status(err.statusCode).json({ message: err.message }) } })```
์ ์ฒ๋ผ prisma ๊ฐ์ฒด๋ฅผ ํตํด model์ ์ ๊ทผ ๋ฐ ์ ์ด ํ ์ ์๋ค.
์์ธํ ํ๋ฆฌ์ฆ๋ง ์ค๋ช ๊ฐ์ฌ๋๋ฆฝ๋๋ค
์๋ดค์ต๋๋ค!