jq

package module
v0.5.0 Latest Latest
Warning

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

Go to latest
Published: Aug 17, 2026 License: MIT Imports: 8 Imported by: 1

README

build coverage Docs

jq

Go JSON structure query path getter/setter

package main

import (
	"encoding/json"
	"fmt"

	"github.com/linkdata/jq"
)

const rawJson = `{
  "name": "John Doe",
  "age": 30,
  "isStudent": false,
  "hobbies": ["reading", "hiking", "gaming"],
  "address": {
    "street": "123 Main St",
    "city": "Anytown",
    "zip": "12345"
  }
}`

type Address struct {
	Street string `json:"street"`
	City   string `json:"city"`
	Zip    string `json:"zip"`
}

type Person struct {
	Name      string   `json:"name"`
	Age       int      `json:"age"`
	IsStudent bool     `json:"isStudent"`
	Hobbies   []string `json:"hobbies"`
	Address   Address  `json:"address"`
}

func main() {
	var person Person
	var err error
	if err = json.Unmarshal([]byte(rawJson), &person); err == nil {
		var firsthobby string
		if firsthobby, err = jq.GetAs[string](&person, "hobbies.0"); err == nil {
			fmt.Println(firsthobby)
			var address Address
			if address, err = jq.GetAs[Address](&person, "address"); err == nil {
				fmt.Println(address.City)
			}
		}
	}
	if err != nil {
		panic(err)
	}
	// Output:
	// reading
	// Anytown
}

Struct fields

Struct path components exactly match names selected by encoding/json's default field-selection rules, including JSON tag names and unambiguous promoted fields. An untagged anonymous struct field contributes its promoted fields directly to the containing struct's namespace; it does not add its Go type name as a path component. For example, an anonymous Inner exposes value. Tagging the field json:"inner" replaces that path with inner.value; json:"Inner" uses Inner.value.

Reachable exported fields promoted through unexported embedded structs are readable with Get and writable with Set, including through map-to-struct assignments.

An exact json:"-" tag excludes a field from path traversal and map-to-struct assignments.

When an unexported embedded field has an explicit JSON name, Get and Set can traverse that component on paths to reachable exported fields. A path ending at the embedded field returns ErrPathNotFound, as does a map-to-struct assignment to it.

Checked updates

SetChecked tentatively applies the same operation as Set, then calls a checker against the resulting object. A checker error restores the original object and is returned unchanged. A checker panic also restores the object before the panic continues.

The checker runs only when Set reports a write. It may inspect or marshal the tentative object, but it must not mutate it. When the checker uses Get, a path ending at an explicitly named unexported embedded field returns ErrPathNotFound, even after a tentative update beneath it. Callers are responsible for synchronizing access throughout SetChecked, including while the checker runs.

Documentation

Overview

Example
package main

import (
	"encoding/json"
	"fmt"

	"github.com/linkdata/jq"
)

const rawJson = `{
  "name": "John Doe",
  "age": 30,
  "isStudent": false,
  "hobbies": ["reading", "hiking", "gaming"],
  "address": {
    "street": "123 Main St",
    "city": "Anytown",
    "zip": "12345"
  }
}`

type Address struct {
	Street string `json:"street"`
	City   string `json:"city"`
	Zip    string `json:"zip"`
}

type Person struct {
	Name      string   `json:"name"`
	Age       int      `json:"age"`
	IsStudent bool     `json:"isStudent"`
	Hobbies   []string `json:"hobbies"`
	Address   Address  `json:"address"`
}

func main() {
	var person Person
	var err error
	if err = json.Unmarshal([]byte(rawJson), &person); err == nil {
		var firsthobby string
		if firsthobby, err = jq.GetAs[string](&person, "hobbies.0"); err == nil {
			fmt.Println(firsthobby)
			var address Address
			if address, err = jq.GetAs[Address](&person, "address"); err == nil {
				fmt.Println(address.City)
			}
		}
	}
	if err != nil {
		panic(err)
	}
}
Output:
reading
Anytown

Index

Examples

Constants

This section is empty.

Variables

View Source
var ErrInvalidReceiver = errors.New("jq: invalid receiver")

