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
package main
import (
"database/sql"
"fmt"
"testing"
"github.com/DATA-DOG/go-sqlmock"
"gorm.io/driver/postgres"
"gorm.io/gorm"
"gorm.io/gorm/clause"
)
type User struct {
ID uint `gorm:"primaryKey"`
Name string
DeletedAt gorm.DeletedAt `gorm:"index"`
}
func softDeleteUser(db *gorm.DB, userID uint) error {
result := db.Delete(&User{}, userID)
return result.Error
}
Penjelasan Kode
- Mendefinisikan model
User
dengan kolomDeletedAt
, yang memungkinkan fitur soft delete. - Fungsi
softDeleteUser
akan menghapus user berdasarkan ID dengan metodeDelete()
, yang hanya menandaiDeletedAt
tanpa benar-benar menghapus data dari database.
Unit Test
func TestSoftDeleteUser(t *testing.T) {
db, mock, _ := sqlmock.New()
defer db.Close()
gormDB, _ := gorm.Open(postgres.New(postgres.Config{Conn: db}), &gorm.Config{})
mock.ExpectExec("UPDATE users").WillReturnResult(sqlmock.NewResult(1, 1))
err := softDeleteUser(gormDB, 1)
if err != nil {
t.Errorf("Error soft deleting user: %v", err)
}
}
Penjelasan Kode Unit Test
- Menggunakan SQLMock untuk meniru query yang dijalankan saat melakukan soft delete.
- Melakukan mocking untuk query
UPDATE users
yang mengubah nilaiDeletedAt
. - Memastikan fungsi
softDeleteUser
berjalan tanpa error.
2. Menemukan Data yang Sudah Dihapus
Contoh Kode
func findDeletedUsers(db *gorm.DB) ([]User, error) {
var users []User
result := db.Unscoped().Where("deleted_at IS NOT NULL").Find(&users)
return users, result.Error
}
Penjelasan Kode
- Fungsi
findDeletedUsers
akan mencari data user yang telah dihapus. - Menggunakan
Unscoped()
agar query dapat mengakses data dengandeleted_at IS NOT NULL
.
Unit Test
func TestFindDeletedUsers(t *testing.T) {
db, mock, _ := sqlmock.New()
defer db.Close()
gormDB, _ := gorm.Open(postgres.New(postgres.Config{Conn: db}), &gorm.Config{})
rows := sqlmock.NewRows([]string{"id", "name", "deleted_at"}).
AddRow(1, "Charlie", "2024-01-01")
mock.ExpectQuery("SELECT * FROM users").WillReturnRows(rows)
users, err := findDeletedUsers(gormDB)
if err != nil || len(users) == 0 {
t.Errorf("Failed to retrieve deleted users")
}
}
Penjelasan Kode Unit Test
- Membuat mock hasil query untuk mencari user yang memiliki
deleted_at
tidak null. - Menambahkan data mock berisi satu user yang dihapus.
- Menguji apakah fungsi
findDeletedUsers
dapat mengambil data tersebut tanpa error.
3. Menghapus Permanen Data
Contoh Kode
func permanentlyDeleteUser(db *gorm.DB, userID uint) error {
result := db.Unscoped().Delete(&User{}, userID)
return result.Error
}
Penjelasan Kode
- Fungsi
permanentlyDeleteUser
menggunakanUnscoped().Delete()
untuk benar-benar menghapus data dari database. - Berbeda dengan soft delete, data yang dihapus dengan metode ini tidak bisa dikembalikan.
Unit Test
func TestPermanentlyDeleteUser(t *testing.T) {
db, mock, _ := sqlmock.New()
defer db.Close()
gormDB, _ := gorm.Open(postgres.New(postgres.Config{Conn: db}), &gorm.Config{})
mock.ExpectExec("DELETE FROM users").WillReturnResult(sqlmock.NewResult(1, 1))
err := permanentlyDeleteUser(gormDB, 1)
if err != nil {
t.Errorf("Error permanently deleting user: %v", err)
}
}
Penjelasan Kode Unit Test
- Menggunakan SQLMock untuk mengekspektasikan query
DELETE FROM users
. - Memastikan fungsi
permanentlyDeleteUser
dijalankan 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.