Desain Skema Prisma

Desain Skema Prisma

Saatnya merancang 'cetakan' databasemu! Pelajari sintaks Prisma Schema Language (PSL) untuk mendefinisikan model data (tabel), field, tipe data, atribut field (seperti ID, default, unik), dan relasi antar model.

Jadi Arsitek Database: Rancang Model Datamu Pake Prisma Schema!

Udah berhasil nyiapin "toko" Prisma di proyekmu dengan prisma init? Keren! Sekarang, kita bakal jadi arsitek yang ngerancang "ruangan-ruangan" dan "perabotan" di dalem "toko data" kita. Di Prisma, semua rancangan ini kita tuangin ke dalem satu file utama: prisma/schema.prisma.

File schema.prisma ini adalah jantung dari penggunaan Prisma. Di sinilah kamu bakal ngedefinisiin:

  • Sumber Data (Datasource): Database apa yang kamu pake dan gimana cara nyambungnya. (Ini udah kita sentuh sedikit pas setup SQLite).
  • Generator Klien (Client Generator): Ngasih tau Prisma buat nge-generate Prisma Client yang type-safe.
  • Model Data (Data Models): Ini yang paling penting! Model data ini ngewakilin tabel-tabel di databasemu, kolom-kolom (field) di tiap tabel, tipe data tiap kolom, dan hubungan (relasi) antar tabel.

Kita bakal nulis semua ini pake bahasa khusus yang simpel dan gampang dibaca namanya Prisma Schema Language (PSL).

Ngintip Lagi schema.prisma Kita

Buka file prisma/schema.prisma yang udah di-generate sebelumnya. Isinya kurang lebih kayak gini (kalau kita udah ubah ke SQLite):

prismaprisma
// prisma/schema.prisma
 
generator client {
  provider = "prisma-client-js"
}
 
datasource db {
  provider = "sqlite" // Kita udah set ini ke sqlite
  url      = env("DATABASE_URL") // Ngambil dari file .env
}
 
// Model-model data kita bakal ditulis di bawah sini
  • generator client { ... }: Bagian ini ngasih tau Prisma buat nge-generate Prisma Client dalam bahasa JavaScript (yang bisa dipake di TypeScript juga). Prisma Client ini yang nanti kita pake di kode aplikasi kita buat ngobrol sama database.
  • datasource db { ... }: Bagian ini ngedefinisiin koneksi ke database kita.
    • provider = "sqlite": Kita pake SQLite. Bisa juga postgresql, mysql, dll.
    • url = env("DATABASE_URL"): String koneksi diambil dari variabel DATABASE_URL di file .env kita (yang udah kita set ke file:./dev.db atau file:./prisma/dev.db).

Mendesain Model Data: "Cetakan" Tabelmu

Sekarang bagian paling serunya: bikin Model. Di PSL, satu model itu biasanya ngewakilin satu tabel di database relasionalmu.

  • Sintaks Dasar Model:
    prismaprisma
    model NamaModel {
      namaField1  TipeData1  @atributField1 @atributField2
      namaField2  TipeData2  // Properti tanpa atribut juga bisa
      // ... field lain ...
     
      // Untuk relasi (dibahas nanti)
      // namaRelasi NamaModelRelasi @relation(...) 
    }
    • model NamaModel: Keyword model diikuti nama modelmu (biasanya diawali huruf besar dan pake PascalCase, misal User, ProductOrder). Nama model ini bakal jadi nama tabel di database (Prisma bisa ngatur konvensi penamaan tabelnya, misal jadi users atau product_orders).
    • namaField TipeData: Tiap baris di dalem model ngedefinisiin satu field (kolom) beserta tipe datanya.
      • namaField: Nama kolom (biasanya camelCase, misal firstName, createdAt).
      • TipeData: Tipe data buat kolom itu.

Tipe Data Dasar di Prisma Schema Language (PSL)

