วิธีการใช้งาน Drizzle ORM
Drizzle คือ ORM ที่ทำหน้าที่ติดต่อกับ Database ซึ่งจะคล้ายกับ Prisma แต่มีขนาดเล็กมาๆ Drizzle มีขนาดแค่ 7.4Kb หลังจาก Minified และ Zip ด้วย Gzip แล้ว
Drizzle นั้นรองรับ Database ดังๆหลายตัว ยกตัวอย่างเช่น
- SQLite
- PostgreSQL
- MySQL
ในบทความนี้เราจะใช้ SQLite เป็น Database และใช้ better-sqlite3
เป็น Library สำหรับการเชื่อมต่อกับ SQLite ซึ่งในการทำงานจริงเราอาจเลือกใช้ Library อื่นๆ เช่น libsql ในการเชื่อมต่อก็ได้
ติดตั้ง Drizzle
เรามาเริ่มต้นติดตั้ง Drizzle กัน โดยที่คุณจะต้องมี Drizzle และ Better SQlite3
npm install drizzle-orm better-sqlite3
หลังจากนั้นให้คุณติดตั้ง Drizzle Kit ซึ่งเป็น GUI สำหรับการ Manage Database เหมือนกับ Prisma Studio
npm install -D drizzle-kit
เราใช้ -D
หรือ --save-dev
เพื่อบอกว่า Drizzle Kit นั้นใช้แค่ตอน Dev เท่านั้นตอนขึ้น Production ไม่ต้องเอา Drizzle Kit ขึ้นไปด้วย
Config Drizzle
สร้างไฟล์ drizzle.config.ts
และบอก Drizzle Kit ว่า schema และ migration อยู่ที่ไหน
// drizzle.config.ts
import { defineConfig } from "drizzle-kit";
export default defineConfig({
schema: "./src/db/schema.ts", // ไฟล์ Schema ที่ระบุโครงสร้างของแต่ละ Table ใน Database
out: "./drizzle", // SQL ที่ generate ออกมาจะเก็บไว้ใน Folder ไหน
dialect: "sqlite",
driver: "better-sqlite", // ระบุ Driver ที่ใช้ในการติดต่อกับ Database
dbCredentials: {
url: "./sqlite.db", // Database จะถูกสร้างโดยอัตโนมัติถ้ายังไม่มีไฟล์นี้
},
});
กำหนด Schema
หลังจากกำหนด Configuration ของ Drizzle เรียบร้อยแล้ว เราก็จะกำหนดโครงสร้างของ Table ต่างๆใน Database ซึ่งเราจะสร้างไฟล์ schema.ts
ไว้ใน Folder /src/db
// src/db/schema.ts
import { sqliteTable, integer, text } from "drizzle-orm/sqlite-core";
import { relations } from "drizzle-orm";
export const users = sqliteTable("users", {
id: integer("id").primaryKey({ autoIncrement: true }),
name: text("name").notNull(),
email: text("email").notNull().unique(),
});
export const posts = sqliteTable("posts", {
id: integer("id").primaryKey({ autoIncrement: true }),
title: text("title").notNull(),
body: text("body"),
authorId: integer("author_id")
.notNull()
.references(() => users.id, { onDelete: "cascade" }),
});
ในกรณีที่ต้องการสร้างความสัมพันธ์(Relationship) เราจะกำหนดความสัมพันธ์ของแต่ละ Table ดังนี้
// User มีความสัมพันธ์แบบ One-To-Many กับ Post
export const usersRelations = relations(users, ({ many }) => ({
posts: many(posts),
}));
export const postsRelations = relations(posts, ({ one }) => ({
author: one(users, {
fields: [posts.authorId],
references: [users.id],
}),
}));
Connect Database
การ Connect Database เราจะใช้การ new Database()
ขึ้นมาแล้วระบุ Database URL
// src/db/index.ts
import Database from "better-sqlite3";
import { drizzle } from "drizzle-orm/better-sqlite3";
import * as schema from "./schema";
const sqlite = new Database("sqlite.db"); // จะสร้างไฟล์ sqlite.db ขึ้นมาใหม่ถ้ายังไม่มี
export const db = drizzle(sqlite, { schema });
Generate และ Migrate database
เพิ่ม script สำหรับการ Migrate และ Generate Database เข้าไปใน package.json
ซึ่ง
Generate
จะสร้างไฟล์ migration(SQL สำหรับสร้างโครงสร้าง Database)Migration
จะใช้สำหรับ Apply SQL ที่ได้จากการ Generate ไปที่ Database ที่เราได้ Connect ไว้นั่นเอง
{
"scripts": {
"db:generate": "drizzle-kit generate",
"db:migrate": "drizzle-kit migrate",
"db:studio": "drizzle-kit studio"
}
}
หลังจากนั้นเราจะสามารถเรียกคำสั่ง migrate
และ generate
ผ่านทาง npm run
แบบนี้ได้เลย
npm run db:generate
npm run db:migrate
npm run db:studio # เปิด UI จัดการ DB
generate
→ drizzle-kit จะสร้างไฟล์ SQL migration จาก schemamigrate
→ apply migrations ไปยังsqlite.db
studio
→ เปิด Drizzle Studio GUI
Seeding
Seeding คือขั้นตอนการนำข้อมูลเข้าไปใน Database เนื่องจาก Application จะทำงานได้นอกจากจะมีโครงสร้างของ Database ที่ถูกต้องแล้วยังต้องมี Master Data หรือข้อมูลเริ่มต้นด้วย เช่น Order Status เป็นต้น
ดังนั้นถ้าเราต้องการนำข้อมูลเข้าไปใส่ใน Database หลังจากที่ Migrate เรียบร้อยแล้วให้เราสร้าง Seeding โดยมีขั้นตอนต่างๆ ดังนี้
1. สร้าง Seed Script
สร้างไฟล์ src/db/seed.ts
แล้วหลังจากนั้นลบข้อมูลเก่าออกก่อน แล้วเพิ่มข้อมูลใหม่ใส่เข้าไป ไม่งั้นเมื่อ Run Seed หลายๆรอบข้อมูลจะเพิ่มขึ้นเรื่อยๆ
// src/db/seed.ts
import { db } from "./index";
import { users, posts } from "./schema";
async function main() {
console.log("Seeding database...");
// ล้างข้อมูลเก่า (ถ้าต้องการเริ่มใหม่ทุกครั้ง)
await db.delete(posts);
await db.delete(users);
// เพิ่ม users
const insertedUsers = await db.insert(users).values([
{ name: "Alice", email: "alice@test.com" },
{ name: "Bob", email: "bob@test.com" },
{ name: "Charlie", email: "charlie@test.com" },
]).returning();
// เพิ่ม posts
await db.insert(posts).values([
{
title: "Hello World",
body: "My first post using Drizzle + SQLite!",
authorId: insertedUsers[0].id,
},
{
title: "SQLite is fast",
body: "Better-sqlite3 is great for local dev.",
authorId: insertedUsers[1].id,
},
{
title: "Relational Queries",
body: "Drizzle makes joins super easy.",
authorId: insertedUsers[2].id,
},
]);
console.log("Seeding completed!");
}
main()
.then(() => process.exit(0))
.catch((err) => {
console.error(err);
process.exit(1);
});
2. เพิ่ม Script ใน package.json
{
"scripts": {
"db:seed": "ts-node src/db/seed.ts"
}
}
ถ้าคุณใช้ tsx
ก็แค่เปลี่ยนจาก ts-node
เป็น tsx
ได้เลย
{
"scripts": {
"db:seed": "tsx src/db/seed.ts"
}
3. รัน Seed Script
สุดท้ายเราก็ไปเลือก Seed Script ที่เราเขียนมาใช้งานโดยใช้คำสั่ง
npm run db:seed
ผลลัพธ์ที่ได้จะออกมาเป็น
- Table
users
จะมีข้อมูล Alice, Bob, Charlie - Table
posts
จะมีโพสต์ 3 ซึ่งผูกอยู่กับ User ด้วยauthorId
ตัวอย่างการใช้ Drizzle
ในตัวอย่างนี้เป็นการเรียกใช้ Drizzle ใน Application ของเราโดยในตัวอย่างนี้เราจะ Insert User ใหม่เข้าไปใน Table Users
import { db } from "./db";
import { users, posts } from "./db/schema";
import { eq } from "drizzle-orm";
// Create
await db.insert(users).values({ name: "John", email: "john@test.com" });
await db.insert(posts).values({ title: "Hello", body: "SQLite + Drizzle", authorId: 4 });
// Get all User
const allUsers = await db.select().from(users);
const userWithPosts = await db.query.users.findMany({
with: { posts: true },
});
// Update user
await db.update(users)
.set({ name: "Jack" })
.where(eq(users.id, 4));
// Delete post
await db.delete(posts)
.where(eq(posts.id, 1));
สรุปข้อดีของ Drizzle ORM
เราสามารถสรุปข้อดีของของ Drizzle ORM ออกมาเป็นข้อๆได้ดังนี้
- Type-safe → เรามีการระบุ Type ไว้ในไฟล์
schema.ts
- Migrations → การมี Migration จะช่วยให้ Database ของเรามี Version ตรงกับ Code
- Relationship → สามารถ Query ข้อมูลข้ามตารางได้ง่ายมาก(Join)