query

package module
v0.4.6 Latest Latest
Warning

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

Go to latest
Published: Apr 13, 2026 License: MIT Imports: 9 Imported by: 1

README

Query

License Coverage GitHub Workflow Status Go Report Card Go PKG

Query is an adaptor of http query to expressions. Check adapters to convert it to sql or other expressions.

go get github.com/rakunlabs/query

Usage

Parse url and extract query parameters with RAW, give to query.Parse to convert it to expression.
Use an adapter to convert it to sql or other expressions.

urlStr := "http://example.com?name=foo,bar|nick=bar&age[lt]=1&_sort=-age&_limit=10&_offset=5&_fields=id,name"
parsedURL, err := url.Parse(urlStr)
// ...
query, err := query.Parse(parsedURL.RawQuery)
// ...
sql, params, err := adaptergoqu.Select(query, goqu.From("test")).ToSQL()
// ...

// Output:
// SQL: SELECT "id", "name" FROM "test" WHERE ((("name" IN (?, ?)) OR ("nick" = ?)) AND ("age" < ?)) ORDER BY "age" DESC LIMIT ? OFFSET ?
// Params: [foo bar bar 1 10 5]

If some value separated by , it will be converted to IN operator.
There are a list of [ ] operators that can be used in the query string:
eq, ne, gt, lt, gte, lte, like, ilike, nlike, nilike, in, nin, is, not, kv, jin, njin

