query

package
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Sep 17, 2026 License: MIT Imports: 9 Imported by: 0

Documentation

Overview

Package query builds Payload REST query strings.

The split is load-bearing and verified live (§2.3, §9.5): `where` and `data` are URL-encoded JSON strings, while `select`, `populate`, `joins`, `sort`, `depth`, `limit`, `page`, `draft` and `trash` use qs bracket notation. Sending `select` as a JSON string is silently dropped by the server, and bracket notation cannot express JSON null — `where[jobTitle][equals]=null` matched 0 documents where the JSON form matched 23.

Index

Constants

View Source
const (
	OpEquals           = "equals"
	OpNotEquals        = "not_equals"
	OpGreaterThan      = "greater_than"
	OpGreaterThanEqual = "greater_than_equal"
	OpLessThan         = "less_than"
	OpLessThanEqual    = "less_than_equal"
	OpLike             = "like"
	OpNotLike          = "not_like"
	OpContains         = "contains"
	OpIn               = "in"
	OpNotIn            = "not_in"
	OpAll              = "all"
	OpExists           = "exists"
	OpNear             = "near"
	OpWithin           = "within"
	OpIntersects       = "intersects"
)

The 16 operators Payload implements (§2.3, fixed list).

View Source
const MaxQFields = 12

MaxQFields caps the fan-out of --q (§9.4).

View Source
const SinceForms = "N[h|d|w|mo] (12h 30d 4w 1mo) · a Go duration (720h 90m 36h30m) · YYYY-MM-DD · full RFC 3339"

SinceForms documents the accepted --since/--until spellings; it is quoted verbatim in the error message so an agent never has to guess.

Variables

Operators is the canonical operator list, sorted.

Functions

func BoolPtr

func BoolPtr(b bool) *bool

func Canonical

func Canonical(alias string) (string, bool)

Canonical resolves an alias to the Payload operator it means.

func CheckOperator

func CheckOperator(op, dbAdapter, adapterSource string) error

CheckOperator implements §9.3's tri-state rule for adapter-specific operators: reject locally only when PayCLI actually knows the adapter is Postgres. "unknown" means send it and learn.

func CheckPathSyntax

func CheckPathSyntax(path string) error

CheckPathSyntax rejects a path that cannot be a field path before it reaches the server, where an unknown path is a 400 QueryError at best and silently ignored at worst.

func EncodePairs

func EncodePairs(pairs []Pair) string

EncodePairs joins pairs with '&'.

func EscapeLike

func EscapeLike(s string) string

EscapeLike escapes the SQL LIKE metacharacters so a user's literal `%` or `_` is matched as itself. Verified live on the Postgres adapter.

func ExtractOperators

func ExtractOperators(w Where) []string

ExtractOperators returns every operator used in a where clause, sorted.

func ExtractPaths

func ExtractPaths(w Where) []string

ExtractPaths returns every field path a where clause queries, sorted and de-duplicated. `and` and `or` are structure, not fields, so they are walked through rather than reported.

func IntPtr

func IntPtr(n int) *int

IntPtr and BoolPtr are helpers for building Params literals.

func IsOperator

func IsOperator(s string) bool

IsOperator reports whether s is a canonical Payload operator.

func KnownAliases

func KnownAliases() []string

KnownAliases lists every accepted spelling of every operator, sorted.

func ParseSince

func ParseSince(expr string, now time.Time) (time.Time, error)

ParseSince resolves a --since/--until expression to an absolute instant. `now` is passed in (never read from the clock here) so the resolution is deterministic under test, per §3.1 and §9.4.

func SplitList

func SplitList(s string) []string

SplitList splits a comma-separated list, honouring `\,` as a literal comma and `\\` as a literal backslash.

func TypeValue

func TypeValue(raw string) (any, error)

TypeValue applies §9.4 value typing to one raw token:

null            -> JSON null
true / false    -> bool
1, -2, 3.5, 1e6 -> number (kept as json.Number so it round-trips verbatim)
"123" / '123'   -> string (quotes force a string)
json:…          -> raw JSON
anything else   -> string

This typing is the entire reason PayCLI emits JSON rather than bracket notation: the bracket form stringifies everything, and `equals=null` then silently matches nothing.

func TypedID

