diff --git a/http/paging.go b/http/paging.go new file mode 100644 index 0000000000..25dfaa772f --- /dev/null +++ b/http/paging.go @@ -0,0 +1,109 @@ +package http + +import ( + "context" + "net/http" + "net/url" + "strconv" + + "github.com/influxdata/platform" +) + +// decodeFindOptions returns a FindOptions decoded from http request. +func decodeFindOptions(ctx context.Context, r *http.Request) (*platform.FindOptions, error) { + opts := &platform.FindOptions{} + qp := r.URL.Query() + + if offset := qp.Get("offset"); offset != "" { + o, err := strconv.Atoi(offset) + if err != nil { + return nil, err + } + + opts.Offset = o + } + + if limit := qp.Get("limit"); limit != "" { + l, err := strconv.Atoi(limit) + if err != nil { + return nil, err + } + + opts.Limit = l + } + + if sortBy := qp.Get("sortBy"); sortBy != "" { + opts.SortBy = sortBy + } + + if descending := qp.Get("descending"); descending != "" { + desc, err := strconv.ParseBool(descending) + if err != nil { + return nil, err + } + + opts.Descending = desc + } + + return opts, nil +} + +// newPagingLinks returns a PagingLinks. +// num is the number of returned results. +func newPagingLinks(basePath string, opts platform.FindOptions, f platform.PagingFilter, num int) *platform.PagingLinks { + u := url.URL{ + Path: basePath, + } + + values := url.Values{} + for k, vs := range f.QueryParams() { + for _, v := range vs { + if v != "" { + values.Add(k, v) + } + } + } + + var self, next, prev string + for k, vs := range opts.QueryParams() { + for _, v := range vs { + if v != "" { + values.Add(k, v) + } + } + } + + u.RawQuery = values.Encode() + self = u.String() + + if num >= opts.Limit { + nextOffset := opts.Offset + opts.Limit + values.Set("offset", strconv.Itoa(nextOffset)) + u.RawQuery = values.Encode() + next = u.String() + } + + if opts.Offset > 0 { + prevOffset := opts.Offset - opts.Limit + if prevOffset < 0 { + prevOffset = 0 + } + values.Set("offset", strconv.Itoa(prevOffset)) + u.RawQuery = values.Encode() + prev = u.String() + } + + links := &platform.PagingLinks{ + Self: map[string]string{ + "self": self, + }, + Prev: map[string]string{ + "prev": prev, + }, + Next: map[string]string{ + "next": next, + }, + } + + return links +} diff --git a/paging.go b/paging.go new file mode 100644 index 0000000000..9c1ebf7b63 --- /dev/null +++ b/paging.go @@ -0,0 +1,38 @@ +package platform + +import ( + "strconv" +) + +// PagingFilter represents a filter containing url query params. +type PagingFilter interface { + // QueryParams returns a map containing url query params. + QueryParams() map[string][]string +} + +// PagingLinks represents paging links. +type PagingLinks struct { + Prev map[string]string `json:"prev"` + Self map[string]string `json:"self"` + Next map[string]string `json:"next"` +} + +// FindOptions represents options passed to all find methods with multiple results. +type FindOptions struct { + Limit int + Offset int + SortBy string + Descending bool +} + +// QueryParams returns a map containing url query params. +func (f FindOptions) QueryParams() map[string][]string { + qp := map[string][]string{ + "limit": []string{strconv.Itoa(f.Limit)}, + "offset": []string{strconv.Itoa(f.Offset)}, + "sortBy": []string{f.SortBy}, + "descending": []string{strconv.FormatBool(f.Descending)}, + } + + return qp +}