lookup

package module
v1.0.4 Latest Latest
Warning

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

Go to latest
Published: Feb 2, 2026 License: BSD-3-Clause Imports: 10 Imported by: 0

Image README

lookup

lookup is a small library that brings dynamic navigation similar to JSONPath or JSONata to native Go structures. It works with structs, maps, arrays, slices and even functions while remaining null safe. The API exposes a few simple primitives that can be composed into complex queries.

This README outlines the core concepts, shows practical examples and documents the available modifiers and data structures. Many of the examples exist as runnable Go programs under examples/.

Why lookup?

While Go's strong typing is excellent for safety and performance, it can be cumbersome when dealing with deeply nested dynamic data or exploring unknown structures (like complex JSON/YAML configuration).

Standard approaches often involve:

  • Verbose type assertions at every step.
  • Risk of panics if a pointer is nil.
  • Complex reflection code that is hard to maintain.

lookup provides a middle ground: safe, dynamic navigation without the verbosity or risk. It allows you to write expressive queries to drill down into your data, automatically handling:

  • Nil checks (returns an error-implementing object instead of panicking).
  • Slice/Array indexing (including negative indices).
  • Map lookups.
  • Interface wrapping.

Installation

To use lookup as a library in your Go project:

go get github.com/arran4/lookup

Concepts

Concept Description
Pathor Interface returned from all queries. Exposes Find, Raw, Type and Value.
Reflector Implementation of Pathor based on reflection for arbitrary Go values. Use lookup.Reflect to create one.
Jsonor Lazily unmarshals raw JSON as fields are requested. Use lookup.Json to create one.
Yamlor Lazily unmarshals raw YAML as fields are requested. Use lookup.Yaml to create one.
Interfaceor Wraps a user defined Interface so you can implement custom lookups.
Constantor Holds a constant value and is often used internally by modifiers.
Invalidor Represents an invalid path while still implementing Pathor.
Relator Stores relative lookups used by modifiers such as This, Parent and Result.

JSONata Support

lookup includes a parsing engine for JSONata, a lightweight query and transformation language.

Basic Usage
import "github.com/arran4/lookup/jsonata"

// 1. Compile expression
ast, err := jsonata.Parse("Account.Orders[0].Product")
if err != nil {
    log.Fatal(err)
}
q := jsonata.Compile(ast)

// 2. Run against data
result := q.Run(&lookup.Scope{
    Current: lookup.Reflect(data),
})

fmt.Println(result.Raw())
Custom Functions

You can extend JSONata by registering custom functions. This leverages github.com/arran4/go-evaluator's Function interface.

// 1. Define function
type GreetFunc struct{}
func (g *GreetFunc) Call(args ...interface{}) (interface{}, error) {
    return "Hello " + args[0].(string), nil
}

// 2. Register
jsonata.Functions["$greet"] = &GreetFunc{}

// 3. Use in query
ast, _ := jsonata.Parse("$greet(Name)")
q := jsonata.Compile(ast)

Quick Start

The following short program demonstrates navigating a struct. You can run it with go run examples/basic_example.go.

package main

import (
    "log"

    "github.com/arran4/lookup"
)

type Node struct {
    Name string
    Size int
}

func main() {
    root := &Node{Name: "root", Size: 10}
    r := lookup.Reflect(root)

    log.Printf("name = %s", r.Find("Name").Raw())
    log.Printf("size = %d", r.Find("Size").Raw())
}

Running the program prints:

name = root
size = 10
JSON Example

Json lets you query raw JSON without fully unmarshalling it:

raw := []byte(`{"name":"root","sizes":[1,2,3]}`)
r := lookup.Json(raw)
log.Printf("last size = %d", r.Find("sizes", lookup.Index("-1")).Raw())
YAML Example

Yaml behaves the same for YAML input:

raw := []byte("name: root\nsizes:\n  - 1\n  - 2\n  - 3\n")
r := lookup.Yaml(raw)
log.Printf("first size = %d", r.Find("sizes", lookup.Index(0)).Raw())
Query Strings

For quick lookups the library understands a tiny query language that mirrors the Find API. Paths are written using dot notation with optional array/slice indexes in brackets. Negative indexes count from the end of the collection. The helper lookup.QuerySimplePath parses the expression and runs it against your value:

// Get the value of root.A.B[0].C
result := lookup.QuerySimplePath(root, "A.B[0].C").Raw()

// Last element using a negative index
last := lookup.QuerySimplePath(root, "A.B[-1].C").Raw()

If you need to reuse a query repeatedly you can compile it once using lookup.ParseSimplePath which returns a Relator that can be executed on any Pathor.

Modifiers

Modifiers are Runner implementations that transform the current scope of a lookup. They are passed to Find after the path name.

Modifier Purpose
Index(i) Select an element from an array or slice. Supports negative indexes.
Filter(r) Keep elements for which r returns true.
Map(r) Convert each element using r.
Contains(r) True if the current collection contains the result of r.
In(r) True if the current value is present in the collection returned by r.
Every(r) True if every element in scope matches r.
Any(r) True if any element in scope matches r.
Match(r) Proceed only if r evaluates to true.
If(c, t, o) When c is true run t otherwise o.
Default(v) Use v whenever the lookup would result in an invalid value.
Union(r) Combine the current collection with r removing duplicates.
Intersection(r) Elements present in both the current collection and r.
First(r) Return the first value matching r.
Last(r) Return the last value matching r.
Range(s, e) Like Index but returns a slice from s to e.
This(p) Parent(p) Result(p) Relative lookups executed from different points in a query.

See expression.go and collections.go for the full list of helpers.

Supported Data Structures

Input Description
Reflector Uses Go reflection to navigate arbitrary structs, maps, arrays, slices and functions. Channels are not supported.
Invalidor Indicates that the search reached an invalid path. It implements the error interface.
Constantor Similar to Invalidor but wraps a constant value. Attempting to navigate it does not change the position.
Interfaceor Like Reflector but relies on a user supplied interface to obtain children.
Jsonor Navigate raw JSON values without unmarshalling everything up front.
Yamlor Navigate raw YAML values without unmarshalling everything up front.
Relator Stores a path which can be replayed. Mostly used by modifiers for relative lookups.
Todo Data Structures
Data structure Description
Simpleor A type-switch based version of Reflector for a smaller set of inputs.

Planned / TODO

Modifier Category Description Input Output
Append(?) Collections Combine two results with duplicates
If(?, ?, ?) Expression Conditional
Error(?) Invalidor Returns an invalid / failed result

Basic Lookup Behaviour

The library works by calling Find with field names. Arrays are expanded automatically so subsequent lookups act as map operations over the elements. Each field navigation can be followed by modifiers. For example, Index selects a specific element:


lookup.Reflect(root).Find("Node2", lookup.Index("1")).Find("Size")

Here .Find("Node2") extracts an array and Index("1") picks a single element from it.

Functions with no arguments and a single return value (optionally followed by an error) can also be executed as part of a lookup.

log.Printf("%s", lookup.Reflect(root).Find("Method1").Raw())

All usage is null-safe. When a path does not exist or an error occurs you receive an object implementing error which still satisfies Pathor:

result := lookup.Reflect(root).Find("Node1").Find("DoesntExist")
if err, ok := result.(error); ok {
    panic(err)
}

Errors returned by functions are wrapped appropriately:

result := lookup.Reflect(root).Find("Method2")
if errors.Is(result, Err1) {
    // expected error
}

Advanced Usage

A runnable advanced example lives in examples/advanced/advanced_example.go and demonstrates combining modifiers for more complex queries:

r := lookup.Reflect(root)

// Filter children by tag and fetch their names
names := r.Find("Children",
    lookup.Filter(lookup.This("Tags").Find("", lookup.Contains(lookup.Constant("groupA"))))).
    Find("Name").Raw()

// Select the largest child size
largest := r.Find("Children", lookup.Map(lookup.This("Size")), lookup.Index("-1")).Raw()

// Check if any child has the tag "groupB"
hasB := r.Find("Children",
    lookup.Any(lookup.Map(lookup.This("Tags").Find("", lookup.Contains(lookup.Constant("groupB")))))).Raw()

A second runnable example demonstrates the collection helpers defined in examples/collections/collections_example.go:

numbers := []int{1, 2, 3, 3}
r := lookup.Reflect(numbers)

union := r.Find("", lookup.Union(lookup.Array(3, 4))).Raw()
intersection := r.Find("", lookup.Intersection(lookup.Array(2, 3, 4))).Raw()
first := r.Find("", lookup.First(lookup.Equals(lookup.Constant(3)))).Raw()
last := r.Find("", lookup.Last(lookup.Equals(lookup.Constant(3)))).Raw()
slice := r.Find("", lookup.Range(1, 3)).Raw()

Running the example prints:

union: []interface{}{1, 2, 3, 4}
intersection: []interface{}{2, 3}
first 3: 3
last 3: 3
range [1:3]: []int{2, 3}

Run go test ./examples/... to execute the examples as tests.

Custom Interface Example

You can plug your own data structures into lookup by implementing the Interface interface. Provide Get to return the next element of the path and Raw to expose the underlying value. A runnable demo lives in examples/interfacor1.

type MyNode struct{}

func (n *MyNode) Get(path string) (interface{}, error) { /* ... */ }
func (n *MyNode) Raw() interface{} { return n }

r := lookup.NewInterfaceor(&MyNode{})

Internals - Scope

Modifiers operate with a Scope that tracks the current, parent and position values. Nested and sequential modifiers adjust the scope without escaping the query. Consider the following:

lookup.Reflect(root).Find("Node2", lookup.Index(lookup.Constant("-1")), lookup.Index(lookup.Constant("-2"))).Find("Size", lookup.Index(lookup.Constant("-3")))

Given this YAML:

Node2:
  - Sizes:
      - 1
      - 2
      - 3
  - Sizes:
      - 4
      - 5
      - 6
  - Sizes:
      - 7
      - 8
      - 9

During the query Index(Constant("-1")) sees:

  • Scope.Parent = [ { Sizes: [1,2,3] }, {Sizes: [4,5,6]}, {Sizes: [7,8,9]} ]
  • Scope.Current = [ { Sizes: [1,2,3] }, {Sizes: [4,5,6]}, {Sizes: [7,8,9]} ]
  • Scope.Position = [ { Sizes: [1,2,3] }, {Sizes: [4,5,6]}, {Sizes: [7,8,9]} ]
  • Result: {Sizes: [7,8,9]}

Constant("-1") sees the same parent, current and position but returns -1.

Index(Constant("-2")) then sees:

  • Scope.Parent = [ { Sizes: [1,2,3] }, {Sizes: [4,5,6]}, {Sizes: [7,8,9]} ]
  • Scope.Current = {Sizes: [7,8,9]}
  • Scope.Position = {Sizes: [7,8,9]}
  • Result: 8

With other modifiers Scope.Current may differ from Scope.Position.

Command Line Tools

Two helper binaries make navigating YAML and JSON from the shell easy. Both use lookup's SimplePath syntax and share the same set of options.

yaml-simpe-path

Reads one or more YAML documents and prints selected values. The interface is inspired by classic Unix text processing tools with jq-style niceties.

Usage: yaml-simpe-path [options] PATH [PATH ...]

Options:
  -f string   YAML file to read (default stdin)
  -e string   simple path query (can be repeated)
  -d string   output delimiter (default "\n")
  -json       output as JSON
  -yaml       output as YAML (default)
  -raw        output raw value without formatting
  -grep str   only print results matching the regex
  -v          invert regex match
  -n          prefix results with their index
  -0          use NUL as output delimiter
  -count      only print the number of matched results

Example:

$ cat <<'EOF' > doc.yaml
name: foo
spec:
  replicas: 3
metadata:
  name: prod-service
EOF
$ yaml-simpe-path -f doc.yaml .spec.replicas
3
json-simpe-path

Operates on JSON input with the same flags. It defaults to JSON output but can emit YAML when -yaml is specified.

$ cat <<'EOF' > doc.json
{"name":"foo","spec":{"replicas":3},"metadata":{"name":"prod-service"}}
EOF
$ json-simpe-path -f doc.json .spec.replicas
3

Manual pages generated with go-md2man are available in the man/ directory.

Releases

Versioned releases are published automatically when a Git tag starting with v is pushed. The release workflow runs GoReleaser to build binaries for all supported platforms, package the man pages and upload the archives to GitHub.

Extensions

Please contribute any external libraries that build upon lookup here:

  • ...

Contributing

Bug reports and pull requests are welcome on GitHub. Feel free to open issues for discussion or ideas.

See docs/jsonata.md for a minimal JSONata parser built on top of this package.

License

This project is publicly available under the 3-Clause BSD License. See LICENSE for details.

Q&A

Can I use it as part of tests in a private library?

Yes. Tests are not considered part of the released binary.

Is lookup production ready?

The core API is stable but still evolving. Feedback and contributions are encouraged before locking it down.

Where can I get help?

Open an issue on GitHub if you have questions or run into problems.

JSONata Feature Compatibility Matrix

Test results generated from go test ./jsonata.

Feature Group Passed Failed
array-constructor 0 21
blocks 0 7
boolean-expresssions 0 31
closures 0 2
coalescing-operator 0 13
comments 4 0
comparison-operators 0 29
conditionals 0 9
context 0 4
default-operator 0 14
descendent-operator 0 17
encoding 0 4
errors 0 27
fields 3 5
flattening 0 47
function-abs 0 4
function-append 0 6
function-applications 0 22
function-assert 0 8
function-average 0 13
function-boolean 0 24
function-ceil 0 4
function-contains 0 7
function-count 0 14
function-decodeUrl 0 3
function-decodeUrlComponent 0 3
function-each 0 3
function-encodeUrl 0 3
function-encodeUrlComponent 0 3
function-error 0 11
function-eval 0 8
function-exists 0 25
function-floor 0 4
function-formatBase 0 9
function-formatNumber 0 37
function-fromMillis 0 3
function-join 0 12
function-keys 0 7
function-length 0 17
function-lookup 0 4
function-lowercase 0 2
function-max 0 27
function-merge 0 5
function-number 0 34
function-pad 0 13
function-power 0 7
function-replace 0 12
function-reverse 0 4
function-round 0 18
function-shuffle 0 4
function-sift 0 5
function-signatures 0 35
function-sort 0 11
function-split 0 19
function-spread 0 4
function-sqrt 0 4
function-string 0 31
function-substring 0 19
function-substringAfter 0 5
function-substringBefore 0 5
function-sum 0 7
function-tomillis 0 13
function-trim 0 3
function-typeOf 0 13
function-uppercase 0 2
function-zip 0 6
higher-order-functions 0 3
hof-filter 0 4
hof-map 0 12
hof-reduce 0 11
hof-single 0 11
hof-zip-map 0 4
inclusion-operator 0 9
lambdas 0 14
literals 0 20
matchers 0 2
missing-paths 6 0
multiple-array-selectors 0 3
null 1 6
numeric-operators 0 19
object-constructor 0 27
parentheses 0 8
partial-application 0 5
performance 0 2
predicates 0 4
quoted-selectors 0 8
range-operator 0 25
regex 0 39
simple-array-selectors 4 19
sorting 0 21
string-concat 0 12
tail-recursion 0 10
token-conversion 0 4
transform 10 94
transforms 0 15
variables 0 13
wildcards 0 10

Image Documentation

Overview

Example (Jsonata)
package main

import (
	"fmt"
	"log"

	"github.com/arran4/lookup"
	"github.com/arran4/lookup/jsonata"
)

func main() {
	// 1. Data
	data := map[string]interface{}{
		"Account": map[string]interface{}{
			"Name":    "Firefly",
			"Balance": 100.50,
		},
	}

	// 2. Compile JSONata expression
	// This uses the lookups JSONata compiler which binds functions at parse time.
	ast, err := jsonata.Parse("Account.Name")
	if err != nil {
		log.Fatal(err)
	}
	q := jsonata.Compile(ast)

	// 3. Execute
	result := q.Run(&lookup.Scope{
		Current: lookup.Reflect(data),
	})

	fmt.Println(result.Raw())
}
Output:
Firefly
Example (JsonataCustomFunction)
package main

import (
	"fmt"
	"log"

	"github.com/arran4/go-evaluator"
	"github.com/arran4/lookup"
	"github.com/arran4/lookup/jsonata"
)

func main() {
	// 1. Create a Context with standard functions and register custom one
	// Thread-safe!
	funcs := jsonata.GetStandardFunctions()
	funcs["$greet"] = &GreetFunc{}
	ctx := &evaluator.Context{
		Functions: funcs,
	}

	// 2. Data
	data := map[string]interface{}{
		"Name": "Alice",
	}

	// 3. Compile expression using the custom function
	ast, err := jsonata.Parse("$greet(Name)")
	if err != nil {
		log.Fatal(err)
	}
	q := jsonata.Compile(ast)

	// 4. Run with Context
	result := q.Run(lookup.NewScopeWithContext(nil, lookup.Reflect(data), ctx))

	fmt.Println(result.Raw())

}

type GreetFunc struct{}

func (g *GreetFunc) Call(args ...interface{}) (interface{}, error) {
	if len(args) == 0 {
		return "Hello!", nil
	}
	name, ok := args[0].(string)
	if !ok {
		return nil, fmt.Errorf("arg 0 must be string")
	}
	return fmt.Sprintf("Hello, %s!", name), nil
}
Output:
Hello, Alice!

Index

Examples

Constants

This section is empty.

Variables

View Source
var (
	ErrNoSuchPath                = errors.New("no such path")
	ErrInvalidEvaluationFunction = errors.New("invalid evaluation function")
	ErrEvalFail                  = errors.New("path succeeded but evaluator failed")
	ErrMatchFail                 = errors.New("path succeeded match failed")
	ErrIndexOfNotArray           = errors.New("tried to index a non-array")
	ErrIndexValueNotValid        = errors.New("index value not valid")
	ErrUnknownIndexMode          = errors.New("unknown index mode")
	ErrIndexOutOfRange           = errors.New("index out of range")
	ErrValueNotIn                = errors.New("value not in set")
	ErrNoMatchesForQuery         = errors.New("nothing matched query")
	ErrFalse                     = errors.New("evaluated to false")

	// Type errors
	ErrNotString    = errors.New("value is not a string")
	ErrNotInt       = errors.New("value is not an int")
	ErrNotBool      = errors.New("value is not a bool")
	ErrNotFloat     = errors.New("value is not a float")
	ErrNotSlice     = errors.New("value is not a slice")
	ErrNotMap       = errors.New("value is not a map")
	ErrNotStruct    = errors.New("value is not a struct")
	ErrNotPtr       = errors.New("value is not a pointer")
	ErrNotInterface = errors.New("value is not an interface")
)

Functions

func Add added in v1.0.3

func Add(left, right Runner) *addFunc

func Any

func Any(e Runner) *anyFunc

func Append

func Append(e Runner) *appendFunc

func Chain added in v1.0.3

func Chain(first, second Runner) *chainFunc

func Contains

func Contains(runner Runner) *containsFunc

func Default

func Default(i interface{}) *otherwiseFunc

Default used with .Find() as a PathOpt this will will fallback / default to the provided value regardless of future nagivations, it suppresses most errors / Invalidators.

func Divide added in v1.0.3

func Divide(left, right Runner) *divideFunc

func Equals

func Equals(e Runner) *equalsFunc

func Error

func Error(err error) *errorFunc

func Every

func Every(e Runner) *everyFunc

func ExtractPath

func ExtractPath(pather Pathor) string

ExtractPath retrieves the path use because I didn't export it.

func FallbackPaths added in v1.0.2

func FallbackPaths(paths ...string) *fallbackPathsFunc

func Filter

func Filter(expression Runner) *filterFunc

func First

func First(e Runner) *firstFunc

func GreaterThan added in v1.0.3

func GreaterThan(e Runner) *evaluatorComparisonFunc

func GreaterThanOrEqual added in v1.0.3

func GreaterThanOrEqual(e Runner) *evaluatorComparisonFunc

func If

func If(cond Runner, then Runner, otherwise Runner) *ifFunc

If evaluates `cond` and runs `then` when true otherwise `otherwise`.

func In

func In(e Runner) *inFunc

func Index

func Index(i interface{}) *indexFunc

func Intersection

func Intersection(e Runner) *intersectionFunc

func IsZero

func IsZero(e Runner) *isZeroFunc

func Last

func Last(e Runner) *lastFunc

func LessThan added in v1.0.3

func LessThan(e Runner) *evaluatorComparisonFunc

func LessThanOrEqual added in v1.0.3

func LessThanOrEqual(e Runner) *evaluatorComparisonFunc

func Map

func Map(expression Runner) *mapFunc

func Match

func Match(e ...Runner) *matchFunc

func Modulo added in v1.0.3

func Modulo(left, right Runner) *moduloFunc

func Multiply added in v1.0.3

func Multiply(left, right Runner) *multiplyFunc

func Not

func Not(e Runner) *notFunc

func NotEquals added in v1.0.3

func NotEquals(e Runner) *evaluatorComparisonFunc

func PathBuilder

func PathBuilder(path string, r Pathor, cp CustomPath) string

func Range

func Range(start, end interface{}) *rangeFunc

func StringConcat added in v1.0.3

func StringConcat(left, right Runner) *stringConcatFunc

func Subtract added in v1.0.3

func Subtract(left, right Runner) *subtractFunc

func ToBool

func ToBool(expression Runner) *toBoolFunc

func ToFloat added in v1.0.3

func ToFloat(i interface{}) (float64, bool)

func ToInt added in v1.0.3

func ToInt(i interface{}) (int64, bool)

func Truthy

func Truthy(expression Runner) *truthyFunc

func Union

func Union(e Runner) *unionFunc

Types

type Constantor

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

Constantor This object represents a non-navigable constant. It can be used as an argument applied on the appropriate location in a .Find() chain and it will be the fallback value if no value is found. It can be constructed with either lookup.NewConstantor or lookup.Default()

func Array

func Array(c ...interface{}) *Constantor

func Constant

func Constant(c interface{}) *Constantor

func False

func False(path string) *Constantor

func NewConstantor

func NewConstantor(path string, c interface{}) *Constantor

NewConstantor constructs a non-navigable constant.

func True

func True(path string) *Constantor

func (*Constantor) AsBool added in v1.0.2

func (c *Constantor) AsBool() (bool, error)

func (*Constantor) AsFloat added in v1.0.2

func (c *Constantor) AsFloat() (float64, error)

func (*Constantor) AsInt added in v1.0.2

func (c *Constantor) AsInt() (int64, error)

func (*Constantor) AsMap added in v1.0.2

func (c *Constantor) AsMap() (map[string]interface{}, error)

func (*Constantor) AsPtr added in v1.0.2

func (c *Constantor) AsPtr() (interface{}, error)

func (*Constantor) AsSlice added in v1.0.2

func (c *Constantor) AsSlice() ([]interface{}, error)

func (*Constantor) AsString added in v1.0.2

func (c *Constantor) AsString() (string, error)

func (*Constantor) Find

func (r *Constantor) Find(path string, opts ...Runner) Pathor

Find returns a new Constinator with the same object but with an updated path if required.

func (*Constantor) IsBool added in v1.0.2

func (c *Constantor) IsBool() bool

func (*Constantor) IsFloat added in v1.0.2

func (c *Constantor) IsFloat() bool

func (*Constantor) IsInt added in v1.0.2

func (c *Constantor) IsInt() bool

func (*Constantor) IsInterface added in v1.0.2

func (c *Constantor) IsInterface() bool

func (*Constantor) IsMap added in v1.0.2

func (c *Constantor) IsMap() bool

func (*Constantor) IsNil added in v1.0.2

func (c *Constantor) IsNil() bool

func (*Constantor) IsPtr added in v1.0.2

func (c *Constantor) IsPtr() bool

func (*Constantor) IsSlice added in v1.0.2

