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.