r3url

package
v0.0.8 Latest Latest
Warning

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

Go to latest
Published: Jul 9, 2026 License: MIT Imports: 10 Imported by: 0

Documentation

Overview

Package r3url provides bidirectional conversion between r3 query types and URL query parameters.

Category: Serialization dialect.

It supports two parsing modes:

  • Unified mode: the entire query is passed as a single JSON parameter (?query={...}), using the same schema as the r3json dialect.
  • Decomposed mode: each r3 component is a separate URL parameter (?fields=a,b&filters=[...]&sort=name:asc&page=2&page_size=25).

The default behavior (ModeAuto) automatically detects which mode to use: if a "query" parameter is present, unified mode is used; otherwise, decomposed mode.

All parameter names, sort formats, and filter styles are configurable via functional options. Django-style shorthand filters (?status=active&age__gte=18) are supported as an opt-in feature.

Index

Constants

This section is empty.

Variables

View Source
var ErrURLDialectorFailed = errors.New("url dialector failed")

ErrURLDialectorFailed is a generic error for r3url dialector failures.

Functions

func FormatCursorPagination

func FormatCursorPagination(c *r3.CursorSpec, paramNames ParamNames) url.Values

FormatCursorPagination writes cursor pagination parameters into url.Values. If cursor is nil, no parameters are added.

func FormatDjangoFilters

func FormatDjangoFilters(filters r3.Filters, cfg Config) url.Values

FormatDjangoFilters formats r3.Filters as Django-style URL parameters. Only simple filters (non-AND/OR) can be represented in Django-style. Filters with AND/OR groups are silently skipped.

func FormatFields

func FormatFields(fields r3.Fields) string

FormatFields formats r3.Fields into a comma-separated string. Example: Fields{FieldSpec("id"), FieldSpec("name")} -> "id,name".

func FormatFilters

func FormatFilters(filters r3.Filters) (string, error)

FormatFilters formats r3.Filters into a JSON string.

func FormatPagination

func FormatPagination(p *r3.PaginationSpec, paramNames ParamNames) url.Values

FormatPagination writes pagination parameters into url.Values. If pagination is nil, no parameters are added.

func FormatQuery

func FormatQuery(q r3.Query, opts ...Option) (url.Values, error)

FormatQuery formats an r3.Query into url.Values using the configured mode and options.

In ModeAuto, it defaults to decomposed mode for formatting (since decomposed produces more human-readable URLs). Use WithMode(ModeUnified) to format as a single JSON query parameter instead.

Example usage:

values, err := r3url.FormatQuery(q)
// values.Encode() -> "fields=id,name&sort=name:asc&page=1&page_size=25"

values, err := r3url.FormatQuery(q, r3url.WithMode(r3url.ModeUnified))
// values.Encode() -> "query={...json...}"

func FormatSort

func FormatSort(sorts r3.Sorts, format SortFormat) (string, error)

FormatSort formats r3.Sorts into a string using the specified format.

func IsErrDialectorFailure

func IsErrDialectorFailure(err error) bool

IsErrDialectorFailure checks if the given error is a r3url failure.

func ParseCursorPagination

func ParseCursorPagination(values url.Values, paramNames ParamNames) (*r3.CursorSpec, error)

ParseCursorPagination extracts cursor pagination parameters from url.Values. It reads the after, before, and limit parameters using the configured param names.

If no cursor parameters are present, it returns nil (no cursor pagination requested).

func ParseDjangoFilters

func ParseDjangoFilters(values url.Values, cfg Config) (r3.Filters, error)

ParseDjangoFilters parses Django-style query parameters into r3.Filters.

Django-style parameters use the pattern "field__operator=value":

?status=active          -> {f: "status", op: "eq", v: "active"}
?age__gte=18            -> {f: "age", op: "gte", v: "18"}
?name__like=John%       -> {f: "name", op: "like", v: "John%"}
?tags__in=a,b,c         -> {f: "tags", op: "in", v: ["a","b","c"]}

Parameters without the separator are treated as "eq" filters. Reserved parameter names (fields, filters, sort, page, page_size, query) are skipped.

The cfg.DjangoFields whitelist controls which fields are allowed. If it is empty, all fields are allowed (validated for identifier safety).

func ParseFields

func ParseFields(raw string) (r3.Fields, error)

ParseFields parses a comma-separated string of field names into r3.Fields. Example: "id,name,status" -> Fields{FieldSpec("id"), FieldSpec("name"), FieldSpec("status")}

Empty string returns nil (no fields specified).

func ParseFilters

func ParseFilters(raw string) (r3.Filters, error)

ParseFilters parses a JSON-encoded filter string into r3.Filters. The string should be a JSON array of filter objects using the r3json schema.

Example: [{"f":"status","op":"eq","v":"active"},{"f":"age","op":"gte","v":18}]

Empty string returns nil (no filters specified).

func ParsePagination

func ParsePagination(values url.Values, paramNames ParamNames) (*r3.PaginationSpec, error)

ParsePagination extracts pagination parameters from url.Values. It reads the page number and page size parameters using the configured param names.

If neither parameter is present, it returns nil (no pagination specified).

func ParseQuery

func ParseQuery(values url.Values, opts ...Option) (r3.Query, error)

ParseQuery parses url.Values into an r3.Query using the configured mode and options.