func (c *Constantor) IsSlice() bool

func (*Constantor) IsString added in v1.0.2

func (c *Constantor) IsString() bool

func (*Constantor) IsStruct added in v1.0.2

func (c *Constantor) IsStruct() bool

func (*Constantor) Raw

func (r *Constantor) Raw() interface{}

Raw returns the contained object / reference.

func (*Constantor) RawAsInterfaceSlice added in v1.0.2

func (r *Constantor) RawAsInterfaceSlice() []interface{}

RawAsInterfaceSlice returns the contained object as a slice of interface{}.

func (*Constantor) Run

func (c *Constantor) Run(scope *Scope) Pathor

func (*Constantor) Type

func (r *Constantor) Type() reflect.Type

Type extracts the reflect.Type from the stored object

func (*Constantor) Value

func (r *Constantor) Value() reflect.Value

Value returns the reflect.Value

type CustomPath

type CustomPath interface {
	Path(previousPath string, findPath string) string
}

type Finder

type Finder interface {
	// Find preforms a path navigation. 'Path' is either a map key, array/slice index, or struct function/field.
	// This function is fixed and will probably not change in the future
	// So usage is supposed to be changed, anything which implements this function should return null-safe values. (ie non
	// nul.)
	// Usage: `lookup.Reflector(MyObjcet).Find("Quotes").Find("12").Find("Qty").Raw()
	Find(path string, opts ...Runner) Pathor
}

type HasPath

type HasPath interface {
	Path() string
}

HasPath is an interface used to determine if a Pathor has a Path() function

type Interface

type Interface interface {
	// Find the next component.. Must return an Interface OR another type of Pathor.
	Get(path string) (interface{}, error)
	// The raw type
	Raw() interface{}
}

Interface an interface you can implement to avoid using Reflector or to put your own selection logic such as if you were to run this over another data structure.

type Interfaceor

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

Interfaceor the wrapping element for the Interface component to make it adhere to the Pathor interface

func (*Interfaceor) AsBool added in v1.0.2

func (i *Interfaceor) AsBool() (bool, error)

func (*Interfaceor) AsFloat added in v1.0.2

func (i *Interfaceor) AsFloat() (float64, error)

func (*Interfaceor) AsInt added in v1.0.2

func (i *Interfaceor) AsInt() (int64, error)

func (*Interfaceor) AsMap added in v1.0.2

func (i *Interfaceor) AsMap() (map[string]interface{}, error)

func (*Interfaceor) AsPtr added in v1.0.2

func (i *Interfaceor) AsPtr() (interface{}, error)

func (*Interfaceor) AsSlice added in v1.0.2

func (i *Interfaceor) AsSlice() ([]interface{}, error)

func (*Interfaceor) AsString added in v1.0.2

func (i *Interfaceor) AsString() (string, error)

func (*Interfaceor) Find

func (i *Interfaceor) Find(path string, opts ...Runner) Pathor

func (*Interfaceor) IsBool added in v1.0.2

func (i *Interfaceor) IsBool() bool

func (*Interfaceor) IsFloat added in v1.0.2

func (i *Interfaceor) IsFloat() bool

func (*Interfaceor) IsInt added in v1.0.2

func (i *Interfaceor) IsInt() bool

func (*Interfaceor) IsInterface added in v1.0.2

func (i *Interfaceor) IsInterface() bool

func (*Interfaceor) IsMap added in v1.0.2

func (i *Interfaceor) IsMap() bool

func (*Interfaceor) IsNil added in v1.0.2

func (i *Interfaceor) IsNil() bool

func (*Interfaceor) IsPtr added in v1.0.2

func (i *Interfaceor) IsPtr() bool

func (*Interfaceor) IsSlice added in v1.0.2

func (i *Interfaceor) IsSlice() bool

func (*Interfaceor) IsString added in v1.0.2

func (i *Interfaceor) IsString() bool

func (*Interfaceor) IsStruct added in v1.0.2

func (i *Interfaceor) IsStruct() bool

func (*Interfaceor) Path

func (i *Interfaceor) Path() string

func (*Interfaceor) Raw

func (i *Interfaceor) Raw() interface{}

func (*Interfaceor) RawAsInterfaceSlice added in v1.0.2

func (i *Interfaceor) RawAsInterfaceSlice() []interface{}

func (*Interfaceor) Type

func (i *Interfaceor) Type() reflect.Type

func (*Interfaceor) Value

func (i *Interfaceor) Value() reflect.Value

type Invalidor

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

Invalidor indicates an invalid state this can be because of an error, or an invalid path. It contains an error and adheres to errors and errors.Unwrap using fmt.Errors(".. %w..") It is designed to be continued to be used without returning a null value when you reach an error and also provide the path and error combo for debugging. It is fully adherent to a Pathor object

func NewInvalidor

func NewInvalidor(path string, err error) *Invalidor

NewInvalidor creates an invalidator, there shouldn't be any real reason to do this but you have an option to. See documentation for Invalidor for details

func (*Invalidor) AsBool added in v1.0.2

func (i *Invalidor) AsBool() (bool, error)

func (*Invalidor) AsFloat added in v1.0.2

func (i *Invalidor) AsFloat() (float64, error)

func (*Invalidor) AsInt added in v1.0.2

func (i *Invalidor) AsInt() (int64, error)

func (*Invalidor) AsMap added in v1.0.2

func (i *Invalidor) AsMap() (map[string]interface{}, error)

func (*Invalidor) AsPtr added in v1.0.2

func (i *Invalidor) AsPtr() (interface{}, error)

func (*Invalidor) AsSlice added in v1.0.2

func (i *Invalidor) AsSlice() ([]interface{}, error)

func (*Invalidor) AsString added in v1.0.2

func (i *Invalidor) AsString() (string, error)

func (*Invalidor) Error

func (i *Invalidor) Error() string

Error implements the error interface

func (*Invalidor) Evaluate

func (i *Invalidor) Evaluate(scope *Scope, position Pathor) (Pathor, error)

Evaluate implements EvaluateNoArgs

func (*Invalidor) Find

func (i *Invalidor) Find(path string, opts ...Runner) Pathor

Find returns a new Invalidator with the same object but with an updated path if required. -- The path changing component might be removed - or become toggleable in an option.

func (*Invalidor) IsBool added in v1.0.2

func (i *Invalidor) IsBool() bool

func (*Invalidor) IsFloat added in v1.0.2

func (i *Invalidor) IsFloat() bool

func (*Invalidor) IsInt added in v1.0.2

func (i *Invalidor) IsInt() bool

func (*Invalidor) IsInterface added in v1.0.2

func (i *Invalidor) IsInterface() bool

func (*Invalidor) IsMap added in v1.0.2

func (i *Invalidor) IsMap() bool

func (*Invalidor) IsNil added in v1.0.2

func (i *Invalidor) IsNil() bool

func (*Invalidor) IsPtr added in v1.0.2

func (i *Invalidor) IsPtr() bool

func (*Invalidor) IsSlice added in v1.0.2

func (i *Invalidor) IsSlice() bool

func (*Invalidor) IsString added in v1.0.2

func (i *Invalidor) IsString() bool

func (*Invalidor) IsStruct added in v1.0.2

func (i *Invalidor) IsStruct() bool

func (*Invalidor) Path

func (i *Invalidor) Path() string

func (*Invalidor) Raw

func (i *Invalidor) Raw() interface{}

Raw returns NULL

func (*Invalidor) RawAsInterfaceSlice added in v1.0.2

func (i *Invalidor) RawAsInterfaceSlice() []interface{}

RawAsInterfaceSlice returns nil

func (*Invalidor) Type

func (i *Invalidor) Type() reflect.Type

Type returns NULL

func (*Invalidor) Unwrap

func (i *Invalidor) Unwrap() error

Unwrap implements the Unwrap error interface

func (*Invalidor) Value

func (i *Invalidor) Value() reflect.Value

Raw returns a zero/invalid reflect.Value

type Jsonor

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

Jsonor is a Pathor that lazily unmarshals JSON bytes when accessed.

func (*Jsonor) AsBool added in v1.0.2

func (j *Jsonor) AsBool() (bool, error)

func (*Jsonor) AsFloat added in v1.0.2

func (j *Jsonor) AsFloat() (float64, error)

func (*Jsonor) AsInt added in v1.0.2

func (j *Jsonor) AsInt() (int64, error)

func (*Jsonor) AsMap added in v1.0.2

func (j *Jsonor) AsMap() (map[string]interface{}, error)

func (*Jsonor) AsPtr added in v1.0.2

func (j *Jsonor) AsPtr() (interface{}, error)

func (*Jsonor) AsSlice added in v1.0.2

func (j *Jsonor) AsSlice() ([]interface{}, error)

func (*Jsonor) AsString added in v1.0.2

func (j *Jsonor) AsString() (string, error)

func (*Jsonor) Find

func (j *Jsonor) Find(path string, opts ...Runner) Pathor

Find navigates the JSON structure using Reflector after decoding.

func (*Jsonor) IsBool added in v1.0.2

func (j *Jsonor) IsBool() bool

func (*Jsonor) IsFloat added in v1.0.2

func (j *Jsonor) IsFloat() bool

func (*Jsonor) IsInt added in v1.0.2

func (j *Jsonor) IsInt() bool

func (*Jsonor) IsInterface added in v1.0.2

func (j *Jsonor) IsInterface() bool

func (*Jsonor) IsMap added in v1.0.2

func (j *Jsonor) IsMap() bool

func (*Jsonor) IsNil added in v1.0.2

func (j *Jsonor) IsNil() bool

func (*Jsonor) IsPtr added in v1.0.2

func (j *Jsonor) IsPtr() bool

func (*Jsonor) IsSlice added in v1.0.2

func (j *Jsonor) IsSlice() bool

func (*Jsonor) IsString added in v1.0.2

func (j *Jsonor) IsString() bool

func (*Jsonor) IsStruct added in v1.0.2

func (j *Jsonor) IsStruct() bool

func (*Jsonor) Path

func (j *Jsonor) Path() string

Path returns the current lookup path.

func (*Jsonor) Raw

func (j *Jsonor) Raw() interface{}

Raw returns the decoded value.

func (*Jsonor) RawAsInterfaceSlice added in v1.0.2

func (j *Jsonor) RawAsInterfaceSlice() []interface{}

RawAsInterfaceSlice returns the decoded value as a slice of interface{}.

func (*Jsonor) Type

func (j *Jsonor) Type() reflect.Type

Type returns the reflect.Type of the decoded value.

func (*Jsonor) Value

func (j *Jsonor) Value() reflect.Value

Value returns the reflect.Value of the decoded value.

type Pathor

type Pathor interface {
	// Finder preforms a path navigation. 'Path' is either a map key, array/slice index, or struct function/field.
	// This function is fixed and will probably not change in the future
	// So usage is supposed to be changed, anything which implements this function should return null-safe values. (ie non
	// nul.)
	// Usage: `lookup.Reflector(MyObjcet).Find("Quotes").Find("12").Find("Qty").Raw()
	Finder
	// Value returns the reflect.Value or an invalid reflect.Value. This could be restricted to lookup.Reflector and others where appropriate
	Value() reflect.Value
	// Raw returns the raw contents / result of the lookup. This won't change
	Raw() interface{}
	// RawAsInterfaceSlice returns the raw contents as a slice of interface{}. If the value is not a slice it returns nil.
	RawAsInterfaceSlice() []interface{}
	// Type returns the reflect.Type or nil. This could be restricted to lookup.Reflector and others where appropriate
	Type() reflect.Type

	// IsString returns true if the underlying value is a string
	IsString() bool
	// IsInt returns true if the underlying value is an int (int, int8, int16, int32, int64)
	IsInt() bool
	// IsBool returns true if the underlying value is a bool
	IsBool() bool
	// IsFloat returns true if the underlying value is a float (float32, float64)
	IsFloat() bool
	// IsSlice returns true if the underlying value is a slice or array
	IsSlice() bool
	// IsMap returns true if the underlying value is a map
	IsMap() bool
	// IsStruct returns true if the underlying value is a struct
	IsStruct() bool
	// IsNil returns true if the underlying value is nil
	IsNil() bool
	// IsPtr returns true if the underlying value is a pointer
	IsPtr() bool
	// IsInterface returns true if the underlying value is an interface
	IsInterface() bool

	// AsString returns the string value or error if not a string
	AsString() (string, error)
	// AsInt returns the int value (as int64) or error if not an int
	AsInt() (int64, error)
	// AsBool returns the bool value or error if not a bool
	AsBool() (bool, error)
	// AsFloat returns the float value (as float64) or error if not a float
	AsFloat() (float64, error)
	// AsSlice returns the slice value as []interface{} or error if not a slice
	AsSlice() ([]interface{}, error)
	// AsMap returns the map value as map[string]interface{} or error if not a map (or keys are not strings)
	AsMap() (map[string]interface{}, error)
	// AsPtr returns the pointer value or error if not a pointer
	AsPtr() (interface{}, error)
}

