Pelajari teknik query lanjutan di GORM dengan Golang, termasuk From SubQuery, Group Conditions, Named Arguments, IN with multiple columns, dan lainnya, lengkap dengan contoh kode dan unit test.
Artikel ini merupakan lanjutan dari pembahasan sebelumnya tentang Advanced Query dengan GORM. Kali ini, kita akan melanjutkan dengan teknik lanjutan lainnya seperti Find To Map, FirstOrInit, FirstOrCreate, Optimizer/Index Hints, Iteration, lengkap dengan contoh kode dan unit test.
8. Find To Map
Metode Find To Map
digunakan untuk mengambil hasil query dan memetakannya ke dalam struktur data berbasis map. Ini berguna ketika kita ingin bekerja dengan hasil query dalam format yang lebih fleksibel.
Fungsi
func GetUsersAsMap(db *gorm.DB) ([]map[string]interface{}, error) {
var results []map[string]interface{} // Deklarasi slice untuk menyimpan hasil query dalam format map
result := db.Model(&User{}).Find(&results) // Mengambil semua data dari tabel User dan menyimpannya ke dalam map
return results, result.Error // Mengembalikan hasil query dan error jika ada
}
Penjelasan Kode
var results []map[string]interface{}
→ Deklarasi slice untuk menyimpan hasil query dalam format map.db.Model(&User{}).Find(&results)
→ Mengambil semua data dari tabel User dan menyimpannya dalam map.return results, result.Error
→ Mengembalikan hasil query dan error jika ada.
Unit Test
func TestGetUsersAsMap_Success(t *testing.T) {
results, err := GetUsersAsMap(db) // Memanggil fungsi untuk mendapatkan data user dalam format map
assert.Nil(t, err) // Memastikan tidak ada error dalam query
assert.Greater(t, len(results), 0) // Memastikan hasil query tidak kosong
}
func TestGetUsersAsMap_Error(t *testing.T) {
db, _ := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{}) // Membuka database tanpa tabel User
results, err := GetUsersAsMap(db)
assert.NotNil(t, err) // Memastikan terjadi error karena tabel tidak ditemukan
assert.Equal(t, 0, len(results)) // Memastikan hasil query kosong
}
Penjelasan Unit Test
- Memanggil
GetUsersAsMap(db)
untuk mendapatkan data dalam format map. - Memastikan tidak ada error dengan
assert.Nil(t, err)
. - Memastikan hasil query tidak kosong dengan
assert.Greater(t, len(results), 0)
. - Menguji skenario error dengan database tanpa tabel
User
untuk memastikan error terjadi.
9. FirstOrInit
Metode FirstOrInit
digunakan untuk mencari data dalam database. Jika data tidak ditemukan, maka struct akan diinisialisasi dengan nilai yang diberikan.
Fungsi
func FirstOrInitUser(db *gorm.DB, name string) User {
var user User // Deklarasi variabel user
db.Where("name = ?", name).FirstOrInit(&user, User{Name: name}) // Jika user tidak ditemukan, inisialisasi struct User dengan nama yang diberikan
return user // Mengembalikan user yang ditemukan atau diinisialisasi
}
Penjelasan Kode
var user User
→ Deklarasi variabeluser
sebagai struct User.db.Where("name = ?", name).FirstOrInit(&user, User{Name: name})
→ Mencari user denganname
yang diberikan. Jika tidak ditemukan, menginisialisasi structUser
dengan nilai default.return user
→ Mengembalikan user yang ditemukan atau diinisialisasi.
Unit Test
func TestFirstOrInitUser_Success(t *testing.T) {
user := FirstOrInitUser(db, "Alice")
assert.Equal(t, "Alice", user.Name)
}
func TestFirstOrInitUser_NewUser(t *testing.T) {
user := FirstOrInitUser(db, "Charlie")
assert.Equal(t, "Charlie", user.Name)
}
Penjelasan Unit Test
- Memanggil
FirstOrInitUser(db, "Alice")
untuk mencari atau menginisialisasi user. - Memastikan nama user sesuai dengan yang diharapkan menggunakan
assert.Equal(t, "Alice", user.Name)
. - Memastikan bahwa jika user tidak ditemukan, user baru akan diinisialisasi dengan nama yang diberikan.
10. FirstOrCreate
Metode FirstOrCreate
digunakan untuk mencari data dalam database dan membuatnya jika tidak ditemukan.
Fungsi
func FirstOrCreateUser(db *gorm.DB, name string) User {
var user User // Deklarasi variabel user
db.Where("name = ?", name).FirstOrCreate(&user, User{Name: name}) // Jika user tidak ditemukan, buat user baru dengan nama yang diberikan
return user // Mengembalikan user yang ditemukan atau dibuat
}
Penjelasan Kode
var user User
→ Deklarasi variabeluser
sebagai struct User.db.Where("name = ?", name).FirstOrCreate(&user, User{Name: name})
→ Mencari user berdasarkanname
, jika tidak ditemukan, membuat user baru denganname
yang diberikan.return user
→ Mengembalikan user yang ditemukan atau dibuat.
Unit Test
func TestFirstOrCreateUser_Success(t *testing.T) {
user := FirstOrCreateUser(db, "Bob")
assert.Equal(t, "Bob", user.Name)
}
func TestFirstOrCreateUser_NewUser(t *testing.T) {
user := FirstOrCreateUser(db, "David")
assert.Equal(t, "David", user.Name)
}
Penjelasan Unit Test
- Memanggil
FirstOrCreateUser(db, "Bob")
untuk mencari atau membuat user baru. - Memastikan bahwa jika user ditemukan, user yang ada akan dikembalikan.
- Memastikan bahwa jika user tidak ditemukan, user baru akan dibuat dengan nama yang diberikan.
11. Optimizer/Index Hints
Metode ini digunakan untuk mengoptimalkan performa query dengan memberikan petunjuk kepada database mengenai indeks yang harus digunakan.
Fungsi
func GetUsersWithIndexHint(db *gorm.DB) ([]User, error) {
var users []User // Deklarasi slice untuk menampung hasil query
result := db.Raw("SELECT * FROM users USE INDEX (idx_name)").Scan(&users) // Menjalankan query dengan hint penggunaan indeks tertentu
return users, result.Error // Mengembalikan hasil query dan error jika ada
}
Penjelasan Kode
var users []User
→ Deklarasi slice untuk menyimpan hasil query.db.Raw("SELECT * FROM users USE INDEX (idx_name)").Scan(&users)
→ Menjalankan query dengan petunjuk penggunaan indeks tertentu.return users, result.Error
→ Mengembalikan hasil query dan error jika ada.
Unit Test
func TestGetUsersWithIndexHint_Success(t *testing.T) {
users, err := GetUsersWithIndexHint(db)
assert.Nil(t, err)
}
12. Iteration
Metode ini digunakan untuk menelusuri data dalam bentuk batch kecil untuk mengurangi penggunaan memori.
Fungsi
func IterateUsers(db *gorm.DB) error {
rows, err := db.Model(&User{}).Rows() // Mengambil semua baris data user dalam bentuk iterator
if err != nil {
return err
}
defer rows.Close() // Menutup iterasi setelah selesai digunakan
for rows.Next() {
var user User // Deklarasi variabel untuk menampung hasil scan
db.ScanRows(rows, &user) // Memindai hasil dari iterator ke struct User
}
return nil
}
Penjelasan Kode
rows, err := db.Model(&User{}).Rows()
→ Mengambil semua baris data user dalam bentuk iterator.defer rows.Close()
→ Menutup iterasi setelah selesai digunakan untuk menghindari kebocoran memori.for rows.Next()
→ Melakukan iterasi pada setiap baris hasil query.var user User
→ Deklarasi variabel untuk menampung hasil scan.db.ScanRows(rows, &user)
→ Memindai hasil dari iterator ke structUser
.
Unit Test
func TestIterateUsers_Success(t *testing.T) {
err := IterateUsers(db)
assert.Nil(t, err)
}
Lanjutkan membaca untuk pembahasan FindInBatches, Query Hooks, Pluck, Scopes, dan Count.
Untuk informasi lebih lanjut, kunjungi: