pointerstructure

package module
v1.2.1 Latest Latest
Warning

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

Go to latest
Published: Nov 2, 2021 License: MIT Imports: 6 Imported by: 25

README

pointerstructure GoDoc

pointerstructure is a Go library for identifying a specific value within any Go structure using a string syntax.

pointerstructure is based on JSON Pointer (RFC 6901), but reimplemented for Go.

The goal of pointerstructure is to provide a single, well-known format for addressing a specific value. This can be useful for user provided input on structures, diffs of structures, etc.

Features

  • Get the value for an address

  • Set the value for an address within an existing structure

  • Delete the value at an address

  • Sorting a list of addresses

Installation

Standard go get:

$ go get github.com/mitchellh/pointerstructure

Usage & Example

For usage and examples see the Godoc.

A quick code example is shown below:

complex := map[string]interface{}{
	"alice": 42,
	"bob": []interface{}{
		map[string]interface{}{
			"name": "Bob",
		},
	},
}

value, err := pointerstructure.Get(complex, "/bob/0/name")
if err != nil {
	panic(err)
}

fmt.Printf("%s", value)
// Output:
// Bob

Continuing the example above, you can also set values:

value, err = pointerstructure.Set(complex, "/bob/0/name", "Alice")
if err != nil {
	panic(err)
}

value, err = pointerstructure.Get(complex, "/bob/0/name")
if err != nil {
	panic(err)
}

fmt.Printf("%s", value)
// Output:
// Alice

The library also supports Get operations on structs including using the pointer struct tag to override struct field names:

	input := struct {
		Values map[string]interface{} `pointer:"embedded"`
	}{
		Values: map[string]interface{}{
			"alice": 42,
			"bob": []interface{}{
				map[string]interface{}{
					"name": "Bob",
				},
			},
		},
	}

	value, err := Get(input, "/embedded/bob/0/name")
	if err != nil {
		panic(err)
	}

	fmt.Printf("%s", value)
// Output:
// Bob

Documentation

Overview

Package pointerstructure provides functions for identifying a specific value within any Go structure using a string syntax.

The syntax used is based on JSON Pointer (RFC 6901).

Index

Examples

Constants

This section is empty.

Variables

View Source
var (
	// ErrNotFound is returned if a key in a query can't be found
	ErrNotFound = errors.New("couldn't find key")

	// ErrParse is returned if the query cannot be parsed
	ErrParse = errors.New("first char must be '/'")

	// ErrOutOfRange is returned if a query is referencing a slice
	// or array and the requested index is not in the range [0,len(item))
	ErrOutOfRange = errors.New("out of range")

	// ErrInvalidKind is returned if the item is not a map, slice,
	// array, or struct
	ErrInvalidKind = errors.New("invalid value kind")

	// ErrConvert is returned if an item is not of a requested type
	ErrConvert = errors.New("couldn't convert value")
)

Functions

func Get

func Get(value interface{}, pointer string) (interface{}, error)

Get reads the value at the given pointer.

This is a shorthand for calling Parse on the pointer and then calling Get on that result. An error will be returned if the value cannot be found or there is an error with the format of pointer.

Example
complex := map[string]interface{}{
	"alice": 42,
	"bob": []interface{}{
		map[string]interface{}{
			"name": "Bob",
		},
	},
}

value, err := Get(complex, "/bob/0/name")
if err != nil {
	panic(err)
}

fmt.Printf("%s", value)
Output:

Bob

func Set

func Set(doc interface{}, pointer string, value interface{}) (interface{}, error)

Set sets the value at the given pointer.

This is a shorthand for calling Parse on the pointer and then calling Set on that result. An error will be returned if the value cannot be found or there is an error with the format of pointer.

Set returns the complete document, which might change if the pointer value points to the root ("").

Example
complex := map[string]interface{}{
	"alice": 42,
	"bob": []interface{}{
		map[string]interface{}{
			"name": "Bob",
		},
	},
}

value, err := Set(complex, "/bob/0/name", "Alice")
if err != nil {
	panic(err)
}

