client

package
v0.11.0 Latest Latest
Warning

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

Go to latest
Published: Nov 8, 2026 License: MIT Imports: 8 Imported by: 0

README

parse/client

Builds requests in parse's grammar from Go: typed filters, sort orders, list parameters, merge-patch members and JSON Patch operations, for SDKs that call a parse server. It imports only the standard library, and it is held to the same filter and patch corpora as the TypeScript SDK.

Quick Start

import (
	"net/http"
	"time"

	"github.com/ashtonian/pkg/parse/client"
)

// One catalog per resource, usually generated.
var Devices = struct {
	Name     client.SortableText
	Enabled  client.Field[bool]
	LastSeen client.SortableTime
}{client.NewSortableText("name"), client.NewField[bool]("enabled"), client.NewSortableTime("last_seen")}

func listRecent(req *http.Request) error {
	q, err := client.ListParams{
		Filter:   client.And(Devices.Name.Like("pump-%"), Devices.Enabled.Eq(true), Devices.LastSeen.Gte(client.Ago(24*time.Hour))),
		Sort:     client.Sort{Devices.LastSeen.Desc(), Devices.Name.Asc()},
		PageSize: 50,
	}.Values()
	if err != nil {
		return err
	}
	req.URL.RawQuery = q.Encode() // filter={"$and":[...]}&page_size=50&sort=-last_seen,name
	return nil
}

example_test.go runs this request, a merge patch and a JSON Patch document with checked output.

Field types

A catalog field's type follows the operators its value type can declare on the server, so a misspelt field or an operand of the wrong type does not compile. The server still refuses an operator a field does not allow (E2072).

Type Value Filter methods
Field[V] key, enum, boolean Eq, Ne, In, Nin, Null, NotNull
Ordered[V] number, decimal (Ordered[decimal.Decimal]: any type that marshals its exact text) Field's, Gt, Gte, Lt, Lte
Text string Ordered's, Like, ILike, Contains
Time (Ordered[Moment]) timestamp Ordered's, with At(t), Now(), Ago(d) or FromNow(d) operands
Document[V] JSON document Eq, Ne, Contains, HasKey, Null, NotNull
Elements[V] JSON array of objects Document's, Some, None (a filter over element members)
Relation[K] has-many or many-to-many Field's on target keys, Some, None (a filter over the target); Replace, Add, Remove membership operations
Reference[K] belongs-to Field's on the target key, Is, IsNot
Geo geographic Near(point, meters), Within(shape), Intersects(shape), Null, NotNull

SortableField[V], SortableOrdered[V], SortableText and SortableTime add Asc and Desc; a sort-only field is a SortKey.

A relative Moment is sent as the server's token (now-1d) and resolved by the server's clock, so the client's clock never skews it.

Encoding

  • Filter encodes every condition in operator form ({"name":{"$eq":"a"}}), so a document value whose members start with $ is never read as operators. And and Or flatten nested groups, so a filter built up in a loop stays within the server's nesting depth. The zero Filter matches every row and encodes as {}.
  • ListParams encodes the list parameters Resource.ParseList reads (filter, sort, cursor, page_size, include_total, include_deleted, search, facets, include, fields) and leaves zero members out.
  • Nullable[T] is a merge-patch (RFC 7386) member: with the omitzero tag option the zero value is absent, Null[T]() clears the field, Set(v) writes it.
  • Operation is a JSON Patch (RFC 6902) operation; a []Operation is the document. Pointer(tokens...) escapes member names into a JSON Pointer.

Errors

The client refuses only what the grammar cannot express; the server judges everything else. A refused filter carries its error (Filter.Err), and encoding it, or ListParams.Values, returns it.

Sentinel When
ErrEmptyOr Or() of no filters, which would match no row
ErrNegatedEmpty Not of the empty filter, which would match no row
ErrSubSecond A relative Moment that is not a whole number of seconds

API Reference

  • NewField[V], NewOrdered[V], NewText, NewTime, NewDocument[V], NewElements[V], NewRelation[K], NewReference[K], NewGeo, NewSortKey, NewSortable* — catalog fields by name
  • And, Or, Not — combine filters; Filter.IsZero, Filter.Err, Filter.MarshalJSON
  • At, Now, Ago, FromNow — timestamp operands
  • Point, Box, Polygon — geographic operands
  • Order, Sort — sort orders; Sort.String is the sort parameter
  • ListParams.Values — a list request's query parameters
  • Nullable[T], Null[T], Set — merge-patch members
  • Operation, Add, Remove, Replace, Move, Copy, Test, Pointer — JSON Patch

Testing

client_test.go pins each encoding. parse's client_conformance_test.go classifies every case of testdata/filter_conformance.json and testdata/patch_conformance.json:

  • the client builds it, and the server reads the same verdict, AST and SQL;
  • the client builds it, and the server refuses it with the corpus's code;
  • the client refuses it itself;
  • or the client's types cannot express it.

A new corpus case fails the test until it is classified. The same file holds the list parameters to ParseList, and checks that JSON Patch operations and geo filters parse.

Key Files

File Responsibility
doc.go Package overview
filter.go Filter, And, Or, Not, encoding, ErrEmptyOr, ErrNegatedEmpty
field.go Field, Ordered, Text, Time, SortKey and the sortable variants
moment.go Moment (At, Now, Ago, FromNow), ErrSubSecond
document.go Document, Elements, Relation, Reference
geo.go Geo, Point, Shape (Box, Polygon)
sort.go Order, Sort
list.go ListParams
patch.go Nullable, Operation, Pointer

Dependencies

  • Imports: standard library only
  • Imported by: parse's conformance tests; generated Go SDKs once they move off forge/sdkgo (A4.18)
  • Package boundary: standard-library-only request builders; no Parse server package imports

References

Documentation

Overview

Package client builds requests in parse's grammar from Go: filters, sort orders, list parameters, merge-patch members and JSON Patch operations. It imports only the standard library, so an SDK built on it depends on no server code.

A catalog of typed fields per resource, usually generated, names the fields and fixes their operand types, so a misspelt field or an operand of the wrong type does not compile:

var Devices = struct {
	Name     client.SortableText
	Enabled  client.Field[bool]
	LastSeen client.SortableTime
}{client.NewSortableText("name"), client.NewField[bool]("enabled"), client.NewSortableTime("last_seen")}

q, err := client.ListParams{
	Filter: client.And(Devices.Name.Like("pump-%"), Devices.LastSeen.Gte(client.Ago(24*time.Hour))),
	Sort:   client.Sort{Devices.LastSeen.Desc()},
}.Values()

The field types follow the operators each value type can declare; the server still refuses an operator a field does not allow. The client refuses only what the grammar cannot express: an Or of nothing, Not of the empty filter, and a relative time finer than a second.

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrEmptyOr reports an Or of no filters. A disjunction of nothing
	// matches no row, which the grammar cannot express.
	ErrEmptyOr = errors.New("client: Or needs at least one filter")
	// ErrNegatedEmpty reports Not of the empty filter, which would match no
	// row; the grammar cannot express that either.
	ErrNegatedEmpty = errors.New("client: Not of the empty filter matches nothing")
)
View Source
var ErrSubSecond = errors.New("client: a relative time is a whole number of seconds")

ErrSubSecond reports a relative Moment that is not a whole number of seconds, the server's finest relative unit.

Functions

func Pointer

func Pointer(tokens ...string) string

Pointer is the JSON Pointer (RFC 6901) to a member: tokens are member names, outermost first, escaped as the pointer requires.

Types

type Document

type Document[V any] struct {
	// contains filtered or unexported fields
}

Document is a JSON document field whose values have type V.

func NewDocument

func NewDocument[V any](name string) Document[V]

NewDocument returns the document field named name.

func (Document[V]) Contains

func (d Document[V]) Contains(v V) Filter

Contains matches rows whose document contains v: every member v encodes, at any depth, is in the document with the same value.

func (Document[V]) Eq

func (d Document[V]) Eq(v V) Filter

Eq matches rows whose document equals v.

func (Document[V]) HasKey

func (d Document[V]) HasKey(key string) Filter

HasKey matches rows whose document has the top-level member key.

func (Document[V]) Name

func (d Document[V]) Name() string

Name is the field's name in the grammar.

func (Document[V]) Ne

func (d Document[V]) Ne(v V) Filter

Ne matches rows whose document differs from v.

func (Document[V]) NotNull

func (d Document[V]) NotNull() Filter

NotNull matches rows whose document is not null.

func (Document[V]) Null

func (d Document[V]) Null() Filter

Null matches rows whose document is null.

type Elements

type Elements[V any] struct{ Document[V] }

Elements is a JSON array of objects whose element members the server declares; Some and None test one element against a filter over them.

func NewElements

func NewElements[V any](name string) Elements[V]

