Documentation
¶
Overview ¶
Package query provides to extract the element from a Go value.
ParseString parses a query string and returns the query which extracts the value.
q, err := query.ParseString(`$.key[0].key['key']`) v, err := q.Extract(ctx, target)
Query Syntax ¶
The query syntax understood by this package when parsing is as follows.
$ the root element
.key extracts by a key of map or field name of struct ("." can be omitted if the head of query)
['key'] same as the ".key" (if the key contains "\" or "'", these characters must be escaped like "\\", "\'")
[0] extracts by an index of array or slice (a negative index counts from the end: [-1] is the last element), or by an integer key of map
Index ¶
- Variables
- func IsCaseInsensitive(ctx context.Context) bool
- type ExtractFunc
- type Extractor
- type Index
- type IndexExtractor
- type Key
- type KeyExtractor
- type NotFoundError
- type Option
- func CaseInsensitive() Option
- func CustomExtractFunc(f func(ExtractFunc) ExtractFunc) Option
- func CustomIsInlineStructFieldFunc(f func(reflect.StructField) bool) Option
- func CustomStructFieldNameGetter(f func(f reflect.StructField) string) Optiondeprecated
- func ExtractByStructTag(tagNames ...string) Option
- func OptionsFromContext(ctx context.Context) []Option
- type Query
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ErrNotFound = errors.New("not found")
ErrNotFound is the sentinel error that reports the queried element as absent. Extractor implementations return it (optionally wrapped) when the key or index does not match anything; any other error is treated as an extraction failure and aborts the query.
Callers can test a *Query.Extract error with errors.Is(err, ErrNotFound) to tell a genuinely absent value apart from a failure such as a context cancellation that interrupted a blocking extractor.
Functions ¶
func IsCaseInsensitive ¶
IsCaseInsensitive reports whether case-insensitive querying is enabled or not.
Types ¶
type ExtractFunc ¶
ExtractFunc is the type of the extraction function customized by the CustomExtractFunc option.
type Extractor ¶
type Extractor interface {
Extract(ctx context.Context, v reflect.Value) (reflect.Value, error)
String() string
}
An Extractor interface is used by a query to extract the element from a value. Extract returns the extracted value, or ErrNotFound (optionally wrapped) when the element is absent; any other error is treated as an extraction failure and aborts the query.
type Index ¶
type Index struct {
// contains filtered or unexported fields
}
Index represents an extractor to access the value by index.
For slices and arrays, a negative index accesses the sequence from the end: -1 is the last element, -2 is the second to last, and so on, following the convention of RFC 9535 (JSONPath). An index that remains out of range after this normalization is reported as absent.
For maps with an integer-kinded key type (and interface-keyed maps holding int keys), the index is looked up as the literal map key with no normalization: maps have no order, so -1 means the key -1. Maps with a floating-point key type are deliberately not supported, matching the map key policies of protobuf and CEL: key lookup by equality is unreliable for floating-point values.
Note that a value implementing IndexExtractor receives the index as given (possibly negative); handling negative indices is up to the implementation.
type IndexExtractor ¶
IndexExtractor is the interface that wraps the ExtractByIndex method.
ExtractByIndex extracts the value by index. It returns the found value, or ErrNotFound (optionally wrapped) when the index is absent; any other error is treated as an extraction failure and aborts the whole query.
type Key ¶
type Key struct {
// contains filtered or unexported fields
}
Key represents an extractor to access the value by key.
type KeyExtractor ¶
KeyExtractor is the interface that wraps the ExtractByKey method.
ExtractByKey extracts the value by key. It returns the found value, or ErrNotFound (optionally wrapped) when the key is absent; any other error is treated as an extraction failure and aborts the whole query.
Example ¶
package main
import (
"context"
"fmt"
"github.com/zoncoen/query-go/v2"
)
type orderedMap struct {
elems []*elem
}
type elem struct {
k, v any
}
func (m *orderedMap) ExtractByKey(_ context.Context, key string) (any, error) {
for _, e := range m.elems {
if k, ok := e.k.(string); ok {
if k == key {
return e.v, nil
}
}
}
return nil, query.ErrNotFound
}
func main() {
q := query.New().Key("key")
v, _ := q.Extract(context.Background(), &orderedMap{
elems: []*elem{{k: "key", v: "value"}},
})
fmt.Println(v)
}
Output: value
type NotFoundError ¶
type NotFoundError struct {
// Query is the string representation of the whole query.
Query string
// FailedAt is the prefix of the query up to and including the extractor
// that did not match, e.g. ".a.b" when ".a.b.c" failed at "b".
FailedAt string
// Err is the error reported by the extractor that did not match. It
// preserves the diagnostic of an extractor that wrapped ErrNotFound
// (e.g. "stream ended after 3 messages: not found") and, when the
// extractor ran a sub-query, the inner *NotFoundError. It is exposed
// via Unwrap, not via Error, so the message stays stable.
Err error
}
NotFoundError is the error returned by Query.Extract when the queried element is absent. It matches ErrNotFound with errors.Is and carries the position information of the failure.
func (*NotFoundError) Error ¶
func (e *NotFoundError) Error() string
Error implements the error interface.
func (*NotFoundError) Is ¶
func (e *NotFoundError) Is(target error) bool
Is reports whether target is ErrNotFound, so that errors.Is(err, ErrNotFound) matches a *NotFoundError.
func (*NotFoundError) Unwrap ¶
func (e *NotFoundError) Unwrap() error
Unwrap returns the extractor's original error.
type Option ¶
type Option func(*Query)
Option represents an option for Query.
func CaseInsensitive ¶
func CaseInsensitive() Option
CaseInsensitive returns the Option to match case insensitivity.
Example ¶
package main
import (
"context"
"fmt"
"github.com/zoncoen/query-go/v2"
)
// Person represents a person.
type Person struct {
Name string `json:"name,omitempty"`
}
func main() {
person := Person{
Name: "Alice",
}
q := query.New(query.CaseInsensitive()).Key("NAME")
name, _ := q.Extract(context.Background(), person)
fmt.Println(name)
}
Output: Alice
func CustomExtractFunc ¶
func CustomExtractFunc(f func(ExtractFunc) ExtractFunc) Option
CustomExtractFunc returns the Option to customize the behavior of extractors.
Example ¶
package main
import (
"context"
"fmt"
"reflect"
"github.com/zoncoen/query-go/v2"
)
// Person represents a person.
type Person struct {
Name string `json:"name,omitempty"`
}
func main() {
person := Person{
Name: "Alice",
}
q := query.New(
query.CustomExtractFunc(func(f query.ExtractFunc) query.ExtractFunc {
return func(ctx context.Context, v reflect.Value) (reflect.Value, error) {
return reflect.ValueOf("Bob"), nil
}
}),
).Key("name")
name, _ := q.Extract(context.Background(), person)
fmt.Println(name)
}
Output: Bob
func CustomIsInlineStructFieldFunc ¶
func CustomIsInlineStructFieldFunc(f func(reflect.StructField) bool) Option
CustomIsInlineStructFieldFunc returns the Option to customize the behavior of extractors.
func CustomStructFieldNameGetter
deprecated
func CustomStructFieldNameGetter(f func(f reflect.StructField) string) Option
CustomStructFieldNameGetter returns the Option to set f as custom function which gets struct field name. f is called by Key.Extract to get struct field name, if the target value is a struct.
Deprecated: Use CustomExtractFunc instead.
Example ¶
package main
import (
"context"
"fmt"
"reflect"
"strings"
"github.com/zoncoen/query-go/v2"
)
// Person represents a person.
type Person struct {
Name string `json:"name,omitempty"`
}
// getFieldNameByJSONTag returns the JSON field tag as field name if exists.
func getFieldNameByJSONTag(field reflect.StructField) string {
tag, ok := field.Tag.Lookup("json")
if ok {
strs := strings.Split(tag, ",")
return strs[0]
}
return field.Name
}
func main() {
person := Person{
Name: "Alice",
}
q := query.New(
query.CustomStructFieldNameGetter(getFieldNameByJSONTag),
).Key("name")
name, _ := q.Extract(context.Background(), person)
fmt.Println(name)
}
Output: Alice
func ExtractByStructTag ¶
ExtractByStructTag returns the Option to allow extracting by struct tag. The tag names are copied, so later mutation of a slice passed with ... has no effect on the option.
Example ¶
package main
import (
"context"
"fmt"
"github.com/zoncoen/query-go/v2"
)
// Person represents a person.
type Person struct {
Name string `json:"name,omitempty"`
}
func main() {
person := Person{
Name: "Alice",
}
q := query.New(query.ExtractByStructTag("json")).Key("name")
name, _ := q.Extract(context.Background(), person)
fmt.Println(name)
}
Output: Alice
func OptionsFromContext ¶
OptionsFromContext returns the options of the query that initiated the current extraction, or nil outside an extraction. An extractor implementation that builds a sub-query — e.g. a KeyExtractor delegating into a nested structure — can pass them to New so that the caller's configuration (struct tags, custom extract funcs, ...) applies to the nested extraction as well, without any global registry:
q := query.New(query.OptionsFromContext(ctx)...).Key("nested")
The returned slice is a copy: appending to it or mutating it in place cannot affect other extractors in the same extraction.
type Query ¶
type Query struct {
// contains filtered or unexported fields
}
Query represents a query to extract the element from a value.
func ParseString ¶
ParseString parses a query string s and returns the corresponding Query.
Example ¶
package main
import (
"context"
"fmt"
"github.com/zoncoen/query-go/v2"
)
type S struct {
Maps []map[string]map[string]string
}
func main() {
q, err := query.ParseString(`$.Maps[0].key['.key\'']`)
if err == nil {
v, _ := q.Extract(context.Background(), &S{
Maps: []map[string]map[string]string{
{"key": map[string]string{
".key'": "value",
}},
},
})
fmt.Println(v)
}
}
Output: value
func (*Query) Extract ¶
Extract extracts the value by q from target, passing ctx to each extractor (e.g. a value implementing KeyExtractor or IndexExtractor).
When the queried element is absent, the returned error is a *NotFoundError matching ErrNotFound via errors.Is. Any other error reported by an extractor — e.g. a context cancellation that interrupted a blocking extractor — aborts the extraction and is returned wrapped with the position of the failing extractor.
func (*Query) Extractors ¶
Extractors returns a copy of the query extractors of q, so that mutating the returned slice cannot corrupt q. Note that extractors carry a snapshot of the options they were created with, but a query rebuilt from them via Append does not: OptionsFromContext inside such a query reflects the new query's own options only.
func (Query) Index ¶
Index is shorthand method to create Index and appends it. For slices and arrays, a negative i accesses the sequence from the end (-1 is the last element); for integer-keyed maps, i is the literal map key. See Index for the exact semantics.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
Package ast declares the types used to represent syntax trees.
|
Package ast declares the types used to represent syntax trees. |
|
Package parser implements a parser for a query string.
|
Package parser implements a parser for a query string. |
|
Package token defines constants representing the lexical tokens.
|
Package token defines constants representing the lexical tokens. |