axe/internal/handlers/pagination.go

54 lines
1.7 KiB
Go
Raw Normal View History

2026-10-18 19:07:25 +00:00
package handlers
import (
"net/http"
"strconv"
"github.com/gin-gonic/gin"
"building-mgmt/internal/repository"
)
// Пагинация списков: одинаковые параметры limit/offset/sort/order
// у всех GET-списков, поэтому разбор вынесен отдельно.
// Словари сортировок приходят из repository — того же источника,
// что и ORDER BY в SQL: валидация и запрос не могут разъехаться.
// parsePage разбирает параметры страницы. Возвращает ok=false после
// ответа 400 — вызывающий хендлер обязан сразу вернуться.
func parsePage(c *gin.Context, sorts map[string]repository.SortSpec) (repository.Page, bool) {
page := repository.Page{
Limit: repository.DefaultLimit,
Sort: c.Query("sort"),
Order: c.Query("order"),
}
if v := c.Query("limit"); v != "" {
n, err := strconv.Atoi(v)
if err != nil || n < 1 || n > repository.MaxLimit {
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid limit"})
return page, false
}
page.Limit = n
}
if v := c.Query("offset"); v != "" {
n, err := strconv.Atoi(v)
if err != nil || n < 0 {
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid offset"})
return page, false
}
page.Offset = n
}
if page.Order != "" && page.Order != "asc" && page.Order != "desc" {
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid order"})
return page, false
}
if page.Sort != "" {
if _, ok := sorts[page.Sort]; !ok {
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid sort"})
return page, false
}
}
return page, true
}