veza/veza-backend-api/internal/pagination/pagination.go
2026-03-06 19:13:16 +01:00

95 lines
2.3 KiB
Go

package pagination
import (
"strconv"
apperrors "veza-backend-api/internal/errors"
"github.com/gin-gonic/gin"
)
const (
DefaultPageSize = 20
MaxPageSize = 100
)
// Params holds parsed pagination parameters
type Params struct {
Page int
Limit int
}
// Offset returns the offset for SQL queries (0-based)
func (p Params) Offset() int {
if p.Page < 1 {
return 0
}
return (p.Page - 1) * p.Limit
}
// PaginationMeta is the standard pagination object in responses
// Format: {"page": 1, "limit": 20, "total": 150, "total_pages": 8}
type PaginationMeta struct {
Page int `json:"page"`
Limit int `json:"limit"`
Total int64 `json:"total"`
TotalPages int `json:"total_pages"`
}
// ParseParams extracts page and limit from query string
// Uses ?page=1&limit=20. Returns default page=1, limit=20. Max limit=100.
// Empty or invalid values default to page=1, limit=20.
// Returns an AppError if validation fails (explicit page < 1 or limit > 100).
func ParseParams(c *gin.Context) (Params, *apperrors.AppError) {
pageStr := c.DefaultQuery("page", "1")
limitStr := c.DefaultQuery("limit", strconv.Itoa(DefaultPageSize))
page, _ := strconv.Atoi(pageStr)
limit, _ := strconv.Atoi(limitStr)
if page < 1 {
page = 1
}
if limit < 1 {
limit = DefaultPageSize
}
if limit > MaxPageSize {
return Params{}, apperrors.NewValidationError("pagination: limit must be between 1 and 100")
}
return Params{Page: page, Limit: limit}, nil
}
// ParseParamsLenient parses params with silent normalization (for backward compat)
// Invalid values are set to defaults. Use ParseParams for strict validation.
func ParseParamsLenient(c *gin.Context) Params {
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
limit, _ := strconv.Atoi(c.DefaultQuery("limit", strconv.Itoa(DefaultPageSize)))
if page < 1 {
page = 1
}
if limit < 1 {
limit = DefaultPageSize
}
if limit > MaxPageSize {
limit = MaxPageSize
}
return Params{Page: page, Limit: limit}
}
// BuildMeta constructs PaginationMeta from page, limit, total
func BuildMeta(page, limit int, total int64) PaginationMeta {
totalPages := 1
if limit > 0 && total > 0 {
totalPages = int((total + int64(limit) - 1) / int64(limit))
if totalPages < 1 {
totalPages = 1
}
}
return PaginationMeta{
Page: page,
Limit: limit,
Total: total,
TotalPages: totalPages,
}
}