ErrInvalidReceiver indicates that Set or SetChecked received a nil or non-pointer receiver.

View Source
var ErrPathNotFound errPathNotFound

ErrPathNotFound is returned when a JSON path cannot be resolved.

View Source
var ErrTypeMismatch errTypeMismatch

ErrTypeMismatch is returned when a value does not have the expected type.

Functions

func Get

func Get(obj any, jspath string) (val any, err error)

Get returns the value at jspath in obj.

An empty path returns obj itself unless obj is nil. Values containing maps, slices, or pointers may share their backing data with obj.

Struct components exactly match names selected by encoding/json's default struct-field rules, including JSON tag names and unambiguous promoted fields. An untagged anonymous struct field contributes its promoted fields directly to the containing struct's namespace; it does not add its Go type name as a path component. A valid explicit JSON name on the field replaces that promotion with a component named by the tag.

Exported fields promoted through unexported embedded structs are readable with Get and writable with Set, including through map-to-struct assignments. An exact `json:"-"` tag excludes a field from the path namespace. Get and Set can traverse an explicitly named unexported embedded field on paths to reachable exported fields, but a path ending at the embedded field returns an error matching ErrPathNotFound. Traversing a nil pointer returns the same error.

When traversal reaches an array or slice, a component is a valid index only if it is "0" or begins with an ASCII digit from '1' through '9' followed by zero or more ASCII decimal digits. The index must be at most 4294967294 and representable as int; otherwise the error matches ErrPathNotFound.

func GetAs

func GetAs[T any](obj any, jspath string) (val T, err error)

GetAs returns the value at jspath in obj as T.

It returns ErrTypeMismatch when the resolved value is not assignable to T.

func Set

func Set(obj any, jspath string, val any) (changed bool, err error)

Set updates jspath in obj and reports whether it performed a write.

obj must be a non-nil pointer. An empty path replaces the pointed-to value. Array and slice components follow the index syntax documented by Get. A path into a settable slice may append one element by using an index equal to the slice's current length. Map paths address existing string-keyed entries and do not create new entries. A nil val stores the destination type's zero value.

Struct components and string keys in map-to-struct assignments follow Get's field-selection rules. Set can traverse an explicitly named unexported embedded field to update a reachable exported field. A path ending at the embedded field, or a map-to-struct key selecting it, returns an error matching ErrPathNotFound. Set does not allocate nil pointers; a path traversing one returns the same error.

Set leaves obj unchanged when it returns an error. It does not synchronize access to obj; callers must prevent concurrent reads and writes.

func SetChecked added in v0.2.0

func SetChecked(obj any, jspath string, val any, check func() error) (changed bool, err error)

SetChecked updates jspath only when check accepts the tentative result.

It performs the same update as Set, including updates to reachable exported fields through explicitly named unexported embedded fields. If the update reports a change, SetChecked calls check exactly once while obj contains the tentative result. A nil error commits the update. If check returns an error, SetChecked restores obj, returns false, and returns the error unchanged. If check panics, SetChecked restores obj before the panic continues. A nil check behaves like Set.

check is not called if the update is invalid or reports no change. When check uses Get to inspect obj, a path ending at an explicitly named unexported embedded field returns an error matching ErrPathNotFound, even after a tentative update beneath it; longer paths to reachable exported fields remain readable.

check must not mutate obj or values reachable from it, call Set or SetChecked on them, or retain references into a rejected value. Rollback restores only changes made by SetChecked.

SetChecked does not synchronize access to obj. Callers must prevent concurrent access for the entire call, including while check runs.

Example
package main

import (
	"encoding/json"
	"errors"
	"fmt"

	"github.com/linkdata/jq"
)

func main() {
	value := []string{"one"}
	maxBytes := len(`["one"]`)

	_, err := jq.SetChecked(&value, "1", "two", func() (err error) {
		var data []byte
		if data, err = json.Marshal(value); err == nil && len(data) > maxBytes {
			err = errors.New("value is too large")
		}
		return
	})

	fmt.Println(value)
	fmt.Println(err)
}
Output:
[one]
value is too large

Types

This section is empty.

Jump to

Keyboard shortcuts

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