func TypedID(id, idType string) (any, error)

TypedID coerces one id to the collection's id_type. An unknown id_type is the tri-state "send it and learn" case: §9.4 typing applies and nothing is rejected locally.

func ValidateDateField

func ValidateDateField(field string, s Schema) error

ValidateDateField enforces §9.4's --date-field rule.

func ValidateLimit

func ValidateLimit(limit *int) error

ValidateLimit rejects `--limit 0`, which Payload reads as unlimited — an agent that means "no documents" would get every document instead.

func ValidateSelect

func ValidateSelect(fields []string, s Schema) error

ValidateSelect rejects an unknown --select key, which the server answers with HTTP 200 and a document containing only `id`.

func ValidateSort

func ValidateSort(fields []string, s Schema) error

ValidateSort rejects an unknown sort field. The server's behaviour here is the worst kind: `sort=bogusField` returns HTTP 200, silently unsorted.

func ValidateWhere

func ValidateWhere(w Where, s Schema) error

ValidateWhere checks every queried path and operator against the schema.

func WrapLike

func WrapLike(s string) string

WrapLike wraps a value in %…% unless the caller already did.

Types

type Input

type Input struct {
	Where []string // --where, ANDed
	Or    []string // --or, one OR group ANDed with the rest

	// WhereJSON is --where-json, which replaces everything else (§9.4).
	WhereJSON string

	// IDs is --id/--ids sugar, compiled to {"id":{"in":[…]}}.
	IDs []string
	// IDType is the manifest's id_type: "number", "string" or "unknown".
	// Unknown means §9.4 typing decides, never a fabricated rejection.
	IDType string

	DraftOnly     bool
	PublishedOnly bool

	// Q is --q: an OR of `contains` across QFields.
	Q       string
	QFields []string

	// Extra terms already compiled by the caller (e.g. --since/--until).
	Extra []Where

	Options ParseOptions
}

Input is everything the filter flags contribute to one where clause.

type Pair

type Pair struct {
	Key   string
	Value string
}

Pair is one already-escaped query-string parameter.

func Brackets

func Brackets(prefix string, v any) ([]Pair, error)

Brackets renders a nested value into qs bracket notation under prefix:

Brackets("select", map[string]any{"hero": map[string]any{"media": true}})
  -> select[hero][media]=true

Map keys are emitted in sorted order so the output is deterministic, and slices become [0], [1], … in index order.

A JSON null anywhere in the tree is a hard error: bracket notation has no syntax for it and the server reads the four characters "null" as the string "null", which silently matches nothing (verified: where[jobTitle][equals]=null returned 0 documents where the JSON form returned 23).

func WhereBrackets

func WhereBrackets(w Where) ([]Pair, error)

WhereBrackets renders a where tree in bracket notation for --where-style qs. It is a debugging aid; StyleJSON is what PayCLI sends by default.

func (Pair) String

func (p Pair) String() string

String renders "key=value".

type Params

type Params struct {
	Where      Where
	WhereStyle WhereStyle
	// WhereRaw is --where-raw: a literal query string appended verbatim.
	WhereRaw string
	// Data is the rare `data=` query parameter (URL-encoded JSON, like where).
	Data any

	Sort  []string
	Limit *int
	Page  int
	Depth *int

	Select        []string
	SelectExclude []string
	// Populate is populate[collection][field]=true.
	Populate map[string][]string
	// Joins is joins[field][limit]=5.
	Joins map[string]map[string]string

	Draft *bool
	Trash *bool

	Locale         string
	FallbackLocale string

	// Extra carries anything a caller needs that this struct does not model
	// (pay raw --query k=v). Keys are emitted in sorted order.
	Extra url.Values
}

Params is every query parameter PayCLI knows how to send. Zero values are omitted, so one type serves find, get, count, create, update and upload.

func (Params) Clone

func (p Params) Clone() Params

Clone returns a shallow-enough copy that callers can adjust one field without mutating a shared Params.

func (Params) Encode

func (p Params) Encode() (string, error)

Encode renders the full query string. Parameter order is fixed so that a golden test can assert on the exact bytes: where, data, select, populate, joins, sort, depth, limit, page, draft, trash, locale, fallback-locale, extras (sorted), then --where-raw verbatim.

type ParseOptions