Pathor interface

func Json

func Json(raw []byte) Pathor

Json creates a Pathor for navigating raw JSON data.

func NewInterfaceor

func NewInterfaceor(i Interface) Pathor

NewInterfaceor see Interface and Interfaceor for details.

func QuerySimplePath

func QuerySimplePath(v interface{}, query string) Pathor

QuerySimplePath executes the given simple path query string against the provided value using reflection.

func Reflect

func Reflect(i interface{}) Pathor

Reflect creates a Pathor that uses reflect to navigate the object. This so far is the only way to navigate arbitrary go objects, so use this.

func Yaml

func Yaml(raw []byte) Pathor

Yaml creates a Pathor for navigating raw YAML data.

type Reflector

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

Reflector is a Pathor which uses reflection for navigation of the the objects, it supports a wide range of elements

func (*Reflector) AsBool added in v1.0.2

func (r *Reflector) AsBool() (bool, error)

func (*Reflector) AsFloat added in v1.0.2

func (r *Reflector) AsFloat() (float64, error)

func (*Reflector) AsInt added in v1.0.2

func (r *Reflector) AsInt() (int64, error)

func (*Reflector) AsMap added in v1.0.2

func (r *Reflector) AsMap() (map[string]interface{}, error)

func (*Reflector) AsPtr added in v1.0.2

func (r *Reflector) AsPtr() (interface{}, error)

func (*Reflector) AsSlice added in v1.0.2

func (r *Reflector) AsSlice() ([]interface{}, error)

func (*Reflector) AsString added in v1.0.2

func (r *Reflector) AsString() (string, error)

func (*Reflector) Find

func (r *Reflector) Find(path string, opts ...Runner) Pathor