NewElements returns the element array named name.

func (Elements[V]) None

func (e Elements[V]) None(f Filter) Filter

None matches rows with no element that f matches.

func (Elements[V]) Some

func (e Elements[V]) Some(f Filter) Filter

Some matches rows with an element that f matches. f's fields are the element's members.

type Field

type Field[V any] struct {
	// contains filtered or unexported fields
}

Field is a filterable field whose values have type V, compared for equality, membership and null: a key, an enum, a boolean.

func NewField

func NewField[V any](name string) Field[V]

NewField returns the field named name.

func (Field[V]) Eq

func (f Field[V]) Eq(v V) Filter

Eq matches rows whose field equals v.

func (Field[V]) In

func (f Field[V]) In(vs ...V) Filter

In matches rows whose field is one of vs.

func (Field[V]) Name

func (f Field[V]) Name() string

Name is the field's name in the grammar.

func (Field[V]) Ne

func (f Field[V]) Ne(v V) Filter

Ne matches rows whose field differs from v.

func (Field[V]) Nin

func (f Field[V]) Nin(vs ...V) Filter

Nin matches rows whose field is none of vs.

func (Field[V]) NotNull

func (f Field[V]) NotNull() Filter

NotNull matches rows whose field is not null.

func (Field[V]) Null

func (f Field[V]) Null() Filter

Null matches rows whose field is null.

type Filter

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

Filter is a filter expression in parse's request grammar, sent as a list's filter parameter. The zero value matches every row. Filters are immutable: field methods build conditions, and And, Or and Not combine them.

A filter the grammar cannot express (an Or of nothing, Not of the empty filter, a sub-second relative time) carries its error, and encoding it returns that error.

func And

func And(filters ...Filter) Filter

And matches the rows every filter matches; And of no filters is the empty filter. Nested Ands are flattened, so a filter built up in a loop stays within the server's nesting depth.

func Not

func Not(f Filter) Filter

Not matches the rows f does not. Not of the empty filter is ErrNegatedEmpty.

func Or

func Or(filters ...Filter) Filter

Or matches the rows any filter matches. An Or holding the empty filter matches every row; an Or of no filters is ErrEmptyOr. Nested Ors are flattened, as And's are.

func (Filter) Err

func (f Filter) Err() error

Err is the error f carries, if the grammar cannot express it.

func (Filter) IsZero

func (f Filter) IsZero() bool

IsZero reports whether f is the empty filter, which matches every row.

func (Filter) MarshalJSON

func (f Filter) MarshalJSON() ([]byte, error)

MarshalJSON encodes f as a filter document: {} for the empty filter.

type Geo

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

Geo is a geographic field.

func NewGeo

func NewGeo(name string) Geo

NewGeo returns the geographic field named name.

func (Geo) Intersects

func (g Geo) Intersects(s Shape) Filter

Intersects matches rows whose geometry intersects s.

func (Geo) Name

func (g Geo) Name() string

Name is the field's name in the grammar.

func (Geo) Near

func (g Geo) Near(p Point, meters float64) Filter

Near matches rows within meters of p.

func (Geo) NotNull

func (g Geo) NotNull() Filter

NotNull matches rows whose field is not null.

func (Geo) Null

func (g Geo) Null() Filter

Null matches rows whose field is null.

func (Geo) Within

func (g Geo) Within(s Shape) Filter

Within matches rows inside s.

type ListParams

type ListParams struct {
	Filter Filter
	Sort   Sort
	// Cursor is the end_cursor of the page before the one to fetch; empty
	// fetches the first page.
	Cursor string
	// PageSize is the number of rows per page; 0 is the server's default.
	PageSize int
	// IncludeTotal asks for the number of matching rows.
	IncludeTotal bool
	// IncludeDeleted lists soft-deleted rows too.
	IncludeDeleted bool
	// Search is free text matched against the resource's search fields.
	Search string
	// Facets names the fields to count values of.
	Facets []string
	// Include names the relations to return with each row.
	Include []string
	// Fields names the members each row returns.
	Fields []string
}

ListParams is one list request: what parse's Resource.ParseList reads from a query string. Zero members are left out, so the server applies its defaults.

func (ListParams) Values

func (p ListParams) Values() (url.Values, error)

Values encodes p as query parameters. It fails only when the filter cannot be encoded (Filter.Err).

type Moment

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

Moment is a timestamp operand: an absolute time (At), or a time relative to the server's clock (Now, Ago, FromNow), which the server resolves when it reads the request, so the client's clock never skews the comparison.

