Pemrograman

08 Advanced Query dengan GORM di Golang

Pelajari berbagai teknik query tingkat lanjut di GORM dengan Golang, termasuk Smart Select Fields, Locking, SubQuery, From SubQuery, dan lainnya. Dilengkapi contoh kode dan unit test.

Dalam artikel ini, kita akan membahas berbagai teknik query tingkat lanjut menggunakan GORM di Golang. Topik-topik yang dibahas meliputi Smart Select Fields, Locking, SubQuery, From SubQuery, Group Conditions, IN with multiple columns, Named Argument, Find To Map, FirstOrInit, FirstOrCreate, Optimizer/Index Hints, Iteration, FindInBatches, Query Hooks, Pluck, Scopes, dan Count.


1. Smart Select Fields

Metode Select() digunakan untuk memilih field tertentu dalam query agar lebih efisien.

Contoh Kode Fungsi

func GetUserNames(db *gorm.DB) ([]string, error) {
    var names []string
    result := db.Model(&User{}).Select("name").Pluck("name", &names)
    return names, result.Error
}

Penjelasan Kode

  1. db.Model(&User{}) → Menentukan model User sebagai sumber data.
  2. .Select("name").Pluck("name", &names) → Memilih hanya kolom name dan menyimpannya dalam slice names.
  3. return names, result.Error → Mengembalikan daftar nama dan error jika ada.

Unit Test

func TestGetUserNames(t *testing.T) {
    names, err := GetUserNames(db)
    assert.Nil(t, err)
    assert.Greater(t, len(names), 0)
}

Penjelasan Unit Test

  1. Memanggil GetUserNames(db) untuk mendapatkan daftar nama user.
  2. Memastikan tidak ada error dengan assert.Nil(t, err).
  3. Memastikan jumlah nama yang dikembalikan lebih dari nol dengan assert.Greater(t, len(names), 0).

2. Locking

Metode Locking digunakan untuk mengunci record agar tidak diubah oleh transaksi lain selama proses berlangsung.

Contoh Kode Fungsi

func LockUserRecord(db *gorm.DB, id uint) (*User, error) {
    var user User
    result := db.Clauses(clause.Locking{Strength: "UPDATE"}).First(&user, id)
    return &user, result.Error
}

Penjelasan Kode

  1. db.Clauses(clause.Locking{Strength: "UPDATE"}) → Menambahkan klausa locking pada query.
  2. .First(&user, id) → Mengambil record user berdasarkan id.
  3. return &user, result.Error → Mengembalikan user yang ditemukan dan error jika ada.

Unit Test

func TestLockUserRecord(t *testing.T) {
    user, err := LockUserRecord(db, 1)
    assert.Nil(t, err)
    assert.NotNil(t, user)
}

Penjelasan Unit Test

  1. Memanggil LockUserRecord(db, 1) untuk mengunci user dengan ID 1.
  2. Memastikan tidak ada error dengan assert.Nil(t, err).
  3. Memastikan user yang dikembalikan tidak nil dengan assert.NotNil(t, user).

3. SubQuery

Metode SubQuery digunakan untuk menyusun query dalam query utama, biasanya digunakan untuk filtering yang kompleks.

Contoh Kode Fungsi

func GetLatestUsers(db *gorm.DB) ([]User, error) {
    var users []User
    subQuery := db.Model(&User{}).Select("MAX(created_at)").Group("id")
    result := db.Where("created_at IN (?)", subQuery).Find(&users)
    return users, result.Error
}

Penjelasan Kode

  1. subQuery := db.Model(&User{}).Select("MAX(created_at)").Group("id") → Membuat subquery untuk mendapatkan waktu pembuatan terbaru.
  2. db.Where("created_at IN (?)", subQuery).Find(&users) → Mengambil user dengan created_at terbaru dari subquery.
  3. return users, result.Error → Mengembalikan hasil query dan error jika ada.

Unit Test

func TestGetLatestUsers(t *testing.T) {
    users, err := GetLatestUsers(db)
    assert.Nil(t, err)
    assert.Greater(t, len(users), 0)
}

