Repository Overview
Pengenalan Repository Pattern dalam API Gateway.
What is Repository Pattern?
Repository Pattern adalah design pattern yang memisahkan logika akses data dari business logic. Ini memberikan:
- Abstraksi - Business logic tidak perlu tahu detail implementasi database
- Testability - Mudah di-mock untuk unit testing
- Maintainability - Perubahan database hanya di satu tempat
- Reusability - Query yang sama dapat digunakan di banyak tempat
Architecture
┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ Controller │────▶│ Repository │────▶│ GORM │────▶│ PostgreSQL │
└─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘
│ │
│ │
▼ ▼
┌─────────────┐ ┌─────────────┐
│ DTO │ │ Model │
└─────────────┘ └─────────────┘
Repository Files
| File | Deskripsi |
|---|---|
sql_repo.go | Generic SQL operations (CRUD, pagination, filtering) |
auth_repo.go | Authentication-specific operations |
pengguna_repo.go | Pengguna-specific operations |
error_repo.go | Custom error handling |
Generic vs Specific Repository
Generic Repository (sql_repo.go)
Functions yang dapat digunakan untuk semua model:
// Works with any model
repository.Save(&user)
repository.Save(&product)
repository.GetById(&user, id)
repository.GetById(&product, id)
Specific Repository (auth_repo.go, pengguna_repo.go)
Functions khusus untuk domain tertentu:
// Only for Pengguna
repository.GetByNoPegawai(&pengguna, noPegawai)
repository.GetPagedPengguna(sort, filter, page, perPage)
Key Features
1. Soft Delete
Semua query otomatis exclude data yang is_deleted = true:
db = db.Where("is_deleted = ?", false)
2. Pagination
Built-in pagination support:
data, totalCount, totalPages, err := repository.GetNew(
&model,
sort,
filter,
page,
perPage,
)
3. Filtering
Dynamic filtering dengan operator support:
filter := "[nama,ilike,%john%;status,=,active]"
data, _, _, _ := repository.GetNew(&users, "", filter, 1, 10)
4. Sorting
Dynamic sorting:
sort := "created_at,desc"
data, _, _, _ := repository.GetNew(&users, sort, "", 1, 10)
Usage Example
In Controller
func GetUsers(c *gin.Context) {
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
perPage, _ := strconv.Atoi(c.DefaultQuery("perPage", "10"))
sort := c.Query("sort")
filter := c.Query("filter")
var users []models.User
data, totalCount, totalPages, err := repository.GetNew(
&users,
sort,
filter,
page,
perPage,
)
if err != nil {
helpers.SendError(c, helpers.NewInternalError("Failed to fetch users"))
return
}
c.JSON(http.StatusOK, helpers.ResponseData[[]models.User]{
Code: 200,
Status: true,
Message: "Success",
Info: helpers.Info{
Page: page,
PerPage: perPage,
TotalPages: totalPages,
TotalData: totalCount,
},
Data: data.([]models.User),
})
}
Best Practices
- Gunakan Generic Repository untuk operasi CRUD standar
- Buat Specific Repository untuk query kompleks atau domain-specific
- Selalu Handle Error dari repository
- Gunakan Transactions untuk operasi multiple
- Log Query di development untuk debugging