Sepanjang Section ini kita menulis SQL dengan tangan: merangkai SELECT, mengisi placeholder, membungkus transaksi, lalu memetakan baris hasil menjadi object JavaScript satu per satu. Keterampilan itu tetap wajib, tetapi pada aplikasi dengan puluhan tabel, pemetaan manual berubah menjadi pekerjaan yang berulang dan rawan salah ketik. ORM — Object-Relational Mapping — mengambil alih pekerjaan pemetaan tersebut: kita mendeskripsikan data sebagai model, dan ORM yang menyusun SQL, mengikat parameter, sekaligus mengubah baris menjadi object. Chapter penutup Section ini mengenalkan Prisma, ORM paling populer di ekosistem Node.js saat ini, membedah skema serta client-nya, lalu menimbang kapan ORM layak dipilih dibanding SQL mentah.

Cara Pandang ORM #

ORM menggeser cara kita berpikir dari tabel dan baris menjadi model dan object. Tabel tugas menjadi model Tugas; satu baris menjadi satu object JavaScript; kolom menjadi property. Operasi pun berubah menjadi pemanggilan method: prisma.tugas.findMany() alih-alih SELECT * FROM tugas, dan hubungan antar tabel — tugas milik pengguna tertentu — dideklarasikan sekali di skema lalu bisa diikuti sebagai property bertingkat, tanpa menulis JOIN manual setiap kali.

Prisma mewujudkan pendekatan itu lewat tiga komponen yang saling terhubung: berkas schema.prisma sebagai deskripsi tunggal bentuk data, Prisma CLI yang menerjemahkan skema menjadi tabel di database, dan Prisma Client — kode yang di-generate — yang kita panggil dari aplikasi.

Mendeskripsikan Data dengan schema.prisma #

Semua bermula dari satu berkas skema. Berikut contoh untuk domain aplikasi tugas yang kita kenal, dengan relasi pengguna ke tugas:

prisma schema.prisma
datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

generator client {
  provider = "prisma-client-js"
}

model Pengguna {
  id    Int    @id @default(autoincrement())
  email String @unique
  nama  String
  tugas Tugas[]
}

model Tugas {
  id         Int      @id @default(autoincrement())
  judul      String
  status     String   @default("belum")
  dibuatPada DateTime @default(now())
  penggunaId Int
  pengguna   Pengguna @relation(fields: [penggunaId], references: [id])
}

Blok datasource memilih jenis database — Prisma mendukung PostgreSQL, MySQL, dan SQLite, sehingga skema ini portabel — serta membaca alamat koneksi dari variabel lingkungan DATABASE_URL, mengikuti kebiasaan .env yang kita bangun pada Chapter Koneksi PostgreSQL dengan pg. Blok generator memberi tahu Prisma cara membuat client-nya. Setiap model menjadi satu tabel: atribut @id menandai primary key, @default(autoincrement()) menyerahkan penomoran ke database, @unique menjaga kolom bebas duplikat, dan @relation mendeklarasikan foreign key penggunaId yang menunjuk ke Pengguna. Karena hubungan ini hidup di skema, Prisma tahu cara memuat tugas beserta pemiliknya tanpa JOIN tulisan tangan.

Prisma CLI #

Dua perintah CLI menjadi denyut nadi alur kerja Prisma. Instalasi dilakukan sekali di awal:

bash
npm install prisma --save-dev
npm install @prisma/client

Lalu siklus pengembangannya berjalan lewat dua perintah berikut:

bash
npx prisma migrate dev --name buat_tabel_awal
npx prisma generate

Perintah migrate dev membandingkan schema.prisma dengan keadaan database, lalu membuat berkas migrasi berisi SQL yang diperlukan dan menerapkannya — pendekatan yang sama dengan CREATE TABLE IF NOT EXISTS pada chapter-chapter sebelumnya, tetapi terdokumentasi dan bisa dibatalkan. Perintah generate membuat kode Prisma Client sesuai skema; perintah ini perlu diulang setiap kali skema berubah.

Query dengan Prisma Client #

