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:
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:
npm install prisma --save-dev
npm install @prisma/clientLalu siklus pengembangannya berjalan lewat dua perintah berikut:
npx prisma migrate dev --name buat_tabel_awal
npx prisma generatePerintah 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:
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:
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 #
| Aspek | ORM (Prisma) | SQL mentah (pg / mysql2 / node:sqlite) |
|---|---|---|
| Kecepatan menulis fitur CRUD | Cepat — method siap pakai | Lambat — query ditulis manual |
| Keamanan tipe dan nama kolom | Diperiksa saat koding, di-generate dari skema | Baru ketahuan saat runtime |
| Kontrol atas SQL akhir | Terbatas pada kemampuan ORM | Penuh — query apa pun bisa ditulis |
| Query analitik kompleks | Terbatas — sering jatuh kembali ke raw query | Bidang aslinya |
| Ketergantungan | Menambah lapisan dan tooling sendiri | Langsung 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.