Penjelasan Unit Test

  1. Memanggil GetLatestUsers(db) untuk mendapatkan daftar user terbaru.
  2. Memastikan tidak ada error dengan assert.Nil(t, err).
  3. Memastikan jumlah user yang dikembalikan lebih dari nol dengan assert.Greater(t, len(users), 0).

4. From SubQuery

Metode From SubQuery digunakan untuk menyusun query berdasarkan hasil dari subquery lain yang dijalankan sebelumnya.

Contoh Kode Fungsi

func GetUsersFromSubQuery(db *gorm.DB) ([]User, error) {
    var users []User
    subQuery := db.Model(&User{}).Select("id").Where("age > ?", 25)
    result := db.Where("id IN (?)", subQuery).Find(&users)
    return users, result.Error
}

Penjelasan Kode

  1. subQuery := db.Model(&User{}).Select("id").Where("age > ?", 25) → Membuat subquery untuk mendapatkan ID user dengan usia di atas 25 tahun.
  2. db.Where("id IN (?)", subQuery).Find(&users) → Mengambil user berdasarkan ID yang didapat dari subquery.
  3. return users, result.Error → Mengembalikan daftar user dan error jika ada.

Unit Test

func TestGetUsersFromSubQuery(t *testing.T) {
    users, err := GetUsersFromSubQuery(db)
    assert.Nil(t, err)
    assert.Greater(t, len(users), 0)
}

Penjelasan Unit Test

  1. Memanggil fungsi GetUsersFromSubQuery(db) untuk mendapatkan daftar user.
  2. Memastikan tidak ada error dengan assert.Nil(t, err).
  3. Memastikan jumlah user lebih dari nol dengan assert.Greater(t, len(users), 0).

5. Group Conditions

Metode Group By digunakan untuk mengelompokkan hasil berdasarkan suatu kolom tertentu.

Contoh Kode Fungsi

func GetUserCountGroupedByAge(db *gorm.DB) ([]map[string]interface{}, error) {
    var results []map[string]interface{}
    result := db.Model(&User{}).
        Select("age, count(*) as total").
        Group("age").
        Find(&results)
    return results, result.Error
}

Unit Test

func TestGetUserCountGroupedByAge(t *testing.T) {
    results, err := GetUserCountGroupedByAge(db)
    assert.Nil(t, err)
    assert.Greater(t, len(results), 0)
}

6. IN with Multiple Columns

Metode ini digunakan untuk melakukan query dengan kondisi IN pada lebih dari satu kolom.

Contoh Kode Fungsi

func GetUsersWithMultiColumnCondition(db *gorm.DB) ([]User, error) {
    var users []User
    result := db.Where("(name, age) IN ((?, ?), (?, ?))", "Alice", 30, "Bob", 25).Find(&users)
    return users, result.Error
}

Unit Test

func TestGetUsersWithMultiColumnCondition(t *testing.T) {
    users, err := GetUsersWithMultiColumnCondition(db)
    assert.Nil(t, err)
    assert.Greater(t, len(users), 0)
}

7. Named Argument

Metode Named Argument digunakan untuk mempermudah pembacaan query dengan parameter yang memiliki nama.

Contoh Kode Fungsi

func GetUsersByNamedParams(db *gorm.DB, name string, age int) ([]User, error) {
    var users []User
    result := db.Where("name = @name AND age = @age", map[string]interface{}{ "name": name, "age": age }).Find(&users)
    return users, result.Error
}

Unit Test

func TestGetUsersByNamedParams(t *testing.T) {
    users, err := GetUsersByNamedParams(db, "Alice", 30)
    assert.Nil(t, err)
    assert.Greater(t, len(users), 0)
}

Selanjutnya, kita akan membahas Find To Map, FirstOrInit, FirstOrCreate, Optimizer/Index Hints, Iteration, FindInBatches, Query Hooks, Pluck, Scopes, dan Count.

Untuk mempelajari lebih lanjut tentang database dalam Golang, silakan kunjungi:


comments powered by Disqus