Pelajari cara menggunakan soft delete di GORM untuk menghapus data tanpa benar-benar menghapusnya. Panduan ini mencakup contoh kode, penjelasan, dan unit test menggunakan SQLMock.
Soft delete adalah fitur yang memungkinkan penghapusan data tanpa benar-benar menghapusnya dari database. GORM menyediakan mekanisme ini dengan menambahkan kolom DeletedAt secara otomatis dalam model.
1. Soft Delete
Contoh Kode
1package main
2
3import (
4 "database/sql"
5 "fmt"
6 "testing"
7 "github.com/DATA-DOG/go-sqlmock"
8 "gorm.io/driver/postgres"
9 "gorm.io/gorm"
10 "gorm.io/gorm/clause"
11)
12
13type User struct {
14 ID uint `gorm:"primaryKey"`
15 Name string
16 DeletedAt gorm.DeletedAt `gorm:"index"`
17}
18
19func softDeleteUser(db *gorm.DB, userID uint) error {
20 result := db.Delete(&User{}, userID)
21 return result.Error
22}Penjelasan Kode
- Mendefinisikan model
Userdengan kolomDeletedAt, yang memungkinkan fitur soft delete. - Fungsi
softDeleteUserakan menghapus user berdasarkan ID dengan metodeDelete(), yang hanya menandaiDeletedAttanpa benar-benar menghapus data dari database.
Unit Test
1func TestSoftDeleteUser(t *testing.T) {
2 db, mock, _ := sqlmock.New()
3 defer db.Close()
4 gormDB, _ := gorm.Open(postgres.New(postgres.Config{Conn: db}), &gorm.Config{})
5
6 mock.ExpectExec("UPDATE users").WillReturnResult(sqlmock.NewResult(1, 1))
7
8 err := softDeleteUser(gormDB, 1)
9 if err != nil {
10 t.Errorf("Error soft deleting user: %v", err)
11 }
12}Penjelasan Kode Unit Test
- Menggunakan SQLMock untuk meniru query yang dijalankan saat melakukan soft delete.
- Melakukan mocking untuk query
UPDATE usersyang mengubah nilaiDeletedAt. - Memastikan fungsi
softDeleteUserberjalan tanpa error.
2. Menemukan Data yang Sudah Dihapus
Contoh Kode
1func findDeletedUsers(db *gorm.DB) ([]User, error) {
2 var users []User
3 result := db.Unscoped().Where("deleted_at IS NOT NULL").Find(&users)
4 return users, result.Error
5}Penjelasan Kode
- Fungsi
findDeletedUsersakan mencari data user yang telah dihapus. - Menggunakan
Unscoped()agar query dapat mengakses data dengandeleted_at IS NOT NULL.
Unit Test
1func TestFindDeletedUsers(t *testing.T) {
2 db, mock, _ := sqlmock.New()
3 defer db.Close()
4 gormDB, _ := gorm.Open(postgres.New(postgres.Config{Conn: db}), &gorm.Config{})
5
6 rows := sqlmock.NewRows([]string{"id", "name", "deleted_at"}).
7 AddRow(1, "Charlie", "2024-01-01")
8 mock.ExpectQuery("SELECT * FROM users").WillReturnRows(rows)
9
10 users, err := findDeletedUsers(gormDB)
11 if err != nil || len(users) == 0 {
12 t.Errorf("Failed to retrieve deleted users")
13 }
14}Penjelasan Kode Unit Test
- Membuat mock hasil query untuk mencari user yang memiliki
deleted_attidak null. - Menambahkan data mock berisi satu user yang dihapus.
- Menguji apakah fungsi
findDeletedUsersdapat mengambil data tersebut tanpa error.
3. Menghapus Permanen Data
Contoh Kode
1func permanentlyDeleteUser(db *gorm.DB, userID uint) error {
2 result := db.Unscoped().Delete(&User{}, userID)
3 return result.Error
4}Penjelasan Kode
- Fungsi
permanentlyDeleteUsermenggunakanUnscoped().Delete()untuk benar-benar menghapus data dari database. - Berbeda dengan soft delete, data yang dihapus dengan metode ini tidak bisa dikembalikan.
Unit Test
1func TestPermanentlyDeleteUser(t *testing.T) {
2 db, mock, _ := sqlmock.New()
3 defer db.Close()
4 gormDB, _ := gorm.Open(postgres.New(postgres.Config{Conn: db}), &gorm.Config{})
5
6 mock.ExpectExec("DELETE FROM users").WillReturnResult(sqlmock.NewResult(1, 1))
7
8 err := permanentlyDeleteUser(gormDB, 1)
9 if err != nil {
10 t.Errorf("Error permanently deleting user: %v", err)
11 }
12}Penjelasan Kode Unit Test
- Menggunakan SQLMock untuk mengekspektasikan query
DELETE FROM users. - Memastikan fungsi
permanentlyDeleteUserdijalankan tanpa error.
Kesimpulan
- Soft delete hanya menandai data sebagai dihapus tanpa benar-benar menghapusnya.
- Data yang sudah dihapus bisa ditemukan dengan
Unscoped().Where("deleted_at IS NOT NULL"). - Penghapusan permanen bisa dilakukan dengan
Unscoped().Delete(), yang akan benar-benar menghapus data dari database.
IHFollow
Ihsan Arif
Backend engineer & penulis di Santekno. Aktif menulis tentang Go, Laravel, dan arsitektur backend modern.