Setelah client ter-generate, query database menjadi panggilan method yang terasa seperti JavaScript biasa:

js Operasi CRUD dengan Prisma Client
import { PrismaClient } from '@prisma/client';

const prisma = new PrismaClient();

// INSERT — create menerima object data.
const tugas = await prisma.tugas.create({
  data: { judul: 'Belajar Prisma', status: 'belum', penggunaId: 1 },
});

// SELECT dengan filter, urutan, dan batasan.
const belumSelesai = await prisma.tugas.findMany({
  where: { status: 'belum' },
  orderBy: { id: 'asc' },
  take: 10,
});

// SELECT satu baris berdasarkan primary key.
const satu = await prisma.tugas.findUnique({ where: { id: tugas.id } });

// UPDATE dengan kondisi.
await prisma.tugas.update({
  where: { id: tugas.id },
  data: { status: 'selesai' },
});

// DELETE dengan kondisi.
await prisma.tugas.delete({ where: { id: tugas.id } });

await prisma.$disconnect();

Setiap model pada skema otomatis menjadi property di client: prisma.tugas, prisma.pengguna. Argumen where menggantikan klausa WHERE, orderBy menggantikan ORDER BY, dan take menggantikan LIMIT — termasuk pola pagination yang kita rancang pada Section REST API. Karena client di-generate dari skema, editor kita mengetahui field apa saja yang ada: salah menulis where: { status: 'belUM' } atau memakai field yang tidak pernah dideklarasikan langsung ditandai sebagai error, tanpa harus menunggu query ditolak database saat aplikasi berjalan. Nilai pada data dan where dikirim sebagai parameter terikat — kebiasaan aman dari Chapter Query Parameterized tetap berlaku secara bawaan.

Bahkan transaksi — materi Chapter sebelumnya — mendapat bentuk yang ringkas:

js Transaksi dengan prisma.$transaction
const [rekeningAsal, rekeningTujuan] = await prisma.$transaction([
  prisma.rekening.update({
    where: { nomor: '001' },
    data: { saldo: { decrement: 150000 } },
  }),
  prisma.rekening.update({
    where: { nomor: '002' },
    data: { saldo: { increment: 150000 } },
  }),
]);

Array yang kita berikan ke prisma.$transaction berjalan dalam satu transaksi: seluruhnya dikomit bersama, atau seluruhnya dibatalkan bersama. Nilai { decrement: ... } dan { increment: ... } bahkan memindahkan aritmetika ke dalam UPDATE di sisi database — bukan baca-ubah-tulis dari sisi aplikasi.

ORM vs SQL Mentah #

AspekORM (Prisma)SQL mentah (pg / mysql2 / node:sqlite)
Kecepatan menulis fitur CRUDCepat — method siap pakaiLambat — query ditulis manual
Keamanan tipe dan nama kolomDiperiksa saat koding, di-generate dari skemaBaru ketahuan saat runtime
Kontrol atas SQL akhirTerbatas pada kemampuan ORMPenuh — query apa pun bisa ditulis
Query analitik kompleksTerbatas — sering jatuh kembali ke raw queryBidang aslinya
KetergantunganMenambah lapisan dan tooling sendiriLangsung ke driver

Keseimbangnya jujur: ORM memenangkan produktivitas untuk operasi CRUD sehari-hari dan aplikasi dengan banyak tabel berelasi, sementara SQL mentah unggul untuk query analitik, penyetelan performa yang presisi, dan ketergantungan minimal. Prisma sendiri menyediakan jalan tengah lewat prisma.$queryRaw untuk SQL tulisan tangan saat dibutuhkan — dokumentasi lengkapnya tersedia di prisma.io/docs .

Database kini terhubung penuh: driver, parameter, pool, transaksi, hingga ORM. Data pengguna pun mulai menumpuk — dan bersamanya muncul pertanyaan baru: siapa yang boleh membaca data ini, dan bagaimana membuktikan identitas peminta? Section Authentication dan Authorization membuka babak berikutnya dengan konsep authentication dan authorization dari nol.