← Semua pembelajaran / Astro Nol β†’ Portal Berita
Fase 2 Β· MySQL dengan Kysely

Kenapa Kysely, bukan ORM

Temanmu benar menyarankan Kysely, tapi alasannya perlu diluruskan: Kysely mirip Query Builder CI3, bukan Active Record Laravel. Dan perbedaan itu justru menguntungkanmu.

Sumber asli kysely.dev Resmi Rangkuman ~9 menit baca

Intisari

  • Kysely adalah query builder bertipe, bukan ORM. Tidak ada objek model, tidak ada lazy loading, tidak ada $artikel->save().
  • Bentuknya nyaris identik dengan $this->db->select()->where()->get() di CI3 β€” kurva belajarnya pendek.
  • Bedanya: nama tabel dan nama kolom diperiksa compiler. Salah ketik gagal di editor, bukan di produksi.
  • SQL yang dihasilkan bisa ditebak dari kodenya. Tidak ada kueri kejutan seperti di ORM dengan relasi malas.
  • Yang tidak kamu dapat: migrasi otomatis dari model, relasi ajaib, dan seeding. Sebagian besar itu tidak kamu butuhkan untuk skema warisan.

Meluruskan istilahnya

Ada tiga hal berbeda yang sering disebut bergantian:

PolaContohCiri
Active Record Eloquent (Laravel), Rails Baris database adalah objek. $a->judul = 'x'; $a->save();
Data Mapper / ORM Prisma, TypeORM, Doctrine Objek terpisah dari baris; ada lapisan pemetaan dan sering ada cache identitas
Query Builder Kysely, CI3 Query Builder, Laravel DB facade Kamu menyusun SQL lewat method. Hasilnya baris biasa, bukan objek berperilaku

CI3 menamai fiturnya "Active Record" di dokumentasi lama, lalu menggantinya jadi "Query Builder" di CI3 β€” karena nama pertamanya memang keliru. Yang selama ini kamu pakai adalah query builder. Kysely juga query builder. Perpindahannya bukan perubahan paradigma; ia perubahan sintaks plus penambahan tipe.

Berdampingan

// CodeIgniter 3
$this->db->select('a.id, a.judul, k.nama AS kategori')
         ->from('artikel a')
         ->join('kategori k', 'k.id = a.kategori_id', 'left')
         ->where('a.status', 'terbit')
         ->where('a.terbit_pada <=', date('Y-m-d H:i:s'))
         ->order_by('a.terbit_pada', 'DESC')
         ->limit(20);

$artikel = $this->db->get()->result();
// Kysely
const artikel = await db
  .selectFrom("artikel as a")
  .leftJoin("kategori as k", "k.id", "a.kategori_id")
  .select(["a.id", "a.judul", "k.nama as kategori"])
  .where("a.status", "=", "terbit")
  .where("a.terbit_pada", "<=", new Date())
  .orderBy("a.terbit_pada", "desc")
  .limit(20)
  .execute();

Baris demi baris hampir sama. Perbedaannya yang penting tidak terlihat di layar:

Kalau kamu salah ketik…CI3Kysely
'a.judl'Error MySQL saat runtime, di produksiGaris merah di editor
'artikl'Error MySQL saat runtimeGaris merah di editor
Lupa status = 'terbit'Draf tersaji ke publik, diam-diamSama β€” tipe tidak menolongmu di sini (lihat Fase 0)
Membandingkan kolom int dengan stringMySQL diam-diam mengonversiError tipe

Dan hasilnya bertipe. artikel[0].kategori diketahui compiler sebagai string | null β€” null karena itu leftJoin. Kysely menurunkan nullability dari jenis join-nya, dan itu menangkap kelas bug yang di CI3 baru muncul saat ada artikel tanpa kategori.

Kenapa bukan Prisma atau Drizzle

KyselyPrismaDrizzle
Cocok untuk skema warisanSangat β€” introspeksi, tanpa menuntut bentuk tertentuBisa, tapi skemanya jadi sumber kebenaranBisa
SQL bisa ditebak dari kodeYa, satu banding satuTidak selaluSebagian besar ya
Runtime tambahanTidak adaDulu ada engine binerTidak ada
Kurva belajar dari CI3Paling landaiKonsep baru: model, relasi, generatorLandai
SQL mentah saat perluMulus lewat sqlAda, terasa terpisahMulus
Ukuran bundelKecilBesarKecil

Untuk migrasi dari skema CI3 yang sudah berjalan bertahun-tahun, alasan pertama itu menentukan. Skemamu punya kolom yang tidak konsisten penamaannya, tabel tanpa foreign key, dan kolom int(11) berisi timestamp Unix. Kysely tidak peduli β€” ia mengambil bentuk skemamu apa adanya lewat introspeksi. ORM yang menuntut model rapi akan memaksamu melawan skemamu sendiri di hari pertama.

Ini bukan penilaian bahwa Prisma buruk. Untuk proyek baru dengan skema yang kamu rancang sendiri, Prisma memberi banyak hal yang Kysely tidak. Tapi kamu tidak sedang membangun proyek baru β€” kamu sedang memindahkan portal yang sudah hidup, dan yang paling kamu butuhkan adalah alat yang tidak berpendapat tentang skema.

Yang tidak kamu dapat, dan apa gantinya

Tidak ada di KyselyGantinya
$artikel->kategori->nama (relasi malas)join eksplisit, atau jsonArrayFrom untuk relasi bersarang
Model dengan methodFungsi di src/lib/artikel.ts
Timestamp otomatisTulis sendiri, atau DEFAULT CURRENT_TIMESTAMP di kolomnya
Soft deleteKolom dihapus_pada plus fungsi yang selalu menyaringnya
SeedingSkrip biasa yang memakai db

Baris pertama itu sebenarnya keuntungan. Relasi malas adalah sumber masalah N+1 yang paling umum: satu loop yang menyentuh $a->kategori diam-diam menghasilkan satu kueri per artikel. Di Kysely kamu tidak bisa melakukan itu tanpa sadar β€” kalau kamu butuh kategori, kamu menulis join-nya.

Struktur berkas yang dipakai

src/lib/
β”œβ”€β”€ db.ts             # instance Kysely + pool. Satu untuk seluruh aplikasi
β”œβ”€β”€ db-types.ts       # DIGENERATE oleh kysely-codegen. Jangan disunting
β”œβ”€β”€ artikel.ts        # fungsi kueri artikel
β”œβ”€β”€ perusahaan.ts
└── member.ts

Satu aturan yang berlaku sepanjang roadmap: hanya berkas di src/lib/ yang boleh mengimpor db. Halaman dan komponen memanggil fungsi, bukan menyusun kueri. Alasannya di Fase 0: supaya filter status = 'terbit' tidak bisa terlupa, dan supaya cache serta pengukuran bisa dipasang di satu tempat.

Latihan: ambil tiga kueri paling sering dipakai dari model CI3-mu. Tulis ulang ketiganya sebagai Kysely di kertas atau berkas teks β€” belum perlu dijalankan. Catat setiap tempat di mana kamu ragu bentuk padanannya; daftar itu akan jadi peta belajarmu untuk materi-materi berikutnya di fase ini.

Rangkuman ini sengaja dipangkas ke bagian yang dipakai di roadmap. Buka sumber aslinya saat kamu butuh detail lengkap atau referensi parameter.