Pelajari cara melakukan query lanjutan di GORM dengan Golang, termasuk Group By, Join, Join Preloading, Join a Derived Table, dan Scan. Dilengkapi contoh kode dan unit test.
Artikel ini merupakan kelanjutan dari pembahasan sebelumnya tentang query lanjutan menggunakan GORM di Golang. Kali ini, kita akan membahas beberapa teknik query tambahan, yaitu Group By & Having, Join, Join Preloading, Join a Derived Table, dan Scan, lengkap dengan contoh kode dan unit test.
11. Group By & Having
Metode Group By
digunakan untuk mengelompokkan data berdasarkan kolom tertentu, sementara Having
digunakan untuk memfilter hasil setelah proses pengelompokan.
Contoh Kode Fungsi
func GetUserCountByAge(db *gorm.DB) ([]map[string]interface{}, error) {
var results []map[string]interface{}
result := db.Model(&User{}).
Select("age, count(*) as total").
Group("age").
Having("count(*) > ?", 1).
Find(&results)
return results, result.Error
}
Penjelasan Kode Fungsi
db.Model(&User{})
→ Menentukan model yang digunakan dalam query..Select("age, count(*) as total")
→ Memilih kolomage
dan menghitung jumlah user dalam setiap kelompok usia..Group("age")
→ Mengelompokkan hasil berdasarkan kolomage
..Having("count(*) > ?", 1)
→ Menyaring hasil yang memiliki lebih dari satu user dalam kelompok usia yang sama.return results, result.Error
→ Mengembalikan hasil query dan error jika ada.
Unit Test dengan SQLMock
func TestGetUserCountByAge(t *testing.T) {
db, mock, _ := sqlmock.New()
gdb, _ := gorm.Open(postgres.New(postgres.Config{Conn: db}), &gorm.Config{})
mock.ExpectQuery("SELECT age, count\(\*\) as total FROM \"users\" GROUP BY age HAVING count\(\*\) > \$1").
WithArgs(1).
WillReturnRows(sqlmock.NewRows([]string{"age", "total"}).AddRow(25, 3))
results, err := GetUserCountByAge(gdb)
assert.Nil(t, err)
assert.Greater(t, len(results), 0)
}
Penjelasan Kode Unit Test
- Membuat database mock menggunakan SQLMock.
- Menentukan query yang diharapkan dijalankan oleh fungsi
GetUserCountByAge
. - Memasukkan data hasil query yang akan dikembalikan.
- Memanggil fungsi
GetUserCountByAge
dan memverifikasi bahwa hasilnya sesuai.
12. Join
Metode Join()
digunakan untuk menghubungkan tabel yang memiliki relasi.
Contoh Kode Fungsi
func GetUsersWithOrders(db *gorm.DB) ([]User, error) {
var users []User
result := db.Joins("JOIN orders ON orders.user_id = users.id").Find(&users)
return users, result.Error
}
Penjelasan Kode Fungsi
db.Joins("JOIN orders ON orders.user_id = users.id")
→ Melakukan join antara tabelusers
danorders
berdasarkanuser_id
..Find(&users)
→ Mengambil semua data user yang memiliki order.return users, result.Error
→ Mengembalikan hasil query dan error jika ada.
Unit Test dengan SQLMock
func TestGetUsersWithOrders(t *testing.T) {
db, mock, _ := sqlmock.New()
gdb, _ := gorm.Open(postgres.New(postgres.Config{Conn: db}), &gorm.Config{})
mock.ExpectQuery("SELECT \* FROM \"users\" JOIN orders ON orders.user_id = users.id").
WillReturnRows(sqlmock.NewRows([]string{"id", "name"}).AddRow(1, "Alice"))
users, err := GetUsersWithOrders(gdb)
assert.Nil(t, err)
assert.Greater(t, len(users), 0)
}
Penjelasan Kode Unit Test
- Membuat database mock menggunakan SQLMock.
- Menentukan query yang diharapkan dijalankan oleh fungsi
GetUsersWithOrders
. - Memasukkan data hasil query yang akan dikembalikan.
- Memanggil fungsi
GetUsersWithOrders
dan memverifikasi bahwa hasilnya sesuai.
13. Join Preloading
Metode Preload()
digunakan untuk mengambil data terkait dari tabel lain secara otomatis.
Contoh Kode Fungsi
func GetUsersWithOrdersPreloaded(db *gorm.DB) ([]User, error) {
var users []User
result := db.Preload("Orders").Find(&users)
return users, result.Error
}
Penjelasan Kode Fungsi
db.Preload("Orders")
→ Mengambil dataOrders
yang berelasi denganUser
..Find(&users)
→ Mengambil semua data user beserta relasiOrders
.return users, result.Error
→ Mengembalikan hasil query dan error jika ada.
Unit Test dengan SQLMock
func TestGetUsersWithOrdersPreloaded(t *testing.T) {
users, err := GetUsersWithOrdersPreloaded(db)
assert.Nil(t, err)
assert.Greater(t, len(users), 0)
}
Penjelasan Kode Unit Test
- Memanggil fungsi
GetUsersWithOrdersPreloaded
. - Memastikan tidak ada error dalam proses query.
- Memeriksa bahwa hasil query memiliki data.
14. Join a Derived Table
Metode ini digunakan untuk melakukan join dengan subquery sebagai tabel sementara.
Contoh Kode Fungsi
func GetUsersWithTotalOrders(db *gorm.DB) ([]map[string]interface{}, error) {
var results []map[string]interface{}
result := db.Table("users as u").
Select("u.id, u.name, o.total_orders").
Joins("JOIN (SELECT user_id, COUNT(*) as total_orders FROM orders GROUP BY user_id) o ON o.user_id = u.id").
Find(&results)
return results, result.Error
}
Penjelasan Kode Fungsi
db.Table("users as u")
→ Menggunakan aliasu
untuk tabelusers
..Select("u.id, u.name, o.total_orders")
→ Memilih kolom yang akan diambil dariusers
dan hasil subquery..Joins("JOIN (...) o ON o.user_id = u.id")
→ Menghubungkan hasil subquery sebagai tabelo
ke tabelusers
..Find(&results)
→ Mengambil hasil query.return results, result.Error
→ Mengembalikan hasil query dan error jika ada.
Unit Test dengan SQLMock
func TestGetUsersWithTotalOrders(t *testing.T) {
results, err := GetUsersWithTotalOrders(db)
assert.Nil(t, err)
assert.Greater(t, len(results), 0)
}
Penjelasan Kode Unit Test
- Memanggil fungsi
GetUsersWithTotalOrders
. - Memastikan tidak ada error dalam proses query.
- Memeriksa bahwa hasil query memiliki data.
15. Scan
Metode Scan()
digunakan untuk mengambil hasil query dan memetakan ke dalam struktur data tertentu.
Contoh Kode Fungsi
func GetUserEmails(db *gorm.DB) ([]string, error) {
var emails []string
result := db.Model(&User{}).Pluck("email", &emails)
return emails, result.Error
}
Penjelasan Kode Fungsi
db.Model(&User{})
→ Menentukan tabel yang digunakan dalam query..Pluck("email", &emails)
→ Mengambil hanya kolomemail
dan menyimpannya dalam sliceemails
.return emails, result.Error
→ Mengembalikan daftar email dan error jika ada.
Unit Test dengan SQLMock
func TestGetUserEmails(t *testing.T) {
db, mock, _ := sqlmock.New()
gdb, _ := gorm.Open(postgres.New(postgres.Config{Conn: db}), &gorm.Config{})
mock.ExpectQuery("SELECT email FROM \"users\"").
WillReturnRows(sqlmock.NewRows([]string{"email"}).AddRow("alice@example.com").AddRow("bob@example.com"))
emails, err := GetUserEmails(gdb)
assert.Nil(t, err)
assert.Greater(t, len(emails), 0)
}
Penjelasan Kode Unit Test
- Membuat database mock menggunakan SQLMock.
- Menentukan query yang diharapkan dijalankan oleh fungsi
GetUserEmails
. - Memasukkan data hasil query yang akan dikembalikan.
- Memanggil fungsi
GetUserEmails
dan memverifikasi bahwa hasilnya sesuai.
Dengan menggunakan metode-metode ini, kita dapat melakukan query yang lebih kompleks dan efisien menggunakan GORM di Golang.
Untuk mempelajari lebih lanjut tentang database dalam Golang, silakan kunjungi: