Skip to main content

SQL Repository Utils

File sql_repo_utils.go berisi fungsi-fungsi utility yang dapat digunakan kembali untuk operasi database umum seperti filtering, sorting, dan pagination.

Konsep

Utility ini mengadopsi konsep filtering dan sorting yang populer di ORM seperti Sequelize, namun dioptimalkan untuk GORM dan Go ecosystem. Format filter yang digunakan: [field,operator,value;field2,operator2,value2]

Daftar Fungsi

ApplyFilter

Menerapkan filter dinamis pada query GORM berdasarkan string filter.

Sintaks

func ApplyFilter(db *gorm.DB, filter string, defineColumnName ...func(string) string) *gorm.DB

Parameter

  • db *gorm.DB - Instance database GORM
  • filter string - String filter dalam format [field1,operator,value1;field2,operator,value2]
  • defineColumnName ...func(string) string (opsional) - Fungsi untuk memetakan nama kolom ke nama kolom dengan alias tabel

Format Filter

Filter menggunakan format: [kolom,operator,nilai;kolom2,operator2,nilai2]

ApplySort

Menerapkan pengurutan dinamis pada query GORM.

Sintaks

func ApplySort(db *gorm.DB, sort string, defineColumnName func(string) string, defaultSort ...string) *gorm.DB

Parameter

  • db *gorm.DB - Instance database GORM
  • sort string - String sorting dalam format field,asc atau field,desc
  • defineColumnName func(string) string - Fungsi untuk memetakan nama kolom
  • defaultSort ...string (opsional) - Default sorting jika sort parameter kosong

Operator yang Didukung

Berikut adalah tabel operator yang didukung:

OperatorDeskripsiContoh Penggunaan
=Sama dengan[nama,=,john]
!=Tidak sama dengan[status,!=,active]
>Lebih besar dari[umur,>,25]
<Lebih kecil dari[umur,<,60]
>=Lebih besar atau sama dengan[umur,>=,18]
<=Lebih kecil atau sama dengan[umur,<=,65]
likeLIKE dengan wildcard[nama,like,john]
ilikeILIKE (case-insensitive)[email,ilike,test]
inIN dengan multiple values[kategori,in,elektronik|fashion]
isIS NULL / IS NOT NULL[deleted_at,is,null]

Catatan Operator:

  • LIKE/ILIKE: Otomatis menambahkan wildcard % di awal dan akhir value
  • IN: Values dipisahkan dengan pipe (|) bukan koma
  • IS: Mendukung null dan not null (case-insensitive)

Contoh Penggunaan

Filtering

Basic Filtering

filter := "[nama,like,john]"
db := ApplyFilter(db, filter)

Multiple Filters

filter := "[umur,>,25;status,=,active]"
db := ApplyFilter(db, filter)

IN Operator

filter := "[kategori,in,elektronik|fashion|makanan]"
db := ApplyFilter(db, filter)

Filter dengan Table Aliases

defineColumns := func(column string) string {
columnMap := map[string]string{
"nama": "u.nama",
"penanggung_jawab": "pj.penanggung_jawab",
"file_path": "iab.file_path"
}
if mappedColumn, exists := columnMap[column]; exists {
return mappedColumn
}
return "iab." + column
}
db := ApplyFilter(db, filter, defineColumns)

Sorting

Basic Sorting

sort := "nama,asc"
db := ApplySort(db, sort, nil)

Sorting dengan Table Aliases

defineColumns := func(column string) string {
return "users." + column
}
sort := "created_at,desc"
db := ApplySort(db, sort, defineColumns)

Multiple Sorting dengan Default

sort := "nama,asc"
db := ApplySort(db, sort, defineColumns, "id ASC", "created_at DESC")

applyCountPaginate

Menerapkan pagination dan menghitung total data (fungsi internal).

Sintaks

func applyCountPaginate(db *gorm.DB, model interface{}, page int, perPage int) (int, int, error)

