Pemrograman

09 Advance Query Data Gorm Library (Bagian 1)

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

  1. var results []map[string]interface{} → Deklarasi slice untuk menyimpan hasil query dalam format map.
  2. db.Model(&User{}).Find(&results) → Mengambil semua data dari tabel User dan menyimpannya dalam map.
  3. 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

  1. Memanggil GetUsersAsMap(db) untuk mendapatkan data dalam format map.
  2. Memastikan tidak ada error dengan assert.Nil(t, err).
  3. Memastikan hasil query tidak kosong dengan assert.Greater(t, len(results), 0).
  4. 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

  1. var user User → Deklarasi variabel user sebagai struct User.
  2. db.Where("name = ?", name).FirstOrInit(&user, User{Name: name}) → Mencari user dengan name yang diberikan. Jika tidak ditemukan, menginisialisasi struct User dengan nilai default.
  3. 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

  1. Memanggil FirstOrInitUser(db, "Alice") untuk mencari atau menginisialisasi user.
  2. Memastikan nama user sesuai dengan yang diharapkan menggunakan assert.Equal(t, "Alice", user.Name).
  3. 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

  1. var user User → Deklarasi variabel user sebagai struct User.
  2. db.Where("name = ?", name).FirstOrCreate(&user, User{Name: name}) → Mencari user berdasarkan name, jika tidak ditemukan, membuat user baru dengan name yang diberikan.
  3. 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

  1. Memanggil FirstOrCreateUser(db, "Bob") untuk mencari atau membuat user baru.
  2. Memastikan bahwa jika user ditemukan, user yang ada akan dikembalikan.
  3. 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

  1. var users []User → Deklarasi slice untuk menyimpan hasil query.
  2. db.Raw("SELECT * FROM users USE INDEX (idx_name)").Scan(&users) → Menjalankan query dengan petunjuk penggunaan indeks tertentu.
  3. 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

  1. rows, err := db.Model(&User{}).Rows() → Mengambil semua baris data user dalam bentuk iterator.
  2. defer rows.Close() → Menutup iterasi setelah selesai digunakan untuk menghindari kebocoran memori.
  3. for rows.Next() → Melakukan iterasi pada setiap baris hasil query.
  4. var user User → Deklarasi variabel untuk menampung hasil scan.
  5. db.ScanRows(rows, &user) → Memindai hasil dari iterator ke struct User.

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:


comments powered by Disqus