Operator Description Example SQL
eq Equal name[eq]=foo or name=foo name = 'foo'
ne Not equal name[ne]=foo name != 'foo'
gt Greater than age[gt]=18 age > 18
lt Less than age[lt]=18 age < 18
gte Greater than or equal age[gte]=18 age >= 18
lte Less than or equal age[lte]=18 age <= 18
like LIKE pattern name[like]=%foo% name LIKE '%foo%'
ilike Case-insensitive LIKE name[ilike]=%foo% name ILIKE '%foo%'
nlike NOT LIKE name[nlike]=%foo% name NOT LIKE '%foo%'
nilike Case-insensitive NOT LIKE name[nilike]=%foo% name NOT ILIKE '%foo%'
in IN list name[in]=foo,bar or name=foo,bar name IN ('foo', 'bar')
nin NOT IN list name[nin]=foo,bar name NOT IN ('foo', 'bar')
is IS NULL name[is]= name IS NULL
not IS NOT NULL name[not]= name IS NOT NULL
kv JSONB containment (@>) meta[kv]=eyJhIjoxfQ meta @> '{"a":1}'
jin JSONB array has any (?|) tags[jin]=admin,editor tags ?&#124; array['admin','editor']
njin JSONB array has none (NOT ?|) tags[njin]=admin,editor NOT (tags ?&#124; array['admin','editor'])

_limit and _offset are used to limit the number of rows returned. 0 limit means no limit.
_fields is used to select the fields to be returned, comma separated.
_sort is used to sort the result set, can be prefixed with - to indicate descending order and comma separated to indicate multiple fields.
[] empty operator means in operator.
Paranteses () can be used to group expressions, | is used for OR operation and & is used for AND operation.

Parse Options

Options can be passed to query.Parse to customize parsing behavior:

WithKeyOperator

Sets the default operator for a specific key when no bracket operator is specified. This allows you to write cleaner query strings without explicit [op] brackets.

// Without WithKeyOperator: name=foo → name[eq]=foo (default)
// With WithKeyOperator:    name=foo → name[like]=foo
q, err := query.Parse("name=foo", query.WithKeyOperator("name", query.OperatorLike))

// Useful for JSONB array columns:
// tags=admin,editor → tags ?| array['admin','editor']
q, err := query.Parse("tags=admin,editor", query.WithKeyOperator("tags", query.OperatorJIn))

Explicit bracket operators always take priority over WithKeyOperator. If the query contains name[eq]=foo, the eq operator is used regardless of the WithKeyOperator setting.

WithKeyValueTransform

Sets a value transform function for a specific key. The function is applied to the raw value string before parsing, regardless of whether a bracket operator is present.

// Wrap value with % for LIKE queries
q, err := query.Parse("name=foo",
    query.WithKeyOperator("name", query.OperatorLike),
    query.WithKeyValueTransform("name", func(v string) string {
        return "%" + v + "%"
    }),
)
// Result: name[like]=%foo%
// SQL:    name LIKE '%foo%'

This also works with explicit bracket operators:

// name[ilike]=foo → name[ilike]=%foo%
q, err := query.Parse("name[ilike]=foo",
    query.WithKeyValueTransform("name", func(v string) string {
        return "%" + v + "%"
    }),
)
Validation

query.WithField is used to validate the field names.

  • WithNotIn is used to validate the field names that are not allowed.
  • WithIn is used to validate the field names that are allowed.
  • WithNotAllowed is used to validate the field names totally not allowed.

query.WithValues is used to validate the values of the fields.

  • WithNotIn is used to validate the values that are not allowed.
  • WithIn is used to validate the values that are allowed.
  • WithNotAllowed is used to validate the values totally not allowed.

query.WithValue is used to validate the values of the fields.

  • WithRequired is used to validate the values that are required.
  • WithNotEmpty is used to validate the values that are not empty.
  • WithNotIn is used to validate the values that are not allowed.
  • WithIn is used to validate the values that are allowed.
  • WithNotAllowed is used to validate the value that are not allowed.
  • WithOperator is used to validate the operator that is allowed.
  • WithNotOperator is used to validate the operator that is not allowed.
  • WithMax is used to validate the maximum of value, value must be a number.
  • WithMin is used to validate the minimum of value, value must be a number.

query.WithOffset is used to validate the offset value.

  • WithMax is used to validate the maximum of offset, value must be a number.
  • WithMin is used to validate the minimum of offset, value must be a number.
  • WithNotAllowed is used to validate the offset value that are not allowed.

query.WithLimit is used to validate the limit value.

  • WithMax is used to validate the maximum of limit, value must be a number.
  • WithMin is used to validate the minimum of limit, value must be a number.
  • WithNotAllowed is used to validate the limit value that are not allowed.

query.WithSort is used to validate the sort value.

  • WithNotIn is used to validate the sort value that are not allowed.
  • WithIn is used to validate the sort value that are allowed.
  • WithNotAllowed is used to validate the sort value that are not allowed.

Example of validation:

validator := query.NewValidator(
    WithValue("member", query.WithRequired(), query.WithNotIn("O", "P", "S")),
    WithValues(query.WithIn("age", "test", "member")),
    WithValue("age", query.WithOperator(OperatorEq), query.WithNotOperator(OperatorIn)),
    WithField(query.WithNotAllowed()),
)

// after that use it to validate
err := validator.Validate(query)
if err != nil {
    // handle error
}

// or pass with when parsing
query, err := query.Parse(rawQuery, query.WithValidator(validator))
// ...

Documentation

Index

Constants

View Source
const (
	// OperatorEmpty is the empty operator which is equal to OperatorIn.
	OperatorEmpty operatorCmpType = ""
	// OperatorEq is the equality operator.
	OperatorEq operatorCmpType = "eq"
	// OperatorNe is the not equal operator.
	OperatorNe operatorCmpType = "ne"
	// OperatorGt is the greater than operator.
	OperatorGt operatorCmpType = "gt"
	// OperatorLt is the less than operator.
	OperatorLt operatorCmpType = "lt"
	// OperatorGte is the greater than or equal operator.
	OperatorGte operatorCmpType = "gte"
	// OperatorLte is the less than or equal operator.
	OperatorLte operatorCmpType = "lte"
	// OperatorLike is the like operator.
	OperatorLike operatorCmpType = "like"
	// OperatorILike is the case insensitive like operator.
	OperatorILike operatorCmpType = "ilike"
	// OperatorNLike is the not like operator.
	OperatorNLike operatorCmpType = "nlike"
	// OperatorNILike is the case insensitive not like operator.
	OperatorNILike operatorCmpType = "nilike"
	// OperatorIn is the in operator.
	OperatorIn operatorCmpType = "in"
	// OperatorNIn is the not in operator.
	OperatorNIn operatorCmpType = "nin"
	// OperatorIs is the is null operator.
	OperatorIs operatorCmpType = "is"
	// OperatorIsNot is the is not null operator.
	OperatorIsNot operatorCmpType = "not"
	// OperatorKV is the contains operator JSON types.
	OperatorKV operatorCmpType = "kv"
	// OperatorJIn is the JSONB array "has any" operator (?|).
	OperatorJIn operatorCmpType = "jin"
	// OperatorNJIn is the negated JSONB array "has any" operator (NOT ?|).
	OperatorNJIn operatorCmpType = "njin"
)
View Source
const (
	// OperatorAnd is the AND operator.
	OperatorAnd operatorLogicType = "and"
	// OperatorOr is the OR operator.
	OperatorOr operatorLogicType = "or"
)

Variables

This section is empty.

Functions

func Base64URLDecode added in v0.4.0

func Base64URLDecode(s string) ([]byte, error)

Base64URLDecode decodes a base64 URL encoded string without padding.

func Base64URLEncode added in v0.4.0

func Base64URLEncode(v []byte) string

Base64URLEncode encodes v using base64 URL encoding without padding.

  • This useful for non-URL-safe strings that need to be included in URLs.
  • OperatorKV understands this encoding.

func StringToType added in v0.3.2

func StringToType(s string, valueType ValueType) (any, error)

func StringsToType added in v0.3.2

func StringsToType(ss []string, valueType ValueType) (any, error)

func WithIn

func WithIn(values ...string) optionValidateFunc

WithIn checks if the value is in the list of values.

  • Usable for 'WithValue', 'WithSort', 'WithValues', 'WithFields'

func WithMax

func WithMax(max string) optionValidateFunc

WithMax to validate the maximum of a value.

  • Usable for 'WithValue', 'WithLimit', 'WithOffset'

func WithMin

func WithMin(min string) optionValidateFunc

WithMin to validate the minimum of a value.

  • Usable for 'WithValue', WithSort', 'WithLimit'

func WithNotAllowed

func WithNotAllowed() optionValidateFunc

WithNotAllowed to validate the value is not allowed.

  • Usable for 'WithValue', 'WithOffset', 'WithLimit', 'WithSort', 'WithValues', 'WithFields'

func WithNotEmpty

func WithNotEmpty() optionValidateFunc

WithNotEmpty to validate the value is not empty.

  • Usable for 'WithValue'

func WithNotIn

func WithNotIn(values ...string) optionValidateFunc

WithNotIn checks if the value is not in the list of values.

  • Usable for 'WithValue', 'WithSort', 'WithValues', 'WithFields'

func WithNotOperator

func WithNotOperator(operators ...operatorCmpType) optionValidateFunc

WithNotOperator to validate the operator is not allowed.

  • Usable for 'WithValue'

func WithOperator

func WithOperator(operators ...operatorCmpType) optionValidateFunc

WithOperator to validate the operator is allowed.

  • Usable for 'WithValue'

func WithRequired

func WithRequired() optionValidateFunc

WithRequired to validate the value is required.

  • Usable for 'WithValue'

Types

type Expression

type Expression interface {
	Expression() Expression
	String() string
}

type ExpressionCmp

type ExpressionCmp struct {
	Operator operatorCmpType
	Field    string
	Value    any
}

func NewExpressionCmp added in v0.2.1

func NewExpressionCmp(operator operatorCmpType, field string, value any) *ExpressionCmp

NewExpressionCmp creates a new ExpressionCmp.

func ParseExpression added in v0.2.1

func ParseExpression(key, value string, valueType ValueType) (*ExpressionCmp, error)

ParseExpression parses a single expression from key-value pairs.

  • key -> key[eq]
  • eq, ne, gt, lt, gte, lte, like, ilike, nlike, nilike, in, nin, is, not, kv

func ParseExpressionWithOperator added in v0.2.1

func ParseExpressionWithOperator(operator string, key string, value string, valueType ValueType) (*ExpressionCmp, error)

func (*ExpressionCmp) Expression

func (e *ExpressionCmp) Expression() Expression

func (ExpressionCmp) String added in v0.2.2

func (e ExpressionCmp) String() string

type ExpressionLogic

type ExpressionLogic struct {
	Operator operatorLogicType
	List     []Expression
}

func NewExpressionLogic added in v0.4.0

func NewExpressionLogic(operator operatorLogicType, list []Expression) *ExpressionLogic

NewExpressionLogic creates a new ExpressionLogic.

func (*ExpressionLogic) Expression

func (e *ExpressionLogic) Expression() Expression

func (ExpressionLogic) String added in v0.2.2

func (e ExpressionLogic) String() string

type ExpressionSort

type ExpressionSort struct {
	// Field is the field name to order by.
	Field string
	// Desc indicates whether the order is descending.
	Desc bool
}

type KeyOption added in v0.4.6

type KeyOption func(key string, o *optionQuery)

KeyOption is a functional option scoped to a single key, used with WithKey.

func KeyCommaSplit added in v0.4.6

func KeyCommaSplit() KeyOption

KeyCommaSplit enables comma-separated value splitting for the key. When enabled, values containing commas are split and combined with OR (for positive operators) or AND (for negated operators like ne, nlike, nilike).

func KeyOperator added in v0.4.6

func KeyOperator(op operatorCmpType) KeyOption

KeyOperator sets the default operator for the key when no bracket operator is specified.

  • For example, KeyOperator(OperatorILike) will parse "name=foo" as "name[ilike]=foo".

func KeyValueTransform added in v0.4.6

func KeyValueTransform(fn func(string) string) KeyOption

KeyValueTransform sets a value transform function for the key. The function is applied to the raw value string before parsing.

  • For example, KeyValueTransform(func(v string) string { return "%" + v + "%" }) will parse "name=foo" as name=%foo%.

type OperatorCmpType

type OperatorCmpType = operatorCmpType

OperatorCmpType is the comparison operator type used in expressions.

type OptionQuery

type OptionQuery func(*optionQuery)

func WithCommaSplit added in v0.4.4

func WithCommaSplit(keys ...string) OptionQuery

WithCommaSplit enables comma-separated value splitting for the given keys. When enabled, values containing commas are split and combined with OR (for positive operators) or AND (for negated operators like ne, nlike, nilike).

This applies to all operators except in, nin, jin, njin (which already handle commas natively), and is, not, kv (which are single-value or special-format operators).

  • For example, WithCommaSplit("name") will parse "name[ilike]=%foo%,%bar%" as (name ILIKE '%foo%' OR name ILIKE '%bar%').
  • For negated operators: "name[nlike]=%foo%,%bar%" becomes (name NOT LIKE '%foo%' AND name NOT LIKE '%bar%').

func WithDefaultLimit

func WithDefaultLimit(limit uint64) OptionQuery

WithDefaultLimit sets the default limit value.

func WithDefaultOffset

func WithDefaultOffset(offset uint64) OptionQuery

WithDefaultOffset sets the default offset value.

func WithExpressionCmp

func WithExpressionCmp(key string, value *ExpressionCmp) OptionQuery

WithExpressionCmp sets the expression comparison for a given key.

func WithKey added in v0.4.6

func WithKey(key string, opts ...KeyOption) OptionQuery

WithKey groups multiple key-scoped options for a single key. This is a convenience wrapper that applies each KeyOption to the given key.

query.WithKey("title",
    query.KeyOperator(query.OperatorILike),
    query.KeyValueTransform(func(v string) string { return "%" + v + "%" }),
    query.KeyCommaSplit(),
)

func WithKeyOperator added in v0.4.2

func WithKeyOperator(key string, operator operatorCmpType) OptionQuery

WithKeyOperator sets the default operator for a given key when no bracket operator is specified.

  • For example, WithKeyOperator("name", OperatorLike) will parse "name=foo" as "name[like]=foo".

func WithKeyType added in v0.3.2

func WithKeyType(key string, valueType ValueType) OptionQuery

func WithKeyValueTransform added in v0.4.3

func WithKeyValueTransform(key string, fn func(string) string) OptionQuery

WithKeyValueTransform sets a value transform function for a given key. The function is applied to the raw value string before parsing, regardless of whether a bracket operator is present.

  • For example, WithKeyValueTransform("name", func(v string) string { return "%" + v + "%" }) will parse "name=foo" as name=%foo%.

func WithSkipExpressionCmp

func WithSkipExpressionCmp(key ...string) OptionQuery

WithSkipExpressionCmp sets the keys to be skipped in the query.

func WithSkipUnderscore added in v0.3.0

func WithSkipUnderscore(v bool) OptionQuery

WithSkipUnderscore sets whether to skip keys starting with underscore.

  • Default is true.

func WithUnderscorePrefix added in v0.4.1

func WithUnderscorePrefix(v bool) OptionQuery

WithUnderscorePrefix sets whether the special query keys use an underscore prefix.

  • Default is true: _limit, _offset, _sort, _fields.
  • When set to false: limit, offset, sort, fields.

type OptionValidate

type OptionValidate func(string, ...optionValidateFunc)

type OptionValidateSet

type OptionValidateSet func(v *Validator) error

func WithField

func WithField(opts ...optionValidateFunc) OptionValidateSet

func WithLimit

func WithLimit(opts ...optionValidateFunc) OptionValidateSet

func WithOffset

func WithOffset(opts ...optionValidateFunc) OptionValidateSet

func WithSort

func WithSort(opts ...optionValidateFunc) OptionValidateSet

func WithValue

func WithValue(key string, opts ...optionValidateFunc) OptionValidateSet

func WithValues

func WithValues(opts ...optionValidateFunc) OptionValidateSet

type Query

type Query struct {
	Values map[string][]*ExpressionCmp

	Select []string
	Where  []Expression
	Sort   []ExpressionSort
	Offset *uint64
	Limit  *uint64
}

func New added in v0.2.1

func New() *Query

func Parse

func Parse(query string, opts ...OptionQuery) (*Query, error)

Parse parses a query string into a Query struct.

func ParseWithValidator

func ParseWithValidator(query string, validator *Validator, opts ...OptionQuery) (*Query, error)

func (*Query) AddField added in v0.2.1

func (q *Query) AddField(fields ...string) *Query

func (*Query) AddSort added in v0.2.1

func (q *Query) AddSort(sorts ...ExpressionSort) *Query

func (*Query) AddWhere added in v0.2.1

func (q *Query) AddWhere(exprs ...Expression) *Query

func (*Query) CloneLimit

func (q *Query) CloneLimit() *uint64

func (*Query) CloneOffset

func (q *Query) CloneOffset() *uint64

func (*Query) GetLimit

func (q *Query) GetLimit() uint64

func (*Query) GetOffset

func (q *Query) GetOffset() uint64

func (*Query) GetValue

func (q *Query) GetValue(v string) string

func (*Query) GetValues

func (q *Query) GetValues(v string) []string

func (*Query) Has

func (q *Query) Has(v string) bool

func (*Query) HasAny

func (q *Query) HasAny(vList ...string) bool

func (*Query) MarshalText added in v0.2.2

func (q *Query) MarshalText() ([]byte, error)

func (*Query) SetLimit added in v0.2.1

func (q *Query) SetLimit(limit uint64) *Query

SetLimit sets the limit for the query.

  • if limit is <= 0, it means no limit.

func (*Query) SetOffset added in v0.2.1

func (q *Query) SetOffset(offset uint64) *Query

SetOffset sets the offset for the query.

  • if offset is <= 0, it means no offset.

func (*Query) Validate

func (q *Query) Validate(v *Validator) error

func (*Query) Walk

func (q *Query) Walk(fn func(Token) error) error

Walk traverses the query tree and calls the provided function for each expression.

type Token

type Token struct {
	Expression Expression
	Type       WalkType
}

type Validator

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

func NewValidator

func NewValidator(opts ...OptionValidateSet) (*Validator, error)

type ValueType added in v0.3.2

type ValueType string
const (
	ValueTypeString  ValueType = "string"
	ValueTypeNumber  ValueType = "number"
	ValueTypeBoolean ValueType = "boolean"
)

type WalkType

type WalkType int
const (
	WalkCurrent WalkType = iota
	WalkStart
	WalkEnd
)

Directories

Path Synopsis
adapter

Jump to

Keyboard shortcuts

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