In ModeAuto (default), it checks for the unified "query" parameter first. If present, unified mode is used; otherwise, decomposed mode is used.

Example usage:

// Auto mode (default):
q, err := r3url.ParseQuery(r.URL.Query())

// Decomposed with sign-prefix sort:
q, err := r3url.ParseQuery(r.URL.Query(),
    r3url.WithMode(r3url.ModeDecomposed),
    r3url.WithSortFormat(r3url.SortFormatSignPrefix),
)

// With Django-style filters:
q, err := r3url.ParseQuery(r.URL.Query(),
    r3url.WithDjangoStyleFilters("status", "age", "name"),
)

func ParseSort

func ParseSort(raw string, format SortFormat) (r3.Sorts, error)

ParseSort parses a raw sort string into r3.Sorts using the specified format.

Empty string returns nil (no sorts specified).

Types

type Config

type Config struct {
	// Mode determines the parsing strategy. Default: ModeAuto.
	Mode Mode

	// ParamNames customizes the URL parameter names.
	ParamNames ParamNames

	// Sort configures sort parsing and formatting.
	Sort SortConfig

	// Filter configures filter parsing.
	Filter FilterConfig
}

Config controls how the URL dialect parses and formats query parameters.

func DefaultConfig

func DefaultConfig() Config

DefaultConfig returns a Config with sensible defaults.

type FilterConfig

type FilterConfig struct {
	// AllowDjangoStyle enables parsing field__op=value query parameters as filters.
	// Default: false.
	AllowDjangoStyle bool

	// DjangoSeparator is the separator between field name and operator in Django-style params.
	// Default: "__" (double underscore).
	DjangoSeparator string

	// DjangoFields restricts which fields can be used in Django-style filters.
	// If empty and AllowDjangoStyle is true, all fields are allowed (validated for identifier safety).
	// Setting this is recommended as a security safeguard to prevent arbitrary query parameters
	// from being interpreted as filters.
	DjangoFields []string
}

FilterConfig configures filter parsing.

type Mode

type Mode int

Mode determines the parsing/formatting strategy for URL query parameters.

const (
	// ModeAuto tries unified mode first (if the "query" param is present),
	// and falls back to decomposed mode otherwise. This is the default.
	ModeAuto Mode = iota
	// ModeUnified only accepts a single JSON parameter containing the full query.
	ModeUnified
	// ModeDecomposed only accepts decomposed parameters (fields, filters, sort, page, page_size).
	ModeDecomposed
)

type Option

type Option func(*Config)

Option is a functional option for configuring the URL dialect.

func WithDjangoSeparator

func WithDjangoSeparator(sep string) Option

WithDjangoSeparator sets the separator used in Django-style filter parameters. Default is "__" (double underscore).

func WithDjangoStyleFilters

func WithDjangoStyleFilters(fields ...string) Option

WithDjangoStyleFilters enables Django-style filter parsing for the specified fields. If no fields are provided, all fields are allowed (not recommended for security reasons).

func WithMode

func WithMode(m Mode) Option

WithMode sets the parsing/formatting mode.

func WithParamNames

func WithParamNames(p ParamNames) Option

WithParamNames sets custom parameter names.

func WithSortFormat

func WithSortFormat(f SortFormat) Option

WithSortFormat sets the sort format.

type ParamNames

type ParamNames struct {
	// Query is the parameter name for unified mode. Default: "query".
	Query string
	// Fields is the parameter name for the fields list. Default: "fields".
	Fields string
	// Filters is the parameter name for the filters JSON array. Default: "filters".
	Filters string
	// Sort is the parameter name for the sort specification. Default: "sort".
	Sort string
	// PageNum is the parameter name for the page number. Default: "page".
	PageNum string
	// PageSize is the parameter name for the page size. Default: "page_size".
	PageSize string

	// CursorAfter is the parameter name for forward cursor token. Default: "after".
	CursorAfter string
	// CursorBefore is the parameter name for backward cursor token. Default: "before".
	CursorBefore string
	// CursorLimit is the parameter name for cursor page size. Default: "limit".
	CursorLimit string
}

ParamNames allows customizing the URL parameter names used during parsing and formatting.

func DefaultParamNames

func DefaultParamNames() ParamNames

DefaultParamNames returns parameter names with sensible defaults.

type SortConfig

type SortConfig struct {
	// Format controls how sort is parsed/formatted. Default: SortFormatColonDir.
	Format SortFormat
}

SortConfig configures sort parsing and formatting.

type SortFormat

type SortFormat int

SortFormat controls how sort parameters are parsed and formatted.

const (
	// SortFormatColonDir uses "field:direction" pairs separated by commas.
	// Example: "name:asc,age:desc"
	// Nulls position can be appended: "name:asc:nulls_last".
	SortFormatColonDir SortFormat = iota

	// SortFormatSignPrefix uses a "-" prefix for descending, no prefix for ascending.
	// Example: "name,-age"
	// This format does not support nulls position.
	SortFormatSignPrefix

	// SortFormatJSON parses the sort parameter as a JSON array of sort objects,
	// using the same schema as the r3json dialect.
	// Example: [{"field":"name","direction":"asc"}].
	SortFormatJSON
)

Jump to

Keyboard shortcuts

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