sortby

package
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 14, 2026 License: MIT Imports: 2 Imported by: 0

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 Direction

type Direction string

Direction is a supported sort direction.

const (
	Ascending  Direction = "asc"
	Descending Direction = "desc"
)

type ErrorKind

type ErrorKind uint8

ErrorKind identifies a stable sort expression failure class.

const (
	ErrorEmptyExpression ErrorKind = iota + 1
	ErrorInvalidExpression
	ErrorUnknownField
	ErrorUnknownDirection
	ErrorEmptyField
)

type Order

type Order[Field any] []Term[Field]

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

func (order Order[Field]) Make[Value any](makeTerm func(Field, Direction) Value) []Value

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

type Term[Field any] struct {
	Field     Field
	Direction Direction
}

Term describes one validated sort criterion.

func ParseExpression

func ParseExpression(expression string) (Term[string], error)

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

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL