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 GORMfilter 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 GORMsort string- String sorting dalam formatfield,ascataufield,descdefineColumnName func(string) string- Fungsi untuk memetakan nama kolomdefaultSort ...string(opsional) - Default sorting jika sort parameter kosong
Operator yang Didukung
Berikut adalah tabel operator yang didukung:
| Operator | Deskripsi | Contoh 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] |
like | LIKE dengan wildcard | [nama,like,john] |
ilike | ILIKE (case-insensitive) | [email,ilike,test] |
in | IN dengan multiple values | [kategori,in,elektronik|fashion] |
is | IS 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
nulldannot 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 GORMmodel interface{}- Model untuk countingpage int- Nomor halaman (dimulai dari 1)perPage int- Jumlah data per halaman
Return Value
int- Total count semua dataint- Total halamanerror- 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 operatorerror- 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.