query

package
v0.4.0 Latest Latest
Warning

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

Go to latest
Published: Jul 28, 2026 License: MIT Imports: 11 Imported by: 0

Documentation

Overview

Package query provides allowlist-based filtering, sorting, and pagination for list endpoints, driven by bracketed query parameters.

URL contract:

GET /tasks?filter[completed]=true&filter[title]=report
          &filter[created_at][gte]=2026-01-01
          &sort=-created_at,title&page=2&per_page=25

Only developer-declared filters and sorts are accepted; unknown names, unsupported operators, and malformed pagination values are rejected with a canonical 400 invalid_query error. Column names reach SQL exclusively from the allowlist and user values only ever bind as arguments.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func EncodeCursor

func EncodeCursor(c Cursor) string

EncodeCursor renders the cursor as an opaque, unpadded base64url token.

func NextCursor

func NextCursor[T any](r Result, items []T, key func(T) (value, id string)) ([]T, string)

NextCursor trims the probe row fetched by CursorLimit and derives the next request's cursor from the last visible item. It returns the visible page and the encoded next cursor, or "" when the page was not full.

Types

type Cursor

type Cursor struct {
	// Value store data used by this type.
	Value string
	// ID store data used by this type.
	ID string
}

Cursor is a decoded keyset-pagination position: the sort value and id of the last row on the previous page. Both bind as strings, like Compare filter values.

func DecodeCursor

func DecodeCursor(raw string) (Cursor, error)

DecodeCursor parses a token produced by EncodeCursor.

type CursorMeta

type CursorMeta struct {
	// NextCursor store data used by this type.
	NextCursor *string `json:"next_cursor"`
	// PerPage store data used by this type.
	PerPage int `json:"per_page"`
}

CursorMeta is the pagination metadata for cursor mode. NextCursor is null on the last page.

type Filter

type Filter struct {
	// contains filtered or unexported fields
}

Filter declares one allowed filter parameter.

func Compare

func Compare(name string) Filter

Compare matches filter[name]=v as equality and filter[name][gte|lte|gt|lt]=v as range comparisons.

func Exact

func Exact(name string) Filter

Exact matches filter[name]=value as column = value.

func In

func In(name string) Filter

In matches filter[name]=a,b,c as column IN (a, b, c).

func Partial

func Partial(name string) Filter

Partial matches filter[name]=value as a contains search (LIKE, escaped).

func (Filter) Bool

func (f Filter) Bool() Filter

Bool declares the filter value as boolean: accepted values parse with strconv.ParseBool and bind as native booleans, which compares correctly against boolean columns on every supported database.

func (Filter) Column

func (f Filter) Column(column string) Filter

Column maps the public parameter name to a different database column.

type FilterValue

type FilterValue struct {
	// Name store data used by this type.
	Name string
	// Column store data used by this type.
	Column string
	// Op store data used by this type.
	Op Op
	// Values store data used by this type.
	Values []string
	// Bool marks values that bind as native booleans.
	Bool bool
}

FilterValue is one accepted filter with its bound values.

type Meta

type Meta struct {
	// Page store data used by this type.
	Page int `json:"page"`
	// PerPage store data used by this type.
	PerPage int `json:"per_page"`
	// Total store data used by this type.
	Total int64 `json:"total"`
	// TotalPages store data used by this type.
	TotalPages int64 `json:"total_pages"`
}

Meta is the standard pagination metadata for httpx.List.

type Op

type Op string

Op identifies a filter operator.

const (
	// OpEq define package-level implementation state.
	OpEq Op = "eq"
	// OpLike define package-level implementation state.
	OpLike Op = "like"
	// OpIn define package-level implementation state.
	OpIn Op = "in"
	// OpGte define package-level implementation state.
	OpGte Op = "gte"
	// OpLte define package-level implementation state.
	OpLte Op = "lte"
	// OpGt define package-level implementation state.
	OpGt Op = "gt"
	// OpLt define package-level implementation state.
	OpLt Op = "lt"
)

type Options

type Options struct {
	// AllowedFilters store data used by this type.
	AllowedFilters []Filter
	// AllowedSorts store data used by this type.
	AllowedSorts []Sort
	// DefaultSort is applied when the request has no sort parameter, e.g.
	// "-created_at". It must reference an allowed sort.
	DefaultSort string
	// DefaultPerPage defaults to 25.
	DefaultPerPage int
	// MaxPerPage clamps per_page and defaults to 100.
	MaxPerPage int
	// CursorSort switches the endpoint to cursor (keyset) pagination on the
	// named allowed sort. In cursor mode the page and sort parameters are
	// rejected, the sort is forced to CursorSort (descending when DefaultSort
	// starts with "-"), rows are tie-broken on the id column, and the cursor
	// parameter carries the keyset position.
	CursorSort string
}

