Pemrograman

06 Query Lanjutan dengan GORM di Golang (Bagian 2)

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

  1. db.Model(&User{}) → Menentukan model yang digunakan dalam query.
  2. .Select("age, count(*) as total") → Memilih kolom age dan menghitung jumlah user dalam setiap kelompok usia.
  3. .Group("age") → Mengelompokkan hasil berdasarkan kolom age.
  4. .Having("count(*) > ?", 1) → Menyaring hasil yang memiliki lebih dari satu user dalam kelompok usia yang sama.
  5. 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

  1. Membuat database mock menggunakan SQLMock.
  2. Menentukan query yang diharapkan dijalankan oleh fungsi GetUserCountByAge.
  3. Memasukkan data hasil query yang akan dikembalikan.
  4. 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

  1. db.Joins("JOIN orders ON orders.user_id = users.id") → Melakukan join antara tabel users dan orders berdasarkan user_id.
  2. .Find(&users) → Mengambil semua data user yang memiliki order.
  3. 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

  1. Membuat database mock menggunakan SQLMock.
  2. Menentukan query yang diharapkan dijalankan oleh fungsi GetUsersWithOrders.
  3. Memasukkan data hasil query yang akan dikembalikan.
  4. 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

  1. db.Preload("Orders") → Mengambil data Orders yang berelasi dengan User.
  2. .Find(&users) → Mengambil semua data user beserta relasi Orders.
  3. 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

  1. Memanggil fungsi GetUsersWithOrdersPreloaded.
  2. Memastikan tidak ada error dalam proses query.
  3. 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

  1. db.Table("users as u") → Menggunakan alias u untuk tabel users.
  2. .Select("u.id, u.name, o.total_orders") → Memilih kolom yang akan diambil dari users dan hasil subquery.
  3. .Joins("JOIN (...) o ON o.user_id = u.id") → Menghubungkan hasil subquery sebagai tabel o ke tabel users.
  4. .Find(&results) → Mengambil hasil query.
  5. 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

  1. Memanggil fungsi GetUsersWithTotalOrders.
  2. Memastikan tidak ada error dalam proses query.
  3. 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

  1. db.Model(&User{}) → Menentukan tabel yang digunakan dalam query.
  2. .Pluck("email", &emails) → Mengambil hanya kolom email dan menyimpannya dalam slice emails.
  3. 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

  1. Membuat database mock menggunakan SQLMock.
  2. Menentukan query yang diharapkan dijalankan oleh fungsi GetUserEmails.
  3. Memasukkan data hasil query yang akan dikembalikan.
  4. 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:

comments powered by Disqus