You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
79 lines
2.2 KiB
Go
79 lines
2.2 KiB
Go
package data
|
|
|
|
import (
|
|
"strings"
|
|
|
|
"git.runcible.io/learning/pulley/internal/validator"
|
|
)
|
|
|
|
type Filters struct {
|
|
Page int
|
|
PageSize int
|
|
Sort string
|
|
SortSafelist []string
|
|
}
|
|
|
|
func ValidateFilters(v *validator.Validator, f Filters) {
|
|
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")
|
|
v.Check(validator.PermittedValue(f.Sort, f.SortSafelist...), "sort", "invalid sort value")
|
|
}
|
|
|
|
// sortColumn checks that the client-provided Sort field matches one of the entries in our safelist
|
|
// and if it does, extract the column name from the Sort field.
|
|
func (f Filters) sortColumn() string {
|
|
for _, safeValue := range f.SortSafelist {
|
|
if f.Sort == safeValue {
|
|
return strings.TrimPrefix(f.Sort, "-")
|
|
}
|
|
}
|
|
// ValidateFilters should have checked this, but we are extra careful of sql injection.
|
|
panic("unsafe sort parameter: " + f.Sort)
|
|
}
|
|
|
|
// sortDirection returns the sort direction depending on the prefix
|
|
// character of the Sort field.
|
|
func (f Filters) sortDirection() string {
|
|
if strings.HasPrefix(f.Sort, "-") {
|
|
return "DESC"
|
|
}
|
|
return "ASC"
|
|
}
|
|
|
|
// limit returns the page_size provided as a query param
|
|
func (f Filters) limit() int {
|
|
return f.PageSize
|
|
}
|
|
|
|
// offset returns the offset of a pagination query based on
|
|
// client's page and page_size query params used.
|
|
func (f Filters) offset() int {
|
|
return (f.Page - 1) * f.PageSize
|
|
}
|
|
|
|
type Metadata struct {
|
|
CurrentPage int `json:"current_page,omitzero"`
|
|
PageSize int `json:"page_size,omitzero"`
|
|
FirstPage int `json:"first_page,omitzero"`
|
|
LastPage int `json:"last_page,omitzero"`
|
|
TotalRecords int `json:"total_records,omitzero"`
|
|
}
|
|
|
|
// calculateMetadata returns a Metadata struct from query results and
|
|
// query params used in a request
|
|
func calculateMetadata(totalRecords, page, pageSize int) Metadata {
|
|
if totalRecords == 0 {
|
|
return Metadata{}
|
|
}
|
|
|
|
return Metadata{
|
|
CurrentPage: page,
|
|
PageSize: pageSize,
|
|
FirstPage: 1,
|
|
LastPage: (totalRecords + pageSize - 1) / pageSize,
|
|
TotalRecords: totalRecords,
|
|
}
|
|
}
|