Find finds the best match for the "Path" argument in the contained object and then returns a Pathor for that location Match nothing was found it will return an Invalidor, or if a Constant has bee provided as an argument (such as through `Default()` it will default to that in most cases. Find is designed to return null safe results.

func (*Reflector) IsBool added in v1.0.2

func (r *Reflector) IsBool() bool

func (*Reflector) IsFloat added in v1.0.2

func (r *Reflector) IsFloat() bool

func (*Reflector) IsInt added in v1.0.2

func (r *Reflector) IsInt() bool

func (*Reflector) IsInterface added in v1.0.2

func (r *Reflector) IsInterface() bool

func (*Reflector) IsMap added in v1.0.2

func (r *Reflector) IsMap() bool

func (*Reflector) IsNil added in v1.0.2

func (r *Reflector) IsNil() bool

func (*Reflector) IsPtr added in v1.0.2

func (r *Reflector) IsPtr() bool

func (*Reflector) IsSlice added in v1.0.2

func (r *Reflector) IsSlice() bool

func (*Reflector) IsString added in v1.0.2

func (r *Reflector) IsString() bool

func (*Reflector) IsStruct added in v1.0.2

func (r *Reflector) IsStruct() bool

func (*Reflector) Path

func (r *Reflector) Path() string

func (*Reflector) Raw

func (r *Reflector) Raw() interface{}

Raw returns the contained object / reference.

func (*Reflector) RawAsInterfaceSlice added in v1.0.2

func (r *Reflector) RawAsInterfaceSlice() []interface{}

RawAsInterfaceSlice returns the contained object as a slice of interface{}.

func (*Reflector) Type

func (r *Reflector) Type() reflect.Type

Type extracts the reflect.Type from the stored object

func (*Reflector) Value

func (r *Reflector) Value() reflect.Value

Value returns the reflect.Value

type Relator

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

Relator allows you to do an Evaluate from a relative location

func Find

func Find(path string, opts ...Runner) *Relator

func NewRelator

func NewRelator() *Relator

func Parent

func Parent(path string, opts ...Runner) *Relator

func ParseSimplePath

func ParseSimplePath(query string) *Relator

ParseSimplePath converts a simple query string like "A.B[0].C" into a Relator which can be run against any Pathor. The supported syntax only understands dot separated field lookups and integer based indexes using square brackets.

func Result

func Result(paths ...string) *Relator

func This

func This(paths ...string) *Relator

func (*Relator) Copy

func (r *Relator) Copy() *Relator

Copy produces a copy of the Relator

func (*Relator) Find

func (r *Relator) Find(path string, opts ...Runner) *Relator

Find stores a find request to be used in the relative location. Please note this doesn't alloc a new Relator use Copy for that.

func (*Relator) Run

func (r *Relator) Run(scope *Scope) Pathor

type Runner

type Runner interface {
	Run(scope *Scope) Pathor
}

type Scope

type Scope struct {
	Current Pathor
	Parent  *Scope

	Position Pathor
	Context  *evaluator.Context
	// contains filtered or unexported fields
}

func NewScope

func NewScope(parent Pathor, position Pathor) *Scope

func NewScopeWithContext added in v1.0.3

func NewScopeWithContext(parent Pathor, position Pathor, ctx *evaluator.Context) *Scope

func (*Scope) Copy

func (s *Scope) Copy() *Scope

func (*Scope) Nest

func (s *Scope) Nest(new Pathor) *Scope

func (*Scope) Next

func (s *Scope) Next(position Pathor) *Scope

func (*Scope) Path

func (s *Scope) Path() string

func (*Scope) Value

func (s *Scope) Value() reflect.Value

type Simpleor

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

Simpleor is a Pathor implementation that uses type switches for common types (map[string]interface{}, []interface{}) to avoid reflection overhead where possible.

func Simple

func Simple(v interface{}) *Simpleor

func (*Simpleor) AsBool added in v1.0.2

func (s *Simpleor) AsBool() (bool, error)

func (*Simpleor) AsFloat added in v1.0.2

func (s *Simpleor) AsFloat() (float64, error)

func (*Simpleor) AsInt added in v1.0.2

func (s *Simpleor) AsInt() (int64, error)

func (*Simpleor) AsMap added in v1.0.2

func (s *Simpleor) AsMap() (map[string]interface{}, error)

func (*Simpleor) AsPtr added in v1.0.2

func (s *Simpleor) AsPtr() (interface{}, error)

func (*Simpleor) AsSlice added in v1.0.2

func (s *Simpleor) AsSlice() ([]interface{}, error)

func (*Simpleor) AsString added in v1.0.2

func (s *Simpleor) AsString() (string, error)

func (*Simpleor) Evaluate

func (s *Simpleor) Evaluate(scope *Scope, position Pathor) (Pathor, error)

func (*Simpleor) Find

func (s *Simpleor) Find(path string, opts ...Runner) Pathor

func (*Simpleor) IsBool added in v1.0.2

func (s *Simpleor) IsBool() bool

func (*Simpleor) IsFloat added in v1.0.2

func (s *Simpleor) IsFloat() bool

func (*Simpleor) IsInt added in v1.0.2

func (s *Simpleor) IsInt() bool

func (*Simpleor) IsInterface added in v1.0.2

func (s *Simpleor) IsInterface() bool

func (*Simpleor) IsMap added in v1.0.2

func (s *Simpleor) IsMap() bool

func (*Simpleor) IsNil added in v1.0.2

func (s *Simpleor) IsNil() bool

func (*Simpleor) IsPtr added in v1.0.2

func (s *Simpleor) IsPtr() bool

func (*Simpleor) IsSlice added in v1.0.2

func (s *Simpleor) IsSlice() bool

func (*Simpleor) IsString added in v1.0.2

func (s *Simpleor) IsString() bool

func (*Simpleor) IsStruct added in v1.0.2

func (s *Simpleor) IsStruct() bool

func (*Simpleor) Path

func (s *Simpleor) Path() string

func (*Simpleor) Raw

func (s *Simpleor) Raw() interface{}

func (*Simpleor) RawAsInterfaceSlice added in v1.0.2

func (s *Simpleor) RawAsInterfaceSlice() []interface{}

func (*Simpleor) Type

func (s *Simpleor) Type() reflect.Type

func (*Simpleor) Value

func (s *Simpleor) Value() reflect.Value

type Valuor

type Valuor struct {
	Pathor
}

func ValueOf

func ValueOf(pathor Pathor) *Valuor

func (*Valuor) Run

func (v *Valuor) Run(scope *Scope) Pathor

type Yamlor

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

Yamlor is a Pathor that lazily unmarshals YAML bytes when accessed.

func (*Yamlor) AsBool added in v1.0.2

func (y *Yamlor) AsBool() (bool, error)

func (*Yamlor) AsFloat added in v1.0.2

func (y *Yamlor) AsFloat() (float64, error)

func (*Yamlor) AsInt added in v1.0.2

func (y *Yamlor) AsInt() (int64, error)

func (*Yamlor) AsMap added in v1.0.2

func (y *Yamlor) AsMap() (map[string]interface{}, error)

func (*Yamlor) AsPtr added in v1.0.2

func (y *Yamlor) AsPtr() (interface{}, error)

func (*Yamlor) AsSlice added in v1.0.2

func (y *Yamlor) AsSlice() ([]interface{}, error)

func (*Yamlor) AsString added in v1.0.2

func (y *Yamlor) AsString() (string, error)

func (*Yamlor) Find

func (y *Yamlor) Find(path string, opts ...Runner) Pathor

Find navigates the YAML structure using Reflector after decoding.

func (*Yamlor) IsBool added in v1.0.2

func (y *Yamlor) IsBool() bool

func (*Yamlor) IsFloat added in v1.0.2

func (y *Yamlor) IsFloat() bool

func (*Yamlor) IsInt added in v1.0.2

func (y *Yamlor) IsInt() bool

func (*Yamlor) IsInterface added in v1.0.2

func (y *Yamlor) IsInterface() bool

func (*Yamlor) IsMap added in v1.0.2

func (y *Yamlor) IsMap() bool

func (*Yamlor) IsNil added in v1.0.2

func (y *Yamlor) IsNil() bool

func (*Yamlor) IsPtr added in v1.0.2

func (y *Yamlor) IsPtr() bool

func (*Yamlor) IsSlice added in v1.0.2

func (y *Yamlor) IsSlice() bool

func (*Yamlor) IsString added in v1.0.2

func (y *Yamlor) IsString() bool

func (*Yamlor) IsStruct added in v1.0.2

func (y *Yamlor) IsStruct() bool

func (*Yamlor) Path

func (y *Yamlor) Path() string

Path returns the current lookup path.

func (*Yamlor) Raw

func (y *Yamlor) Raw() interface{}

Raw returns the decoded value.

func (*Yamlor) RawAsInterfaceSlice added in v1.0.2

func (y *Yamlor) RawAsInterfaceSlice() []interface{}

RawAsInterfaceSlice returns the decoded value as a slice of interface{}.

func (*Yamlor) Type

func (y *Yamlor) Type() reflect.Type

Type returns the reflect.Type of the decoded value.

func (*Yamlor) Value

func (y *Yamlor) Value() reflect.Value

Value returns the reflect.Value of the decoded value.

Image Directories

Path Synopsis
cmd
json-simpe-path command
yaml-simpe-path command
advanced command
collections command
interfacor1 command

Jump to

Keyboard shortcuts

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