Parameter

  • db *gorm.DB - Instance database GORM
  • model interface{} - Model untuk counting
  • page int - Nomor halaman (dimulai dari 1)
  • perPage int - Jumlah data per halaman

Return Value

  • int - Total count semua data
  • int - Total halaman
  • error - Error jika terjadi

Catatan

Fungsi ini internal dan biasanya dipanggil oleh fungsi pagination lainnya.

parseFilterString

Mem-parse string filter menjadi map (fungsi internal).

Sintaks

func parseFilterString(filterString string) (map[string]string, error)

Parameter

  • filterString string - String filter yang akan diparse

Return Value

  • map[string]string - Map dari kolom ke nilai dengan operator
  • error - Error jika format filter tidak valid

Format String Filter

[field1,operator,value1;field2,operator,value2]

Best Practices

1. Gunakan Column Mapping untuk Join Tables

Saat melakukan query dengan multiple tables, selalu gunakan defineColumnName function untuk memetakan kolom ke alias tabel yang tepat:

defineColumns := func(column string) string {
columnMap := map[string]string{
"user_name": "u.nama",
"role_name": "r.nama",
"created_at": "u.created_at"
}
if mappedColumn, exists := columnMap[column]; exists {
return mappedColumn
}
return "u." + column
}

2. Validasi Input Filter

Selalu validasi input filter sebelum menerapkannya, meskipun fungsi ini sudah memiliki basic validation.

3. Gunakan Default Sort

Sediakan default sorting untuk pengalaman pengguna yang konsisten:

db := ApplySort(db, sort, defineColumns, "id ASC", "created_at DESC")

4. Error Handling

Fungsi ApplyFilter akan mengabaikan filter yang invalid dan melanjutkan query tanpa filter. Pastikan aplikasi memiliki error handling yang tepat di level yang lebih tinggi.

Contoh Implementasi Lengkap

// Repository function dengan filtering dan sorting
func GetUsers(db *gorm.DB, filter, sort string, page, perPage int) ([]User, int, int, error) {
var users []User

// Define column mapping untuk join dengan table roles
defineColumns := func(column string) string {
columnMap := map[string]string{
"name": "u.nama",
"email": "u.email",
"role_name": "r.nama as role_name",
"created_at": "u.created_at"
}
if mappedColumn, exists := columnMap[column]; exists {
return mappedColumn
}
return "u." + column
}

// Apply filter
db = ApplyFilter(db, filter, defineColumns)

// Apply sort dengan default
db = ApplySort(db, sort, defineColumns, "u.id ASC")

// Count dan pagination
totalCount, totalPages, err := applyCountPaginate(db, &User{}, page, perPage)
if err != nil {
return nil, 0, 0, err
}

// Execute query dengan joins
err = db.
Table("users u").
Select("u.*, r.nama as role_name").
Joins("LEFT JOIN roles r ON u.role_id = r.id").
Find(&users).Error

return users, totalCount, totalPages, err
}

API Request Examples

Request Parameters

GET /api/users?filter=[nama,like,john;status,=,active]&sort=nama,asc&page=1&perPage=10

Response

{
"success": true,
"data": [
{
"id": 1,
"nama": "John Doe",
"email": "john@example.com",
"role_name": "Admin",
"created_at": "2024-01-01T00:00:00Z"
}
],
"meta": {
"total_count": 1,
"total_pages": 1,
"current_page": 1,
"per_page": 10
}
}

Kesimpulan

SQL Repository Utils menyediakan fungsi-fungsi reusable untuk:

  • Filtering dinamis dengan berbagai operator
  • Sorting dinamis dengan custom column mapping
  • Pagination dengan automatic counting
  • Column mapping untuk complex queries dengan joins

Utility ini dioptimalkan untuk GORM dan Go ecosystem dengan format string-based filter yang ideal untuk API endpoints yang memerlukan filtering dinamis via URL parameters.