Skip to content
This repository has been archived by the owner on Feb 5, 2021. It is now read-only.

Commit

Permalink
Merge pull request #2 from qri-io/orderby-util
Browse files Browse the repository at this point in the history
feat(orderby): added util for orderBy support in api calls
  • Loading branch information
Arqu authored Jun 9, 2020
2 parents 7a07891 + 3a356e3 commit df48fea
Show file tree
Hide file tree
Showing 2 changed files with 153 additions and 0 deletions.
110 changes: 110 additions & 0 deletions order.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
package apiutil

import (
"fmt"
"net/http"
"net/url"
"strings"
)

var (
// OrderASC defines the ascending order keyword
OrderASC = "asc"
// OrderDESC defines the descending order keyword
OrderDESC = "desc"
)

// OrderBy represents ordering information
type OrderBy []Order

// Order represents ordering information for a single key
type Order struct {
Key string
Direction string
}

// NewOrder constructs a basic order struct
func NewOrder(key, orderDirection string) Order {
if orderDirection != OrderASC && orderDirection != OrderDESC {
orderDirection = OrderDESC
}
return Order{
Key: key,
Direction: orderDirection,
}
}

// String implements the stringer interface for OrderBy
func (o OrderBy) String() string {
var b strings.Builder
for i, oi := range o {
if i > 0 {
b.WriteString(",")
}
b.WriteString(oi.String())
}
return b.String()
}

// String implements the stringer interface for Order
func (o Order) String() string {
return fmt.Sprintf("%s,%s", o.Key, o.Direction)
}

// SetQueryParams adds order by info to a url as query parameters
func (o OrderBy) SetQueryParams(u *url.URL) *url.URL {
q := u.Query()
if len(o) > 0 {
q.Set("orderBy", o.String())
}

u.RawQuery = q.Encode()
return u
}

// OrderByFromRequest extracts orderBy params from an http request
func OrderByFromRequest(r *http.Request) OrderBy {
orderBy := r.FormValue("orderBy")
return NewOrderByFromString(orderBy, nil)
}

// OrderByFromRequestWithKeys extracts orderBy params from an
// http request and only takes the specified keys
func OrderByFromRequestWithKeys(r *http.Request, validKeys []string) OrderBy {
orderBy := r.FormValue("orderBy")
return NewOrderByFromString(orderBy, validKeys)
}

// NewOrderByFromString converts a commaa delimited string to an OrderBy struct
func NewOrderByFromString(orderBy string, validKeys []string) OrderBy {
orderComponents := strings.Split(orderBy, ",")
if orderBy == "" || len(orderComponents) == 0 || (len(orderComponents) != 1 && len(orderComponents)%2 == 1) {
return []Order{}
}
res := []Order{}
if len(orderComponents) == 1 {
res = append(res, NewOrder(strings.TrimSpace(orderComponents[0]), OrderDESC))
return res
}
for i := 0; i <= len(orderComponents)/2; i += 2 {
orderDirection := ""
if strings.ToLower(orderComponents[i+1]) == OrderASC {
orderDirection = OrderASC
} else {
orderDirection = OrderDESC
}
orderKey := strings.TrimSpace(orderComponents[i])
if validKeys != nil {
for _, vkey := range validKeys {
if vkey == orderKey {
res = append(res, NewOrder(orderKey, orderDirection))
break
}
}
} else {
res = append(res, NewOrder(orderKey, orderDirection))
}
}

return res
}
43 changes: 43 additions & 0 deletions order_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package apiutil

import (
"net/http/httptest"
"testing"
)

func TestOrderByFromRequest(t *testing.T) {
cases := []struct {
description string
query string
validKeys []string
expNumber int
expOrderBy string
}{
{"no orderBy specified", "", nil, 0, ""},
{"orderBy with no direction (defaults to desc)", "title", nil, 1, "title,desc"},
{"invalid orderBy", "title,asc,date", nil, 0, ""},
{"orderBy with bad parameters", "title,asc, date,desc", nil, 2, "title,asc,date,desc"},
{"orderBy with multiple parameters", "title,asc,date,desc", nil, 2, "title,asc,date,desc"},
{"orderBy with some invalid parameters", "title,asc,date,desc", []string{"title"}, 1, "title,asc"},
}

for _, c := range cases {
r := httptest.NewRequest("GET", "/", nil)
q := r.URL.Query()
// add query params
if c.query != "" {
q.Set("orderBy", c.query)
}

r.URL.RawQuery = q.Encode()

got := OrderByFromRequestWithKeys(r, c.validKeys)
if c.expNumber != len(got) {
t.Errorf("case '%s' error: number mismatch, expected '%d', got '%d'", c.description, c.expNumber, len(got))
}
if c.expOrderBy != got.String() {
t.Errorf("case '%s' error: output mismatch, expected '%s', got '%s'", c.description, c.expOrderBy, got.String())
}
}

}

0 comments on commit df48fea

Please sign in to comment.