PSL punya tipe data dasar yang bakal nge-map ke tipe data spesifik di databasemu:

  • String: Buat teks (VARCHAR, TEXT, dll. tergantung database).
  • Int: Buat angka integer (INT, INTEGER).
  • BigInt: Buat angka integer yang gede banget.
  • Float: Buat angka desimal (FLOAT, REAL, DOUBLE).
  • Decimal: Buat angka desimal dengan presisi tinggi (DECIMAL, NUMERIC), cocok buat data keuangan.
  • Boolean: Buat nilai true atau false (BOOLEAN, BIT).
  • DateTime: Buat nyimpen tanggal dan waktu (TIMESTAMP, DATETIME).
  • Json: Buat nyimpen data JSON langsung di satu kolom (JSON, JSONB di PostgreSQL).
  • Bytes: Buat data biner.

Modifier Tipe:

  • ? (Opsional): Tambahin ? setelah tipe data buat nandain kalau field itu boleh NULL (opsional, gak wajib diisi). Contoh: deskripsi String?
  • [] (List/Array): Tambahin [] setelah tipe data buat nandain kalau field itu adalah array/list dari tipe tersebut. Penting: Gak semua database ngedukung tipe array secara native di kolom. Prisma bisa nyimulasiin ini, tapi perilakunya tergantung provider database. (Misal, String[] di PostgreSQL itu array beneran, di MySQL mungkin jadi JSON atau cara lain).

Atribut Field (@ dan @@)

Selain nama dan tipe, field juga bisa punya atribut buat ngasih "sifat" atau "aturan" tambahan. Atribut field diawali satu @, atribut level model (blok) diawali dua @@.

Beberapa atribut field yang paling sering dipake:

  • @id: Nandain kalau field itu adalah Primary Key buat tabel/model itu. Biasanya dipake di field id.
  • @default(nilai_atau_fungsi): Nentuin nilai default buat field itu kalau gak diisi pas bikin data baru.
    • Contoh: status String @default("pending"), createdAt DateTime @default(now()), poin Int @default(0), uuid String @default(uuid()) (butuh fungsi uuid() dari database atau Prisma).
  • @unique: Nandain kalau nilai di field itu harus unik di seluruh tabel (gak boleh ada yang sama). Cocok buat email, username.
  • @updatedAt: Otomatis ngeset field (yang tipenya DateTime) ke waktu saat ini setiap kali record itu di-update. Berguna buat ngelacak kapan data terakhir diubah.
  • @map("nama_kolom_di_db"): Kalau kamu mau nama field di model Prismamu beda sama nama kolom di database benerannya.
  • @relation(...): Ini dipake buat ngedefinisiin relasi antar model. Bakal kita bahas lebih detail.

Contoh Model User dan Post Sederhana:

prismaprisma
// prisma/schema.prisma
// ... (generator dan datasource masih sama) ...
 
model User {
  id        Int      @id @default(autoincrement()) // Primary Key, auto-increment (beda per DB)
  email     String   @unique // Email harus unik
  nama      String?  // Nama boleh kosong (opsional)
  password  String   // Password wajib ada (nantinya di-hash ya!)
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
 
  // Relasi: Satu User bisa punya banyak Post
  posts Post[] 
}
 
model Post {
  id        Int      @id @default(autoincrement())
  judul     String
  konten    String?
  dipublikasi Boolean  @default(false)
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
 
  // Relasi: Satu Post dimiliki oleh satu User
  author    User     @relation(fields: [authorId], references: [id])
  authorId  Int      // Foreign Key ke tabel User
}

Bedah Contoh:

  • User Model:

    • id: Tipe Int, jadi Primary Key (@id), dan nilainya di-generate otomatis sama database pas data baru dibuat (@default(autoincrement())). (Sintaks autoincrement bisa beda dikit antar database, misal uuid() buat ID string unik).
    • email: String, wajib unik.
    • nama: String, opsional (?).
    • createdAt: DateTime, otomatis diisi waktu saat ini pas User dibuat.
    • updatedAt: DateTime, otomatis diupdate tiap kali User diubah.
    • posts Post[]: Ini field relasi. Nunjukin kalau satu User bisa punya banyak ([]) record dari model Post. Prisma pinter, dia bakal ngerti ini relasi one-to-many.
  • Post Model:

    • id, judul, konten, dipublikasi, createdAt, updatedAt: Mirip kayak di User.
    • author User @relation(fields: [authorId], references: [id]): Ini juga field relasi.
      • author User: Nunjukin kalau satu Post itu "milik" satu User.
      • @relation(...): Ngasih detail soal relasinya.
        • fields: [authorId]: Ngasih tau Prisma kalau field authorId di model Post ini yang jadi foreign key.
        • references: [id]: Ngasih tau Prisma kalau authorId itu ngacunya ke field id di model User.
    • authorId Int: Ini field foreign key benerannya yang nyimpen id dari User pemilik post ini. Tipe datanya harus sama kayak id di User.