value, err = Get(complex, "/bob/0/name")
if err != nil {
	panic(err)
}

fmt.Printf("%s", value)
Output:

Alice

func Sort

func Sort(p []*Pointer)

Sort does an in-place sort of the pointers so that they are in order of least specific to most specific alphabetized. For example: "/foo", "/foo/0", "/qux"

This ordering is ideal for applying the changes in a way that ensures that parents are set first.

Types

type Config added in v1.1.0

type Config struct {
	// The tag name that pointerstructure reads for field names. This
	// defaults to "pointer"
	TagName string
	// ValueTransformationHook is called on each reference token within the
	// provided JSON Pointer when Get is used.  The returned value from this
	// hook is then used for matching for all following parts of the JSON
	// Pointer.  If this returns a nil interface Get will return an error.
	ValueTransformationHook ValueTransformationHookFn
}

type Pointer

type Pointer struct {
	// Parts are the pointer parts. No escape codes are processed here.
	// The values are expected to be exact. If you have escape codes, use
	// the Parse functions.
	Parts []string

	// Config is the configuration controlling how items are looked up
	// in structures.
	Config Config
}

Pointer represents a pointer to a specific value. You can construct a pointer manually or use Parse.

func MustParse

func MustParse(input string) *Pointer

MustParse is like Parse but panics if the input cannot be parsed.

func Parse

func Parse(input string) (*Pointer, error)

Parse parses a pointer from the input string. The input string is expected to follow the format specified by RFC 6901: '/'-separated parts. Each part can contain escape codes to contain '/' or '~'.

func (*Pointer) Delete

func (p *Pointer) Delete(s interface{}) (interface{}, error)

Delete deletes the value specified by the pointer p in structure s.

When deleting a slice index, all other elements will be shifted to the left. This is specified in RFC6902 (JSON Patch) and not RFC6901 since RFC6901 doesn't specify operations on pointers. If you don't want to shift elements, you should use Set to set the slice index to the zero value.

The structures s must have non-zero values set up to this pointer. For example, if deleting "/bob/0/name", then "/bob/0" must be set already.

The returned value is potentially a new value if this pointer represents the root document. Otherwise, the returned value will always be s.

func (*Pointer) Get

func (p *Pointer) Get(v interface{}) (interface{}, error)

Get reads the value out of the total value v.

For struct values a `pointer:"<name>"` tag on the struct's fields may be used to override that field's name for lookup purposes. Alternatively the tag name used can be overridden in the `Config`.

func (*Pointer) IsRoot

func (p *Pointer) IsRoot() bool

IsRoot returns true if this pointer represents the root document.

func (*Pointer) Parent

func (p *Pointer) Parent() *Pointer

Parent returns a pointer to the parent element of this pointer.

If Pointer represents the root (empty parts), a pointer representing the root is returned. Therefore, to check for the root, IsRoot() should be called.

func (*Pointer) Set

func (p *Pointer) Set(s, v interface{}) (interface{}, error)

Set writes a value v to the pointer p in structure s.

The structures s must have non-zero values set up to this pointer. For example, if setting "/bob/0/name", then "/bob/0" must be set already.

The returned value is potentially a new value if this pointer represents the root document. Otherwise, the returned value will always be s.

func (*Pointer) String

func (p *Pointer) String() string

String returns the string value that can be sent back to Parse to get the same Pointer result.

type PointerSlice

type PointerSlice []*Pointer

PointerSlice is a slice of pointers that adheres to sort.Interface

func (PointerSlice) Len

func (p PointerSlice) Len() int

func (PointerSlice) Less

func (p PointerSlice) Less(i, j int) bool

func (PointerSlice) Swap

func (p PointerSlice) Swap(i, j int)

type ValueTransformationHookFn added in v1.2.0

type ValueTransformationHookFn func(reflect.Value) reflect.Value

ValueTransformationHookFn transforms a Go data structure into another. This is useful for situations where you want the JSON Pointer to not be an exact match to the structure of the Go struct or map, for example when working with protocol buffers' well-known types.

Jump to

Keyboard shortcuts

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