func Ago

func Ago(d time.Duration) Moment

Ago is d before the server's current time.

func At

func At(t time.Time) Moment

At is the absolute time t.

func FromNow

func FromNow(d time.Duration) Moment

FromNow is d after the server's current time.

func Now

func Now() Moment

Now is the server's current time.

func (Moment) MarshalJSON

func (m Moment) MarshalJSON() ([]byte, error)

MarshalJSON encodes an absolute Moment in RFC 3339 and a relative one as the server's token: now, or now±N with the largest unit that states the offset exactly (now-7d is now-1w).

type Nullable

type Nullable[T any] struct {
	// contains filtered or unexported fields
}

Nullable is a member of a merge patch (RFC 7386) struct. The zero value is absent and, with the omitzero tag option, leaves the field alone; Null clears it; Set writes a value.

type DevicePatch struct {
	Name client.Nullable[string] `json:"name,omitzero"`
	Note client.Nullable[string] `json:"note,omitzero"`
}
body, err := json.Marshal(DevicePatch{Name: client.Set("pump"), Note: client.Null[string]()})
// {"name":"pump","note":null}

func Null

func Null[T any]() Nullable[T]

Null clears a field.

func Set

func Set[T any](v T) Nullable[T]

Set writes v to a field.

func (Nullable[T]) Get

func (n Nullable[T]) Get() (T, bool)

Get returns the value n writes and whether it writes one.

func (Nullable[T]) IsNull

func (n Nullable[T]) IsNull() bool

IsNull reports whether n clears its field.

func (Nullable[T]) IsZero

func (n Nullable[T]) IsZero() bool

IsZero reports whether n is absent, for the omitzero tag option.

func (Nullable[T]) MarshalJSON

func (n Nullable[T]) MarshalJSON() ([]byte, error)

MarshalJSON encodes a set value, and null otherwise. An absent member is left out by its struct's omitzero option, never encoded.

func (*Nullable[T]) UnmarshalJSON

func (n *Nullable[T]) UnmarshalJSON(data []byte) error

UnmarshalJSON reads null as Null and any other value as Set.

type Operation

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

Operation is one JSON Patch (RFC 6902) operation; a []Operation is a JSON Patch document. Build one with Add, Remove, Replace, Move, Copy, Test or a Relation's membership methods.

func Add

func Add(path string, value any) Operation

Add adds value at path.

func Copy

func Copy(from, path string) Operation

Copy copies the value at from to path.

func Move

func Move(from, path string) Operation

Move moves the value at from to path.

func Remove

func Remove(path string) Operation

Remove removes the value at path.

func Replace

func Replace(path string, value any) Operation

Replace replaces the value at path with value.

func Test

func Test(path string, value any) Operation

Test checks that the value at path equals value.

func (Operation) MarshalJSON

func (o Operation) MarshalJSON() ([]byte, error)

MarshalJSON encodes the operation with the members its op takes: value for add, replace and test (null included) and for a relation's remove, from for move and copy.

type Order

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

Order is one sort key and its direction, from a SortKey's Asc or Desc.

func (Order) String

func (o Order) String() string

String is the order as the sort parameter spells it: field, or -field.

type Ordered

type Ordered[V any] struct{ Field[V] }

