95 lines
2.3 KiB
Go
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,
|
|
}
|
|
}
|