package data import ( "math" "strings" "party.at/party/internal/validator" ) type Filters struct { Page int PageSize int Sort string SortSafelist []string } func (f Filters) sortColumn() string { for _, safeValue := range f.SortSafelist { if f.Sort == safeValue { return strings.TrimPrefix(f.Sort, "-") } } panic("unsafe sort parameter: " + f.Sort) } // Return the sort direction ("ASC" or "DESC") depending on the prefix character of the // Sort field. func (f Filters) sortDirection() string { if strings.HasPrefix(f.Sort, "-") { return "DESC" } return "ASC" } func (f Filters) limit() int { return f.PageSize } func (f Filters) offset() int { return (f.Page - 1) * f.PageSize } func ValidateFilters(v *validator.Validator, f Filters) { // Check that the page and page_size parameters contain sensible values. v.Check(f.Page > 0, "page", "must be greater than zero") v.Check(f.Page <= 10_000_000, "page", "must be a maximum of 10 million") v.Check(f.PageSize > 0, "page_size", "must be greater than zero") v.Check(f.PageSize <= 100, "page_size", "must be a maximum of 100") // Check that the sort parameter matches a value in the safelist. v.Check(validator.In(f.Sort, f.SortSafelist...), "sort", "invalid sort value") } type Metadata struct { CurrentPage int `json:"current_page,omitempty"` PageSize int `json:"page_size,omitempty"` FirstPage int `json:"first_page,omitempty"` LastPage int `json:"last_page,omitempty"` TotalRecords int `json:"total_records,omitempty"` } func calculateMetadata(totalRecords, page, pageSize int) Metadata { if totalRecords == 0 { // Note that we return an empty Metadata struct if there are no records. return Metadata{} } return Metadata{ CurrentPage: page, PageSize: pageSize, FirstPage: 1, LastPage: int(math.Ceil(float64(totalRecords) / float64(pageSize))), TotalRecords: totalRecords, } }