Documentation
¶
Overview ¶
Package sortby parses client sort expressions into a typed order.
A client sends one expression per value, a field optionally followed by a direction:
GET /articles?sort=status&sort=updatedAt:desc
A field without a direction sorts in ascending order. Parse checks each expression and converts its field with a function the application supplies, so only the fields an endpoint allows reach the storage:
order, err := sortby.Parse(query["sort"], func(name string) (Column, error) {
switch name {
case "status":
return ColumnStatus, nil
case "updatedAt":
return ColumnUpdatedAt, nil
default:
return "", fmt.Errorf("unknown sort field %q", name)
}
})
The result is an Order, the Term values in the order the client sent them. Order.Make converts it into the application's own type, for example the sort type of a storage package.
Errors ¶
Parse stops at the first invalid expression and returns a *ParseError with an ErrorKind and the Index of the expression. The error of the field function is available through errors.Unwrap. ParseExpression parses one expression without restricting its field.
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Order ¶
Order is an ordered collection of validated sort criteria.
func Parse ¶
func Parse[Field any](expressions []string, parseField func(string) (Field, error)) (Order[Field], error)
Parse validates expressions using parseField. An expression may be either "field" or "field:direction". A missing direction means ascending. A ParseError reports the position of the rejected expression in Index.
Example ¶
package main
import (
"fmt"
"log"
"github.com/uchaloop/httpx/sortby"
)
type column string
const (
columnTitle column = "title"
columnUpdatedAt column = "updated_at"
)
// parseColumn allows only the fields the endpoint can sort by.
func parseColumn(name string) (column, error) {
switch name {
case "title":
return columnTitle, nil
case "updatedAt":
return columnUpdatedAt, nil
default:
return "", fmt.Errorf("unknown sort field %q", name)
}
}
func main() {
order, err := sortby.Parse([]string{"updatedAt:desc", "title"}, parseColumn)
if err != nil {
log.Fatal(err)
}
for _, term := range order {
fmt.Println(term.Field, term.Direction)
}
}
Output: updated_at desc title asc
func (Order[Field]) Make ¶
Make converts criteria to application-owned values, preserving their order.
Example ¶
package main
import (
"fmt"
"log"
"strings"
"github.com/uchaloop/httpx/sortby"
)
type column string
const (
columnTitle column = "title"
columnUpdatedAt column = "updated_at"
)
// parseColumn allows only the fields the endpoint can sort by.
func parseColumn(name string) (column, error) {
switch name {
case "title":
return columnTitle, nil
case "updatedAt":
return columnUpdatedAt, nil
default:
return "", fmt.Errorf("unknown sort field %q", name)
}
}
func main() {
order, err := sortby.Parse([]string{"updatedAt:desc", "title"}, parseColumn)
if err != nil {
log.Fatal(err)
}
clauses := order.Make(func(field column, direction sortby.Direction) string {
return string(field) + " " + strings.ToUpper(string(direction))
})
fmt.Println("ORDER BY", strings.Join(clauses, ", "))
}
Output: ORDER BY updated_at DESC, title ASC
type ParseError ¶
type ParseError struct {
Kind ErrorKind
Index int
Expression string
Field string
Direction string
// contains filtered or unexported fields
}
ParseError describes an invalid sort expression. Index is the position of the expression among the values passed to Parse.
Example ¶
package main
import (
"errors"
"fmt"
"github.com/uchaloop/httpx/sortby"
)
type column string
const (
columnTitle column = "title"
columnUpdatedAt column = "updated_at"
)
// parseColumn allows only the fields the endpoint can sort by.
func parseColumn(name string) (column, error) {
switch name {
case "title":
return columnTitle, nil
case "updatedAt":
return columnUpdatedAt, nil
default:
return "", fmt.Errorf("unknown sort field %q", name)
}
}
func main() {
for _, expressions := range [][]string{{"title", "author"}, {"title:up"}} {
_, err := sortby.Parse(expressions, parseColumn)
if parseErr, ok := errors.AsType[*sortby.ParseError](err); ok {
fmt.Printf("sort[%d]: %v\n", parseErr.Index, err)
}
}
}
Output: sort[1]: sort field "author" is not allowed sort[0]: sort direction "up" is not supported
func (*ParseError) Error ¶
func (e *ParseError) Error() string
func (*ParseError) Unwrap ¶
func (e *ParseError) Unwrap() error
Unwrap preserves the application field parser's error.
type Term ¶
Term describes one validated sort criterion.
func ParseExpression ¶
ParseExpression parses one sort expression without restricting its field. Field validation may be applied by a framework adapter or application enum. A ParseError reports Index 0.
Example ¶
package main
import (
"fmt"
"log"
"github.com/uchaloop/httpx/sortby"
)
func main() {
term, err := sortby.ParseExpression("createdAt:desc")
if err != nil {
log.Fatal(err)
}
fmt.Println(term.Field, term.Direction)
}
Output: createdAt desc