Ordered is a field whose values have an order: a number, a decimal (any type that marshals as its exact text, such as shopspring's), a timestamp.

func NewOrdered

func NewOrdered[V any](name string) Ordered[V]

NewOrdered returns the ordered field named name.

func (Ordered[V]) Gt

func (f Ordered[V]) Gt(v V) Filter

Gt matches rows whose field is greater than v.

func (Ordered[V]) Gte

func (f Ordered[V]) Gte(v V) Filter

Gte matches rows whose field is at least v.

func (Ordered[V]) Lt

func (f Ordered[V]) Lt(v V) Filter

Lt matches rows whose field is less than v.

func (Ordered[V]) Lte

func (f Ordered[V]) Lte(v V) Filter

Lte matches rows whose field is at most v.

type Point

type Point struct {
	Lat float64 `json:"lat"`
	Lon float64 `json:"lon"`
}

Point is a WGS 84 coordinate.

type Reference

type Reference[K any] struct{ Field[K] }

Reference is a to-one (belongs-to) relation whose target key has type K. Is and IsNot filter by the target's fields.

func NewReference

func NewReference[K any](name string) Reference[K]

NewReference returns the reference named name.

func (Reference[K]) Is

func (r Reference[K]) Is(f Filter) Filter

Is matches rows whose referenced row f matches. f's fields are the target's.

func (Reference[K]) IsNot

func (r Reference[K]) IsNot(f Filter) Filter

IsNot matches rows whose referenced row f does not match, or that reference none.

type Relation

type Relation[K any] struct{ Field[K] }

Relation is a to-many relation, has-many or many-to-many, whose target keys have type K. Its key comparisons (Eq, In, Null, ...) ask whether a related row has that key; Some and None filter by the target's fields.

func NewRelation

func NewRelation[K any](name string) Relation[K]

NewRelation returns the relation named name.

func (Relation[K]) Add

func (r Relation[K]) Add(keys ...K) Operation

Add adds keys to the relation's members, as a JSON Patch operation.

func (Relation[K]) None

func (r Relation[K]) None(f Filter) Filter

None matches rows with no related row that f matches; the empty filter matches rows with no related row.

func (Relation[K]) Remove

func (r Relation[K]) Remove(keys ...K) Operation

Remove removes keys from the relation's members, as a JSON Patch operation. Unlike Remove of a path, it carries the keys.

func (Relation[K]) Replace

func (r Relation[K]) Replace(keys ...K) Operation

Replace sets the relation's members to keys, as a JSON Patch operation.

func (Relation[K]) Some

func (r Relation[K]) Some(f Filter) Filter

Some matches rows with a related row that f matches. f's fields are the target's; the empty filter matches rows with any related row.

type Shape

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

Shape is a region: a Box or a Polygon.

func Box

func Box(topLeft, bottomRight Point) Shape

Box is the region between a top-left and a bottom-right corner.

func Polygon

func Polygon(points ...Point) Shape

Polygon is the region inside points, in order; the server takes 3 to 100.

func (Shape) MarshalJSON

func (s Shape) MarshalJSON() ([]byte, error)

MarshalJSON encodes the shape as the server reads it.

type Sort

type Sort []Order

Sort is a list's sort order, most significant key first.

func (Sort) String

func (s Sort) String() string

String is the sort parameter: the orders joined by commas.

type SortKey

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

SortKey sorts by a field. A sort-only field is a SortKey; the Sortable field types embed one.

func NewSortKey

func NewSortKey(name string) SortKey

NewSortKey returns the sort key of the field named name.

func (SortKey) Asc

func (k SortKey) Asc() Order

Asc sorts by the field, ascending.

func (SortKey) Desc

func (k SortKey) Desc() Order

Desc sorts by the field, descending.

type SortableField

type SortableField[V any] struct {
	Field[V]
	SortKey
}

SortableField is a Field the server also sorts by.

func NewSortableField

func NewSortableField[V any](name string) SortableField[V]

NewSortableField returns the sortable field named name.

type SortableOrdered

type SortableOrdered[V any] struct {
	Ordered[V]
	SortKey
}

SortableOrdered is an Ordered field the server also sorts by.

func NewSortableOrdered

func NewSortableOrdered[V any](name string) SortableOrdered[V]

NewSortableOrdered returns the sortable ordered field named name.

type SortableText

type SortableText struct {
	Text
	SortKey
}

SortableText is a Text field the server also sorts by.

func NewSortableText

func NewSortableText(name string) SortableText

NewSortableText returns the sortable text field named name.

type SortableTime

type SortableTime = SortableOrdered[Moment]

SortableTime is a Time field the server also sorts by.

func NewSortableTime

func NewSortableTime(name string) SortableTime

NewSortableTime returns the sortable timestamp field named name.

type Text

type Text struct{ Ordered[string] }

Text is a string field, matched by pattern and substring as well.

func NewText

func NewText(name string) Text

NewText returns the text field named name.

func (Text) Contains

func (f Text) Contains(s string) Filter

Contains matches rows whose field contains s.

func (Text) ILike

func (f Text) ILike(pattern string) Filter

ILike is Like, ignoring case.

func (Text) Like

func (f Text) Like(pattern string) Filter

Like matches rows whose field matches the SQL LIKE pattern (% any run, _ one character, \ escapes).

type Time

type Time = Ordered[Moment]

Time is a timestamp field. Its operands are Moments: an absolute time, or one relative to the server's clock.

func NewTime

func NewTime(name string) Time

NewTime returns the timestamp field named name.

Jump to

Keyboard shortcuts

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