rename query package to qs
This commit is contained in:
+123
@@ -0,0 +1,123 @@
|
||||
package qs
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// Query error.
|
||||
var (
|
||||
ErrInvalidLimit = errors.New("invalid limit")
|
||||
ErrInvalidOffset = errors.New("invalid offset")
|
||||
ErrInvalidPage = errors.New("invalid page")
|
||||
)
|
||||
|
||||
// Pagination represents a page size and offset for, most likely, a database query.
|
||||
type Pagination struct {
|
||||
Limit int `json:"limit"` // Maximum number of results in the page.
|
||||
Offset int `json:"offset"` // Results offset.
|
||||
Page int `json:"page,omitempty"` // Page number. This is 0 if the query specifies Offset directly.
|
||||
}
|
||||
|
||||
// ReadPaginationOptions configures the behaviour of ReadPagination.
|
||||
type ReadPaginationOptions struct {
|
||||
LimitKey string // Query string key for limit. The default value is "limit"
|
||||
OffsetKey string // Query string key for offset. The default value is "offset"
|
||||
PageKey string // Query string key for page. The default value is "page"
|
||||
|
||||
MaxLimit int // If this is > 0, the limit is clamped to this maximum value
|
||||
MinLimit int // The limit is clamped to this minimum value
|
||||
}
|
||||
|
||||
// ReadPagination parses URL values into a Pagination struct.
|
||||
// This function offers support for both Page and Offset values.
|
||||
// If both are provided, Offset is always prioritised.
|
||||
// If only Page is provided, Offset is calculated based on Limit.
|
||||
func ReadPagination(values url.Values, opt *ReadPaginationOptions) (*Pagination, error) {
|
||||
opt = initPaginationOptions(opt)
|
||||
|
||||
limit := 0
|
||||
offset := 0
|
||||
page := 0
|
||||
var err error = nil
|
||||
|
||||
if values.Has(opt.LimitKey) {
|
||||
limit, err = strconv.Atoi(values.Get(opt.LimitKey))
|
||||
if err != nil {
|
||||
return nil, ErrInvalidLimit
|
||||
}
|
||||
}
|
||||
|
||||
if opt.MaxLimit > 0 && limit > opt.MaxLimit {
|
||||
limit = opt.MaxLimit
|
||||
} else if limit < opt.MinLimit {
|
||||
limit = opt.MinLimit
|
||||
}
|
||||
|
||||
if values.Has(opt.OffsetKey) {
|
||||
offset, err = strconv.Atoi(values.Get(opt.OffsetKey))
|
||||
if err != nil {
|
||||
return nil, ErrInvalidOffset
|
||||
}
|
||||
} else if values.Has(opt.PageKey) {
|
||||
page, err = strconv.Atoi(values.Get(opt.PageKey))
|
||||
if err != nil {
|
||||
return nil, ErrInvalidPage
|
||||
}
|
||||
offset = (page - 1) * limit
|
||||
}
|
||||
|
||||
pag := &Pagination{
|
||||
Limit: limit,
|
||||
Offset: offset,
|
||||
Page: page,
|
||||
}
|
||||
return pag, nil
|
||||
}
|
||||
|
||||
// ReadRequestPagination parses a request's query string into a slice of filters.
|
||||
// This function always returns a value if it does not encounter an error.
|
||||
func ReadRequestPagination(req *http.Request, opt *ReadPaginationOptions) (*Pagination, error) {
|
||||
return ReadPagination(req.URL.Query(), opt)
|
||||
}
|
||||
|
||||
// ReadStringPagination parses a query string literal into a slice of filters.
|
||||
// This function always returns a value if it does not encounter an error.
|
||||
func ReadStringPagination(qs string, opt *ReadPaginationOptions) (*Pagination, error) {
|
||||
values, err := url.ParseQuery(qs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ReadPagination(values, opt)
|
||||
}
|
||||
|
||||
func initPaginationOptions(opt *ReadPaginationOptions) *ReadPaginationOptions {
|
||||
def := &ReadPaginationOptions{
|
||||
LimitKey: "limit",
|
||||
OffsetKey: "offset",
|
||||
PageKey: "page",
|
||||
}
|
||||
|
||||
if opt != nil {
|
||||
if len(opt.LimitKey) > 0 {
|
||||
def.LimitKey = opt.LimitKey
|
||||
}
|
||||
if len(opt.OffsetKey) > 0 {
|
||||
def.OffsetKey = opt.OffsetKey
|
||||
}
|
||||
if len(opt.PageKey) > 0 {
|
||||
def.PageKey = opt.PageKey
|
||||
}
|
||||
|
||||
if opt.MaxLimit > def.MaxLimit {
|
||||
def.MaxLimit = opt.MaxLimit
|
||||
}
|
||||
if opt.MinLimit > def.MinLimit {
|
||||
def.MinLimit = opt.MinLimit
|
||||
}
|
||||
}
|
||||
|
||||
return def
|
||||
}
|
||||
Reference in New Issue
Block a user