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, } }