Options declares what a list endpoint accepts.

type Result

type Result struct {
	// Filters store data used by this type.
	Filters []FilterValue
	// Sorts store data used by this type.
	Sorts []SortValue
	// Page store data used by this type.
	Page int
	// PerPage store data used by this type.
	PerPage int
	// CursorMode reports that the endpoint uses cursor (keyset) pagination.
	CursorMode bool
	// Cursor is the decoded keyset position, or nil on the first page.
	Cursor *Cursor
}

Result is a validated, normalized query ready to apply to a data source.

func Parse

func Parse(c *gin.Context, options Options) (Result, error)

Parse validates the request's filter, sort, page, and per_page parameters against options. Rejections return a 400 *httpx.Error with code invalid_query listing the offending parameters; allowlist configuration mistakes return a 500-class *httpx.Error. When Options.CursorSort is set the endpoint uses cursor (keyset) pagination instead: page and sort are rejected and the cursor parameter is decoded into Result.Cursor.

func (Result) ApplyCursorGORM

func (r Result) ApplyCursorGORM(db *gorm.DB) *gorm.DB

ApplyCursorGORM applies filters, the keyset predicate, the forced cursor ordering, and the probe-row limit (CursorLimit — never an offset) to a GORM chain. Trim the probe row with NextCursor before responding.

func (Result) ApplyGORM

func (r Result) ApplyGORM(db *gorm.DB) *gorm.DB

ApplyGORM applies filters, sorts, and pagination to a GORM chain.

func (Result) BuildCountSQL

func (r Result) BuildCountSQL(base string) (string, []any)

BuildCountSQL appends only WHERE to a base statement such as "SELECT COUNT(*) FROM tasks".

func (Result) BuildCursorSQL

func (r Result) BuildCursorSQL(base string) (string, []any)

BuildCursorSQL appends WHERE (filters plus the keyset predicate), ORDER BY, and "LIMIT ?" bound to CursorLimit — never OFFSET — to a base statement such as "SELECT id, title FROM tasks". sqlx callers pass the final statement through Rebind for their dialect.

func (Result) BuildSQL

func (r Result) BuildSQL(base string) (string, []any)

BuildSQL appends WHERE, ORDER BY, LIMIT, and OFFSET to a base statement such as "SELECT id, title FROM tasks".

func (Result) CountGORM

func (r Result) CountGORM(db *gorm.DB) (int64, error)

CountGORM counts the rows matching the filters in an isolated session, so the caller's chain can still receive ApplyGORM afterwards.

func (Result) CursorLimit

func (r Result) CursorLimit() int

CursorLimit returns the row limit for cursor mode: PerPage plus one probe row that detects whether a next page exists. Trim the probe row with NextCursor before responding.

func (Result) CursorMeta

func (r Result) CursorMeta(next string) CursorMeta

CursorMeta builds cursor pagination metadata for httpx.List; next == "" marks the last page and serializes next_cursor as null.

func (Result) FiltersGORM

func (r Result) FiltersGORM(db *gorm.DB) *gorm.DB

FiltersGORM applies only the filters, for use in count queries or custom chains.

func (Result) Meta

func (r Result) Meta(total int64) Meta

Meta builds pagination metadata from a total row count.

func (Result) Offset

func (r Result) Offset() int

Offset returns the row offset for the current page.

func (Result) OrderSQL

func (r Result) OrderSQL() string

OrderSQL renders "ORDER BY ..." for the accepted sorts, or "".

func (Result) WhereSQL

func (r Result) WhereSQL() (string, []any)

WhereSQL renders the filters as a parameterized SQL condition using '?' placeholders, e.g. "completed = ? AND title LIKE ? ESCAPE '!'". sqlx callers pass the final statement through Rebind for their dialect. The clause and args are empty when no filters are present.

type Sort

type Sort struct {
	// contains filtered or unexported fields
}

Sort declares one allowed sort field.

func SortBy

func SortBy(name string) Sort

SortBy allows sort=name and sort=-name.

func (Sort) Column

func (s Sort) Column(column string) Sort

Column maps the public sort name to a different database column.

type SortValue

type SortValue struct {
	// Column store data used by this type.
	Column string
	// Desc store data used by this type.
	Desc bool
}

SortValue is one accepted sort field.

Jump to

Keyboard shortcuts

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