[ 살펴보기 ] DrizzleORM - Basics
![[ 살펴보기 ] DrizzleORM - Basics](https://cdn.hashnode.com/res/hashnode/image/upload/v1731562725362/6cf28f40-e345-4b17-8959-5d0d9ad0127a.jpeg)
DrizzleORM을 통해 NodeJS에서 database를 조작하는 방법을 살펴보자. 포스트에서 사용하는 DBMS는 PostgreSQL이며 Hono framework를 통해 router를 구성한다.
우선 Hono project 세팅을 위해 다음 command를 실행한다. 아래 command를 실행하면 몇 가지 질문을 하고 drizzle_app이라는 폴더에 새로운 hono project의 기본 template을 추가한다. 아래 포스트 내용은 command를 실행했을 때 물어보는 질문 중 사용할 template은 nodejs로 설정하여 진행한다.
npm create hono@latest drizzle_app
위의 command를 통해 생성된 파일 중 src/index.ts의 초기 내용은 다음과 같다.
src/index.ts
import { serve } from "@hono/node-server";
import { Hono } from "hono";
const app = new Hono();
app.get("/", (c) => {
return c.text("Hello Hono!");
});
const port = 3000;
console.log(`Server is running on http://localhost:${port}`);
serve({
fetch: app.fetch,
port,
});
이제 drizzle을 사용하기 위해 필요한 package를 설치한다.
npm i drizzle-orm pg dotenv
npm i -D drizzle-kit tsx @types/pg
그리고 .env 파일을 생성해 database url 정보를 추가해준다. database가 localhost에서 실행 중이라면 url 정보의 형식은 아래와 같다. username, password, port_number, database_name은 현재 실행 중인 database의 설정값으로 대체해준다.
.env
DATABASE_URL=postgresql://username:password@localhost:port_number/database_name
만약 username이 testname, password가 testpassword, port number가 3000, database name이 postgres라면 URL 정보는 다음과 같이 설정한다.
DATABASE_URL=postgresql://testname:testpassword@localhost:3000/postgres
그리고 database에 members라는 table을 하나 생성해보자.
CREATE TABLE members (
id int GENERATED ALWAYS AS IDENTITY,
name text,
email text UNIQUE,
PRIMARY KEY( id )
)
그리고 간단한 테스트를 위해 members table에 데이터를 몇 개 추가해준다. 아래 예제에서 id column data를 별도로 추가하지 않는 이유는 id column은 GENERATED ALWAYS AS IDENTITY 설정으로 인해 자동 생성되기 때문이다.
INSERT INTO members (name, email)
VALUES ('test name1', 'test email1'),
('test name2', 'test email2');
이제 application에서 members table에 select, create, update와 같은 작업을 수행하기 위해 해당 table에 대한 drizzle schema를 작성해야 한다. schema를 직접 작성할 수도 있지만 drizzle-kit을 사용하면 database에 존재하는 table에 대한 drizzle schema를 자동으로 생성해준다.
drizzle-kit를 사용하기 위해 package를 설치해준다.
npm instal -D drizzle-kit
그리고 project root에 drizzle.config.ts 파일을 생성해주고 database 관련 내용을 설정한다.
drizzle.config.ts
import "dotenv/config";
import { defineConfig } from "drizzle-kit";
export default defineConfig({
dialect: "postgresql",
schemaFilter: "public",
out: "./drizzle",
dbCredentials: {
url: process.env.DATABASE_URL!,
},
});
위의 예제에서 database는 postgresql를 사용하며 database schema는 public schema 그리고 drizzle-kit로 생성되는 코드는 ./drizzle이라는 경로에 생성되도록 설정하고 있다.
이제 다음 command를 실행해 database table 정보를 기반으로 drizzle schema를 생성해보자.
npx drizzle-kit pull
위의 명령어를 실행하면 다음과 같이 ./drizzle/schema.ts 파일에 table에 대한 drizzle schema가 생성된 것을 확인할 수 있다.
import { pgTable, unique, integer, text } from "drizzle-orm/pg-core";
import { sql } from "drizzle-orm";
export const members = pgTable(
"members",
{
id: integer()
.primaryKey()
.generatedAlwaysAsIdentity({
name: "members_id_seq",
startWith: 1,
increment: 1,
minValue: 1,
maxValue: 2147483647,
cache: 1,
}),
name: text(),
email: text(),
},
(table) => {
return {
membersEmailKey: unique("members_email_key").on(table.email),
};
}
);
이제 위에서 생성한 schema를 통해 table에서 데이터를 조회하거나 추가하는 작업을 해보자. 아래 예제는 database connection을 생성하고 members라는 router에 request가 들어오면 members table의 모든 데이터를 return 해주는 code를 추가한다.
import "dotenv/config";
import { serve } from "@hono/node-server";
import { Hono } from "hono";
import { drizzle } from "drizzle-orm/node-postgres";
import { members } from "../drizzle/schema.js";
const app = new Hono();
const database = drizzle(process.env.DATABASE_URL!);
app.get("/members", async (c) => {
try {
const memberList = await database.select().from(members);
return c.json({ memberList });
} catch (err) {
return c.json({ error: true }, 400);
}
});
const port = 3000;
console.log(`Server is running on port ${port}`);
serve({
fetch: app.fetch,
port,
});
이제 hono application을 실행하고 /members path로 request를 보내보면 members table의 data가 return되는 것을 확인할 수 있다.
Create data
새로운 데이터를 추가하기 위해 post method를 처리하는 router를 추가해보자. table에 새로운 데이터를 추가할 때는 insert method를 통해 추가할 수 있다. 아래 예제는 request body로 전달 받은 value를 table에 추가한다.
...
import { members } from "../drizzle/schema.js";
app.post("/members", async (c) => {
const requestBody = await c.req.json();
try {
await database
.insert(members)
.values(requestBody);
return c.json({ success: true }, 201);
} catch (err) {
return c.json({ error: true }, 400);
}
});
Update data
데이터의 update를 위해 patch method를 처리하는 router를 추가해보자. 기존 데이터를 수정할 때는 update method를 통해 수정할 수 있다. 아래 예제는 path parameter로 전달 받은 member id와 request body로 table의 값을 수정한다.
...
import { eq } from "drizzle-orm";
import { members } from "../drizzle/schema.js";
app.patch("/members/:id", async (c) => {
const { id } = c.req.param();
const { email, name } = await c.req.json();
console.log({ email, name, id });
try {
await database
.update(members)
.set({ email, name })
.where(eq(memberTable.id, Number(id)));
return c.json({ success: true }, 200);
} catch (err) {
return c.json({ error: true }, 400);
}
});
Delete data
다음은 기존 데이터의 삭제를 위해 delete method를 처리하는 router를 추가해보자. 기존 데이터를 삭제할 때는 delete method를 통해 삭제할 수 있다. 아래 예제는 path parameter로 전달 받은 member id를 통해 table의 값을 삭제한다.
...
import { eq } from "drizzle-orm";
import { members } from "../drizzle/schema.js";
app.delete("/members/:id", async (c) => {
const { id } = c.req.param();
try {
await database
.delete(members)
.where(eq(memberTable.id, Number(id)));
return c.json({ success: true }, 204);
} catch (err) {
return c.json({ error: true }, 400);
}
});
위의 예제를 통해서 살펴보았듯이 drizzle은 SQL와 유사한 syntax를 통해 각종 query를 실행할 수 있다. 간단한 drizzle query와 SQL query 구문을 비교하면 다음과 같다.
Insert ( Drizzle )
database.insert(members).values({ name:'name1', email: 'email1'})
Insert ( SQL )
INSERT INTO members (name, email) VALUES ('name1', 'email1');
Update ( Drizzle )
db.update(members)
.set({ name:'name1 update', email: 'email1 update'})
.where(eq(memberTable.id, 1))
Update ( SQL )
UPDATE members
SET name = 'name1 update', email = 'email1 update'
WHERE id = 1
![[ 살펴보기 ] RDB - Relationships](https://cdn.hashnode.com/res/hashnode/image/upload/v1739711556668/48dc9e84-a621-42aa-9c9f-5fc5c436f0ec.jpeg)
![[ 살펴보기 ] MySQL - Data types](https://cdn.hashnode.com/res/hashnode/image/upload/v1739593589113/530f8704-4d27-42c9-a451-bb5c63150b99.jpeg)
![[ 살펴보기 ] TypeORM - Transactions, Migration](https://cdn.hashnode.com/res/hashnode/image/upload/v1739106042581/980b8133-61d4-406a-a026-65be9c28eace.jpeg)
![[ 살펴보기 ] TypeORM - Relations](https://cdn.hashnode.com/res/hashnode/image/upload/v1738666874402/b688bd0b-b6bb-4f43-87d8-c1b46b59f1b7.jpeg)
![[ 살펴보기 ] TypeORM - Basics](https://cdn.hashnode.com/res/hashnode/image/upload/v1738666803591/bef5df17-7dc7-4123-ae55-004d5042df39.jpeg)