Dengan ngedefinisiin relasi kayak gini, Prisma Client nanti bakal ngasih kita cara gampang buat ngambil data user beserta semua post-nya, atau sebaliknya.

Mendesain Relasi Lebih Lanjut

Prisma ngedukung semua jenis relasi database umum:

  • One-to-One (1-1): Misal, satu User punya satu Profile.

    prismaprisma
    model User {
      id      Int     @id @default(autoincrement())
      profile Profile? // Profile opsional, dan unik per User
    }
    model Profile {
      id     Int    @id @default(autoincrement())
      bio    String?
      user   User   @relation(fields: [userId], references: [id])
      userId Int    @unique // userId di Profile harus unik, nandain 1-1
    }
  • One-to-Many (1-N): Udah kita liat di contoh User dan Post. Satu User -> Banyak Post. Satu Post -> Satu User.

  • Many-to-Many (N-M): Misal, satu Post bisa punya banyak Category, dan satu Category bisa dipake di banyak Post.

    • Cara Implisit (Prisma yang bikinin tabel join):
      prismaprisma
      model Post {
        id         Int        @id @default(autoincrement())
        judul      String
        categories Category[] // Post punya banyak Category
      }
      model Category {
        id    Int    @id @default(autoincrement())
        nama  String @unique
        posts Post[] // Category dipake di banyak Post
      }
      // Prisma bakal otomatis bikin tabel join di belakang layar (_CategoryToPost)
    • Cara Eksplisit (Kita definisiin tabel join-nya sendiri): Kadang kita butuh nambahin info ekstra di tabel join (misal, tanggal kapan post ditambahin ke kategori).
      prismaprisma
      model Post {
        id          Int              @id @default(autoincrement())
        judul       String
        kategoriDiPost KategoriDiPost[] // Ngacu ke model tabel join
      }
      model Category {
        id          Int              @id @default(autoincrement())
        nama        String           @unique
        postDiKategori KategoriDiPost[] // Ngacu ke model tabel join
      }
      model KategoriDiPost { // Ini model tabel join-nya
        post       Post     @relation(fields: [postId], references: [id])
        postId     Int
        kategori   Category @relation(fields: [kategoriId], references: [id])
        kategoriId Int
        ditugaskanPada DateTime @default(now()) // Info tambahan di tabel join
       
        @@id([postId, kategoriId]) // Primary key gabungan
      }

Milih antara implisit atau eksplisit buat many-to-many tergantung kebutuhan. Kalau gak butuh field ekstra di tabel join, implisit lebih simpel.

Atribut Level Model (Blok) @@

Selain atribut field (@), ada juga atribut yang diterapin ke seluruh model (blok), diawali dua @@.

  • @@id([...]): Buat bikin composite primary key (primary key yang terdiri dari beberapa field).
  • @@unique([...]): Buat bikin composite unique constraint (kombinasi beberapa field harus unik).
  • @@index([...]): Buat nambahin indeks database ke beberapa field (buat percepat query).
  • @@map("nama_tabel_di_db"): Kalau mau nama model beda sama nama tabel di database.

Contoh di model KategoriDiPost tadi: @@id([postId, kategoriId]).


File schema.prisma ini adalah "cetak biru" buat seluruh struktur databasemu. Dengan Prisma Schema Language (PSL) yang deklaratif dan gampang dibaca, kamu bisa ngedesain model data dan relasinya dengan jelas.

Uji Pemahamanmu!

Memeriksa status login...