Skip to content

Kontrak Repositori di Garisan SQL

Adityo Guni Waluyo

Uji integrasi mengunci kontrak repositori di batas SQL: pemetaan error 1062, visibilitas soft delete, clamp paginasi, dan pelajaran parameter marker MySQL.

Ringkasan

Awalnya nulis fungsi seed data, karena binding SQL expression buat deleted_at, kuerinya gagal diam-diam tanpa error. Ternyata placeholder prepared statement cuma nampung nilai data, bukan ekspresi SQL, jadi solusinya pecah jadi dua cabang query dan panggil fungsi waktu langsung. Sekarang kontrak repo dikunci pake uji integrasi MySQL beneran, termasuk mapping error 1062 ke ErrSlugTaken pake errors.Is.

Saat menulis fungsi pembantu untuk seed data pada repositori pengumuman di KotaPortal, proses penyisipan baris yang sudah dihapus gagal secara diam-diam. Fungsi tersebut mencoba mengikat nilai waktu saat ini sebagai parameter string literal pada kolom deleted_at. Eksekusi kueri tidak menghasilkan error dari mesin basis data, namun baris tidak terhapus sesuai ekspektasi. Kolom deleted_at berisi string mentah, bukan penanda waktu.

Asumsi awal: mesin basis data akan mengevaluasi string tersebut sebagai fungsi waktu saat eksekusi berlangsung. Pendekatan itu mengandalkan binding parameter untuk "menyuntikkan" ekspresi SQL ke dalam prepared statement.

Dokumentasi resmi prepared statement MySQL menyatakan fakta yang berbeda. Penanda parameter hanya berfungsi sebagai posisi nilai data, "not for SQL keywords, identifiers, and so forth" [3]. Mengikat ekspresi SQL sebagai string adalah akar kegagalan. Solusinya membutuhkan dua cabang SQL terpisah: satu untuk penyisipan baris aktif, satu lagi untuk baris terhapus yang memanggil fungsi waktu langsung di dalam kueri, bukan sebagai parameter terikat.

Perbaikan ini mengubah cara proyek memandang lapisan akses data. Kontrak repositori tidak lagi hidup sebagai asumsi di kepala pengembang, melainkan terkunci dalam suite uji integrasi. File uji menjadi spesifikasi yang dapat dieksekusi mesin secara otomatis.

Pemetaan Error di Batas SQL

Uji integrasi berjalan melalui testutil.SetupTestDB pada MySQL sungguhan, bukan mock. Ketika terjadi pelanggaran unik pada slug, driver MySQL mengembalikan ER_DUP_ENTRY, kode error 1062, SQLSTATE 23000, dengan pesan "Duplicate entry '%s' for key %d" [4]. Lapisan repositori menerjemahkan error driver mentah ini menjadi sentinel ErrSlugTaken yang bisa dibaca lapisan aplikasi di atasnya.

Perbandingan error di sisi Go memakai errors.Is, bukan operator ==. Panduan resmi Go 1.13 menyebut pola ini sebagai cara memeriksa error yang telah dibungkus konteks [1]. Lapisan repositori sering membungkus error driver dengan informasi tambahan, dan errors.Is tetap mengenali sentinel di balik pembungkus tersebut.

Siklus Hidup yang Dikunci Uji

Spesifikasi visibilitas data dikunci dalam file repository_lifecycle_test.go. Daftar default menyembunyikan baris yang kolom penghapusnya terisi. Tampilan khusus data terhapus tetap menampilkannya untuk keperluan administrasi. Upaya menghapus ganda pada entri yang sama mengembalikan ErrNotFound. Pengurutan daftar admin punya whitelist kolom dengan fallback ke urutan terbaru bila kolom yang diminta tidak dikenali. Paginasi menerapkan clamp: halaman di bawah satu atau limit di luar rentang wajar dikoreksi ke default yang aman, mencegah beban kueri berlebih dari permintaan yang tidak valid.

Pengemasan paket testing Go menetapkan kontraknya: T.Error dan metode terkait menandai kegagalan [2]. Satu asersi di suite ini awalnya bergantung pada urutan eksekusi yang rapuh. Komit perbaikan menambahkan t.Fatalf sebelum melakukan dereferensi elemen slice, mencegah panic saat slice kosong. Fungsi t.Helper juga ditandai pada scaffolding agar laporan kegagalan menunjuk ke baris pemanggil, buka ke dalam fungsi pembantu.

Spesifikasi ini memastikan setiap perubahan pada lapisan basis data terverifikasi otomatis. Ketika logika berubah, suite uji gagal dan menunjuk aturan mana yang dilanggar. Pengembang tidak perlu menebak dampak perubahan kueri karena batas perilaku sudah dijaga kode uji itu sendiri.

Satu pengamatan terakhir dari commit perbaikan: kontrak yang paling sering dilanggar justru yang paling sederhana. Slug duplikat sudah ditangani constraint UNIQUE di database sejak hari pertama, namun tanpa uji yang memetakan error 1062 ke sentinel yang tepat, setiap pemanggil bebas menebak arti error mentah tersebut. Uji integrasi mengakhiri tebakan itu.

Sumber

Artikel terkait