Files
MyClub/internal/controllers/pagination_helper.go
T
Tomas Dvorak 9ccca365b3 dev day #65
2025-10-19 18:09:28 +02:00

122 lines
3.1 KiB
Go

package controllers
import (
"math"
"strconv"
"github.com/gin-gonic/gin"
"gorm.io/gorm"
)
// PaginationHelper provides pagination utilities
type PaginationHelper struct{}
// PaginationParams represents pagination parameters
type PaginationParams struct {
Page int `json:"page"`
PageSize int `json:"page_size"`
Offset int `json:"-"`
}
// PaginationMeta represents pagination metadata
type PaginationMeta struct {
Page int `json:"page"`
PageSize int `json:"page_size"`
Total int64 `json:"total"`
TotalPages int `json:"total_pages"`
HasNext bool `json:"has_next"`
HasPrev bool `json:"has_prev"`
}
// NewPaginationHelper creates a new PaginationHelper instance
func NewPaginationHelper() *PaginationHelper {
return &PaginationHelper{}
}
// GetPaginationParams extracts pagination parameters from the request
// Defaults: page=1, pageSize=20
func (ph *PaginationHelper) GetPaginationParams(c *gin.Context) PaginationParams {
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "20"))
// Validate and constrain values
if page < 1 {
page = 1
}
if pageSize < 1 {
pageSize = 20
}
if pageSize > 100 {
pageSize = 100 // Max page size to prevent abuse
}
offset := (page - 1) * pageSize
return PaginationParams{
Page: page,
PageSize: pageSize,
Offset: offset,
}
}
// BuildPaginationMeta creates pagination metadata
func (ph *PaginationHelper) BuildPaginationMeta(params PaginationParams, total int64) PaginationMeta {
totalPages := int(math.Ceil(float64(total) / float64(params.PageSize)))
return PaginationMeta{
Page: params.Page,
PageSize: params.PageSize,
Total: total,
TotalPages: totalPages,
HasNext: params.Page < totalPages,
HasPrev: params.Page > 1,
}
}
// Paginate applies pagination to a GORM query and returns the paginated results with metadata
func (ph *PaginationHelper) Paginate(c *gin.Context, db *gorm.DB, dest interface{}) (PaginationMeta, error) {
params := ph.GetPaginationParams(c)
// Count total records
var total int64
if err := db.Count(&total).Error; err != nil {
return PaginationMeta{}, err
}
// Apply pagination
if err := db.Offset(params.Offset).Limit(params.PageSize).Find(dest).Error; err != nil {
return PaginationMeta{}, err
}
meta := ph.BuildPaginationMeta(params, total)
return meta, nil
}
// PaginateWithPreload applies pagination with preloading associations
func (ph *PaginationHelper) PaginateWithPreload(c *gin.Context, db *gorm.DB, dest interface{}, preloads ...string) (PaginationMeta, error) {
params := ph.GetPaginationParams(c)
// Count total records (without preload)
var total int64
if err := db.Count(&total).Error; err != nil {
return PaginationMeta{}, err
}
// Apply preloads
query := db
for _, preload := range preloads {
query = query.Preload(preload)
}
// Apply pagination
if err := query.Offset(params.Offset).Limit(params.PageSize).Find(dest).Error; err != nil {
return PaginationMeta{}, err
}
meta := ph.BuildPaginationMeta(params, total)
return meta, nil
}
// Global PaginationHelper instance for convenience
var Paginator = NewPaginationHelper()