Prisma

Prisma คือ ORM (Object-Relational Mapping) ของฝั่ง Node.js/TypeScript ที่นิยมที่สุดตัวหนึ่ง จุดเด่นคือ type-safe เต็มรูปแบบ — auto-generate TypeScript client จาก schema ทำให้ query ทุกอันมี autocomplete + ตรวจ type ตอน compile

เทียบ Java: Prisma ทำหน้าที่เหมือน Hibernate/JPA แต่ปรัชญาต่างกันชัด — Hibernate ใช้ @Entity บน class แล้ว map กลับไปตาราง ส่วน Prisma แยก schema ออกมาเป็น ไฟล์ภาษากลาง (schema.prisma) ไฟล์เดียว เป็น single source of truth แล้ว generate code ออกมา ไม่ใช่เขียน entity class เอง

โครงสร้างการทำงาน

  1. นิยามตารางใน schema.prisma (model + @attribute)
  2. prisma migrate dev → สร้าง migration + อัปเดตตารางจริง
  3. prisma generate → สร้าง Prisma Client (โค้ด TypeScript ที่ใช้ query)
  4. import client มา query ในโค้ด
model User {
  id       Int    @id @default(autoincrement())
  email    String @unique
  password String
  todos    Todo[]            // ความสัมพันธ์ 1—*
}
 
model Todo {
  id     Int    @id @default(autoincrement())
  title  String
  userId Int
  user   User   @relation(fields: [userId], references: [id])
}

Query หลัก ๆ

create / findMany / findUnique / findFirst / update / delete

  • findUnique — หาด้วย field ที่ unique (เช่น id, email) เท่านั้น
  • findFirst — หาแถวแรกที่ตรงเงื่อนไขทั่วไป (ใช้กรอง id + userId พร้อมกันเพื่อกันเห็นของคนอื่น)
  • relationTodo.userId + @relation, ฝั่ง User.todos Todo[] (1—*)

Prisma 7 — จุดที่ต่างจากเวอร์ชันเก่า (และทำให้ติดบั๊ก)

Prisma 7 เปลี่ยนสถาปัตยกรรมหลายอย่างจน config เดิมใช้ไม่ได้:

  • ใช้ driver adapter — ต้องต่อ DB ผ่าน adapter โดยตรง เช่น @prisma/adapter-better-sqlite3 (เดิม Prisma จัดการ connection ให้เอง)
  • ไม่อ่าน .env ให้อัตโนมัติ ในบาง flow → ต้องส่ง connection url เองผ่าน @nestjs/config (ConfigService)
  • เป็น ESM-first → ชนกับโปรเจกต์ที่ build เป็น CommonJS (exports is not defined) แก้ด้วย moduleFormat = "cjs" ใน schema
  • generated client + build layout ต้องจัดเอง (ย้าย generated เข้า src/, exclude prisma.config.ts)

นี่คือ “ภาษีของ bleeding edge” — Prisma 7 ยังใหม่ ทำให้ tutorial เก่า ๆ ใช้ไม่ได้ ต้องอ่าน migration guide จริง

ในบริบท NestJS

  • ห่อ PrismaClient ไว้ใน PrismaService ที่ implements OnModuleInit, OnModuleDestroy เพื่อ connect()/disconnect() ตาม lifecycle ของ Nest
  • ตั้ง PrismaModule เป็น @Global() → service อื่น inject PrismaService ได้โดยไม่ต้อง import ซ้ำ

Key Points

  • Prisma = ORM แบบ type-safe + schema-first (single source of truth ในไฟล์ .prisma)
  • ต่างจาก Hibernate: แยก schema เป็นไฟล์กลาง + generate client แทนเขียน entity class
  • Flow: เขียน schema → migrate devgenerate → query
  • Prisma 7 ใช้ driver adapter + ESM-first → เป็นต้นเหตุบั๊กตอน setup กับ NestJS (CommonJS)
  • findFirst + เงื่อนไข userId = trick ทำ ownership scoping