type ParseOptions struct {
	// ReadFile resolves an @file.geojson argument. Nil means @file is refused
	// rather than silently treated as a string — the query package performs no
	// I/O of its own.
	ReadFile func(path string) ([]byte, error)
	// NoEscapeContains disables the `contains` escaping for a caller that
	// genuinely wants LIKE wildcards.
	NoEscapeContains bool
	// NoWrapNotLike disables the not_like auto-wrap.
	NoWrapNotLike bool
}

ParseOptions tunes term parsing. The zero value is the safe default.

type Schema

type Schema struct {
	// Collection is the slug, for error messages only.
	Collection string
	// Queryable lists field paths that may appear in a where clause.
	Queryable []string
	// Sortable lists field paths that may appear in --sort.
	Sortable []string
	// Selectable lists field paths that may appear in --select.
	Selectable []string
	// DateFields lists fields with payload_type "date".
	DateFields []string
	// DBAdapter / DBAdapterSource gate the adapter-specific operators.
	DBAdapter       string
	DBAdapterSource string
}

Schema is the slice of the manifest the query layer needs. Every slice is tri-state: a nil slice means "PayCLI never learned this", and §9.3's rule is that an unknown fact is never a local rejection — the request is sent and a *_unknown warning is attached by the caller. An empty non-nil slice means "known to be empty" and does reject.

type Where

type Where map[string]any

Where is a Payload where-clause tree: {"and":[…]}, {"or":[…]} or {"field":{"operator":value}}.

func And

func And(terms ...Where) Where

And ANDs the non-empty terms. A single term is returned unwrapped so the simplest query stays the simplest string.

func Build

func Build(in Input) (Where, error)

Build compiles the whole filter into one Where clause.

func BuildTerm

func BuildTerm(path, alias, raw string, opts ParseOptions) (Where, error)

BuildTerm compiles one path/operator/value triple into a Where clause.

func Combine

func Combine(and []Where, or []Where) Where

Combine implements §9.4's composition rule: --where terms are ANDed, and the repeatable --or terms form exactly one OR group which is ANDed with them.

func DateTerm

func DateTerm(field string, since, until *time.Time) Where

DateTerm compiles a resolved --since/--until bound against a date field.

func IDTerm

func IDTerm(ids []string, idType string) (Where, error)

IDTerm compiles --id/--ids into {"id":{"in":[…]}}, typing each id against the collection's id_type when it is known.

func Or

func Or(terms ...Where) Where

Or ORs the non-empty terms.

func ParseTerm

func ParseTerm(term string, opts ParseOptions) (Where, error)

ParseTerm parses one `--where` / `--or` term: at most three whitespace-separated tokens — path, operator, rest-of-string-as-value — so a value containing spaces needs no quoting.

func ParseWhereJSON

func ParseWhereJSON(s string) (Where, error)

ParseWhereJSON decodes --where-json, rejecting anything that is not a JSON object so `--where-json '[…]'` fails here rather than as an opaque server 400.

func QTerm

func QTerm(text string, fields []string) (Where, error)

QTerm expands --q into an OR of `contains` across up to MaxQFields fields.

func Term

func Term(path, op string, value any) Where

Term builds {path: {op: value}}.

func (Where) Encode

func (w Where) Encode() (string, error)

Encode returns the URL-encoded JSON form used as the `where=` value.

func (Where) IsEmpty

func (w Where) IsEmpty() bool

IsEmpty reports whether the clause would contribute nothing to a request.

func (Where) JSON

func (w Where) JSON() (string, error)

JSON marshals the clause. Go's encoder sorts map keys, so the output is deterministic and therefore golden-testable.

type WhereStyle

type WhereStyle string

WhereStyle selects the encoding of the `where` parameter.

const (
	// StyleJSON is the default and the only style that can express null.
	StyleJSON WhereStyle = "json"
	// StyleQS emits bracket notation for debugging and URL-pasting
	// (--where-style qs). It fails loudly on a null comparison rather than
	// silently returning the wrong documents.
	StyleQS WhereStyle = "qs"
)

func ParseWhereStyle

func ParseWhereStyle(s string) (WhereStyle, error)

ParseWhereStyle validates a --where-style value.

Jump to

Keyboard shortcuts

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