gojq

package module
v0.12.1-0...-a7688e3 Latest Latest
Warning

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

Go to latest
Published: Aug 22, 2024 License: MIT Imports: 21 Imported by: 0

README

gojq

CI Status Go Report Card MIT License release pkg.go.dev

Pure Go implementation of jq

This is an implementation of jq command written in Go language. You can also embed gojq as a library to your Go products.

Usage

 $ echo '{"foo": 128}' | gojq '.foo'
128
 $ echo '{"a": {"b": 42}}' | gojq '.a.b'
42
 $ echo '{"id": "sample", "10": {"b": 42}}' | gojq '{(.id): .["10"].b}'
{
  "sample": 42
}
 $ echo '[{"id":1},{"id":2},{"id":3}]' | gojq '.[] | .id'
1
2
3
 $ echo '{"a":1,"b":2}' | gojq '.a += 1 | .b *= 2'
{
  "a": 2,
  "b": 4
}
 $ echo '{"a":1} [2] 3' | gojq '. as {$a} ?// [$a] ?// $a | $a'
1
2
3
 $ echo '{"foo": 4722366482869645213696}' | gojq .foo
4722366482869645213696  # keeps the precision of large numbers
 $ gojq -n 'def fact($n): if $n < 1 then 1 else $n * fact($n - 1) end; fact(50)'
30414093201713378043612608166064768844377641568960512000000000000 # arbitrary-precision integer calculation

Nice error messages.

 $ echo '[1,2,3]' | gojq '.foo & .bar'
gojq: invalid query: .foo & .bar
    .foo & .bar
         ^  unexpected token "&"
 $ echo '{"foo": { bar: [] } }' | gojq '.'
gojq: invalid json: <stdin>
    {"foo": { bar: [] } }
              ^  invalid character 'b' looking for beginning of object key string

Installation

Homebrew
brew install gojq
Zero Install
0install add gojq https://apps.0install.net/utils/gojq.xml
Build from source
go install github.com/itchyny/gojq/cmd/gojq@latest
Docker
docker run -i --rm itchyny/gojq
docker run -i --rm ghcr.io/itchyny/gojq

Difference to jq

  • gojq is purely implemented with Go language and is completely portable. jq depends on the C standard library so the availability of math functions depends on the library. jq also depends on the regular expression library and it makes build scripts complex.
  • gojq implements nice error messages for invalid query and JSON input. The error message of jq is sometimes difficult to tell where to fix the query.
  • gojq does not keep the order of object keys. I understand this might cause problems for some scripts but basically, we should not rely on the order of object keys. Due to this limitation, gojq does not have keys_unsorted function and --sort-keys (-S) option. I would implement when ordered map is implemented in the standard library of Go but I'm less motivated.
  • gojq supports arbitrary-precision integer calculation while jq does not; jq loses the precision of large integers when calculation is involved. Note that even with gojq, all mathematical functions, including floor and round, convert integers to floating-point numbers; only addition, subtraction, multiplication, modulo, and division operators (when divisible) keep the integer precision. To calculate floor division of integers without losing the precision, use def idivide($n): (. - . % $n) / $n;. To round down floating-point numbers to integers, use def ifloor: floor | tostring | tonumber;, but note that this function does not work with large floating-point numbers and also loses the precision of large integers.
  • gojq behaves differently than jq in some features, hoping that jq will fix the behaviors in the future. gojq consistently counts by characters (not by bytes) in index, rindex, and indices functions; "12345" | .[index("3"):] results in "345" (jq#1430, jq#1624). gojq supports string indexing; "abcde"[2] (jq#1520). gojq fixes handling files with no newline characters at the end (jq#2374). gojq consistently truncates down floating-point number indices both in indexing ([0] | .[0.5] results in 0), and slicing ([0,1,2] | .[0.5:1.5] results in [0]). gojq parses unary operators with higher precedence than variable binding ([-1 as $x | 1,$x] results in [1,-1] not [-1,-1]) (jq#3053). gojq fixes @base64d to allow binary string as the decoded string (jq#1931). gojq improves time formatting and parsing; deals with %f in strftime and strptime (jq#1409), parses timezone offsets with fromdate and fromdateiso8601 (jq#1053), supports timezone name/offset with %Z/%z in strptime (jq#929, jq#2195), and looks up correct timezone during daylight saving time on formatting with %Z (jq#1912). gojq supports nanoseconds in date and time functions.
  • gojq does not support some functions intentionally; get_jq_origin, get_prog_origin, get_search_list (unstable, not listed in jq document), input_line_number, $__loc__ (performance issue). gojq does not support some flags; --ascii-output, -a (performance issue), --seq (not used commonly), --sort-keys, -S (sorts by default because map[string]any does not keep the order), --unbuffered (unbuffered by default). gojq does not parse JSON extensions supported by jq; NaN, Infinity, and [000]. gojq normalizes floating-point numbers to fit to double-precision floating-point numbers. gojq does not support some regular expression metacharacters, backreferences, look-around assertions, and some flags (regular expression engine differences). gojq does not support BOM (encoding/json does not support this). gojq disallows using keywords for function names (def true: .; true is a confusing query), and module name prefixes in function declarations (using module prefixes like def m::f: .; is undocumented).
  • gojq supports reading from YAML input (--yaml-input) while jq does not. gojq also supports YAML output (--yaml-output). gojq supports @urid format string (jq#798, jq#2261).
Color configuration

The gojq command automatically disables coloring output when the output is not a tty. To force coloring output, specify --color-output (-C) option. When NO_COLOR environment variable is present or --monochrome-output (-M) option is specified, gojq disables coloring output.

Use GOJQ_COLORS environment variable to configure individual colors. The variable is a colon-separated list of ANSI escape sequences of null, false, true, numbers, strings, object keys, arrays, and objects. The default configuration is 90:33:33:36:32:34;1.

Usage as a library

You can use the gojq parser and interpreter from your Go products.

package main

import (
	"fmt"
	"log"

	"github.com/wader/gojq"
)

func main() {
	query, err := gojq.Parse(".foo | ..")
	if err != nil {
		log.Fatalln(err)
	}
	input := map[string]any{"foo": []any{1, 2, 3}}
	iter := query.Run(input) // or query.RunWithContext
	for {
		v, ok := iter.Next()
		if !ok {
			break
		}
		if err, ok := v.(error); ok {
			if err, ok := err.(*gojq.HaltError); ok && err.Value() == nil {
				break
			}
			log.Fatalln(err)
		}
		fmt.Printf("%#v\n", v)
	}
}
  • Firstly, use gojq.Parse(string) (*Query, error) to get the query from a string.
    • Use gojq.ParseError to get the error position and token of the parsing error.
  • Secondly, get the result iterator
    • using query.Run or query.RunWithContext
    • or alternatively, compile the query using gojq.Compile and then code.Run or code.RunWithContext. You can reuse the *Code against multiple inputs to avoid compilation of the same query. But for arguments of code.Run, do not give values sharing same data between multiple calls.
    • In either case, you cannot use custom type values as the query input. The type should be []any for an array and map[string]any for a map (just like decoded to an any using the encoding/json package). You can't use []int or map[string]string, for example. If you want to query your custom struct, marshal to JSON, unmarshal to any and use it as the query input.
  • Thirdly, iterate through the results using iter.Next() (any, bool). The iterator can emit an error so make sure to handle it. The method returns true with results, and false when the iterator terminates.
    • The return type is not (any, error) because the iterator may emit multiple errors. The jq and gojq commands stop the iteration on the first error, but the library user can choose to stop the iteration on errors, or to continue until it terminates.
      • In any case, it is recommended to stop the iteration on gojq.HaltError, which is emitted by halt and halt_error functions, although these functions are rarely used. The error implements gojq.ValueError, and if the error value is nil, stop the iteration without handling the error. Technically speaking, we can fix the iterator to terminate on the halting error, but it does not terminate at the moment. The halt function in jq not only stops the iteration, but also terminates the command execution, even if there are still input values. So, gojq leaves it up to the library user how to handle the halting error.
    • Note that the result iterator may emit infinite number of values; repeat(0) and range(infinite). It may stuck with no output value; def f: f; f. Use RunWithContext when you want to limit the execution time.

gojq.Compile allows to configure the following compiler options.

  • gojq.WithModuleLoader allows to load modules. By default, the module feature is disabled. If you want to load modules from the file system, use gojq.NewModuleLoader.
  • gojq.WithEnvironLoader allows to configure the environment variables referenced by env and $ENV. By default, OS environment variables are not accessible due to security reasons. You can use gojq.WithEnvironLoader(os.Environ) if you want.
  • gojq.WithVariables allows to configure the variables which can be used in the query. Pass the values of the variables to code.Run in the same order.
  • gojq.WithFunction allows to add a custom internal function. An internal function can return a single value (which can be an error) each invocation. To add a jq function (which may include a comma operator to emit multiple values, empty function, accept a filter for its argument, or call another built-in function), use LoadInitModules of the module loader.
  • gojq.WithIterFunction allows to add a custom iterator function. An iterator function returns an iterator to emit multiple values. You cannot define both iterator and non-iterator functions of the same name (with possibly different arities). You can use gojq.NewIter to convert values or an error to a gojq.Iter.
  • gojq.WithInputIter allows to use input and inputs functions. By default, these functions are disabled.

Bug Tracker

Report bug at Issues・itchyny/gojq - GitHub.

Author

itchyny (https://github.com/itchyny)

License

This software is released under the MIT License, see LICENSE.

Documentation

Overview

Package gojq provides the parser and the interpreter of gojq. Please refer to Usage as a library for introduction.

Index

Examples

Constants

View Source
const (
	JQTypeArray   = "array"
	JQTypeBoolean = "boolean"
	JQTypeNull    = "null"
	JQTypeNumber  = "number"
	JQTypeObject  = "object"
	JQTypeString  = "string"
)

TODO: use in TypeOf?

Variables

This section is empty.

Functions

func BinopTypeSwitch

func BinopTypeSwitch(
	l, r any,
	callbackInts func(_, _ int) any,
	callbackFloats func(_, _ float64) any,
	callbackBigInts func(_, _ *big.Int) any,
	callbackStrings func(_, _ string) any,
	callbackArrays func(_, _ []any) any,
	callbackMaps func(_, _ map[string]any) any,
	fallback func(_, _ any) any) any

BinopTypeSwitch helper for external binops re-exported instead of renamed to make it easier to follow upstream

func Compare

func Compare(l, r any) int

Compare l and r, and returns jq-flavored comparison value. The result will be 0 if l == r, -1 if l < r, and +1 if l > r. This comparison is used by built-in operators and functions.

func Marshal

func Marshal(v any) ([]byte, error)

Marshal returns the jq-flavored JSON encoding of v.

This method accepts only limited types (nil, bool, int, float64, *big.Int, string, []any, and map[string]any) because these are the possible types a gojq iterator can emit. This method marshals NaN to null, truncates infinities to (+|-) math.MaxFloat64, uses \b and \f in strings, and does not escape '<', '>', '&', '\u2028', and '\u2029'. These behaviors are based on the marshaler of jq command, and different from json.Marshal in the Go standard library. Note that the result is not safe to embed in HTML.

func NormalizeNumber

func NormalizeNumber(v json.Number) any

func NormalizeNumbers

func NormalizeNumbers(v any) any

func Preview

func Preview(v any) string

Preview returns the preview string of v. The preview string is basically the same as the jq-flavored JSON encoding returned by Marshal, but is truncated by 30 bytes, and more efficient than truncating the result of Marshal.

This method is used by error messages of built-in operators and functions, and accepts only limited types (nil, bool, int, float64, *big.Int, string, []any, and map[string]any). Note that the maximum width and trailing strings on truncation may be changed in the future.

func TypeOf

func TypeOf(v any) string

TypeOf returns the jq-flavored type name of v.

This method is used by built-in type/0 function, and accepts only limited types (nil, bool, int, float64, *big.Int, string, []any, and map[string]any).

func ValidNumber

func ValidNumber(s string) bool

Types

type Array

type Array struct {
	Query *Query `json:"query,omitempty"`
}

Array ...

func (*Array) String

func (e *Array) String() string

type Bind

type Bind struct {
	Patterns []*Pattern `json:"patterns,omitempty"`
	Body     *Query     `json:"body,omitempty"`
}

Bind ...

func (*Bind) String

func (e *Bind) String() string

type Code

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

Code is a compiled jq query.

func Compile

func Compile(q *Query, options ...CompilerOption) (*Code, error)

Compile compiles a query.

Example
package main

import (
	"fmt"
	"log"

	"github.com/wader/gojq"
)

func main() {
	query, err := gojq.Parse(".[] | .foo")
	if err != nil {
		log.Fatalln(err)
	}
	code, err := gojq.Compile(query)
	if err != nil {
		log.Fatalln(err)
	}
	iter := code.Run([]any{
		nil,
		"string",
		42,
		[]any{"foo"},
		map[string]any{"foo": 42},
	})
	for {
		v, ok := iter.Next()
		if !ok {
			break
		}
		if err, ok := v.(error); ok {
			fmt.Println(err)
			continue
		}
		fmt.Printf("%#v\n", v)
	}

}
Output:

<nil>
expected an object but got: string ("string")
expected an object but got: number (42)
expected an object but got: array (["foo"])
42

func (*Code) Run

func (c *Code) Run(v any, values ...any) Iter

Run runs the code with the variable values (which should be in the same order as the given variables using WithVariables) and returns a result iterator.

It is safe to call this method in goroutines, to reuse a compiled *Code. But for arguments, do not give values sharing same data between goroutines.

Example
package main

import (
	"fmt"
	"log"

	"github.com/wader/gojq"
)

func main() {
	query, err := gojq.Parse(".foo")
	if err != nil {
		log.Fatalln(err)
	}
	code, err := gojq.Compile(query)
	if err != nil {
		log.Fatalln(err)
	}
	input := map[string]any{"foo": 42}
	iter := code.Run(input)
	for {
		v, ok := iter.Next()
		if !ok {
			break
		}
		if err, ok := v.(error); ok {
			log.Fatalln(err)
		}
		fmt.Printf("%#v\n", v)
	}

}
Output:

42

func (*Code) RunWithContext

func (c *Code) RunWithContext(ctx context.Context, v any, values ...any) Iter

RunWithContext runs the code with context.

Example
package main

import (
	"context"
	"fmt"
	"log"
	"time"

	"github.com/wader/gojq"
)

func main() {
	query, err := gojq.Parse("def f: f; f, f")
	if err != nil {
		log.Fatalln(err)
	}
	code, err := gojq.Compile(query)
	if err != nil {
		log.Fatalln(err)
	}
	ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
	defer cancel()
	iter := code.RunWithContext(ctx, nil)
	for {
		v, ok := iter.Next()
		if !ok {
			break
		}
		if err, ok := v.(error); ok {
			fmt.Println(err)
			continue
		}
		_ = v
	}

}
Output:

context deadline exceeded

type CompilerOption

type CompilerOption func(*compiler)

CompilerOption is a compiler option.

func WithEnvironLoader

func WithEnvironLoader(environLoader func() []string) CompilerOption

WithEnvironLoader is a compiler option for environment variables loader. The OS environment variables are not accessible by default due to security reasons. You can specify os.Environ as argument if you allow to access.

Example
package main

import (
	"fmt"
	"log"

	"github.com/wader/gojq"
)

func main() {
	query, err := gojq.Parse("env | keys[]")
	if err != nil {
		log.Fatalln(err)
	}
	code, err := gojq.Compile(
		query,
		gojq.WithEnvironLoader(func() []string {
			return []string{"foo=42", "bar=128"}
		}),
	)
	if err != nil {
		log.Fatalln(err)
	}
	iter := code.Run(nil)
	for {
		v, ok := iter.Next()
		if !ok {
			break
		}
		if err, ok := v.(error); ok {
			log.Fatalln(err)
		}
		fmt.Printf("%#v\n", v)
	}

}
Output:

"bar"
"foo"

func WithFunction

func WithFunction(name string, minarity, maxarity int, f func(any, []any) any) CompilerOption

WithFunction is a compiler option for adding a custom internal function. Specify the minimum and maximum count of the function arguments. These values should satisfy 0 <= minarity <= maxarity <= 30, otherwise panics. On handling numbers, you should take account to int, float64 and *big.Int. These are the number types you are allowed to return, so do not return int64. Refer to ValueError to return a value error just like built-in error function. If you want to emit multiple values, call the empty function, accept a filter for its argument, or call another built-in function, then use LoadInitModules of the module loader.

Example
package main

import (
	"encoding/json"
	"fmt"
	"log"
	"math/big"
	"strconv"

	"github.com/wader/gojq"
)

func toFloat(x any) (float64, bool) {
	switch x := x.(type) {
	case int:
		return float64(x), true
	case float64:
		return x, true
	case *big.Int:
		f, err := strconv.ParseFloat(x.String(), 64)
		return f, err == nil
	default:
		return 0.0, false
	}
}

func main() {
	query, err := gojq.Parse(".[] | f | f(3)")
	if err != nil {
		log.Fatalln(err)
	}
	code, err := gojq.Compile(
		query,
		gojq.WithFunction("f", 0, 1, func(x any, xs []any) any {
			if x, ok := toFloat(x); ok {
				if len(xs) == 1 {
					if y, ok := toFloat(xs[0]); ok {
						x *= y
					} else {
						return fmt.Errorf("f cannot be applied to: %v, %v", x, xs)
					}
				} else {
					x += 2
				}
				return x
			}
			return fmt.Errorf("f cannot be applied to: %v, %v", x, xs)
		}),
	)
	if err != nil {
		log.Fatalln(err)
	}
	input := []any{0, 1, 2.5, json.Number("10000000000000000000000000000000000000000")}
	iter := code.Run(input)
	for {
		v, ok := iter.Next()
		if !ok {
			break
		}
		if err, ok := v.(error); ok {
			log.Fatalln(err)
		}
		fmt.Printf("%#v\n", v)
	}

}
Output:

6
9
13.5
3e+40

func WithInputIter

func WithInputIter(inputIter Iter) CompilerOption

WithInputIter is a compiler option for input iterator used by input(s)/0. Note that input and inputs functions are not allowed by default. We have to distinguish the query input and the values for input(s) functions. For example, consider using inputs with --null-input. If you want to allow input(s) functions, create an Iter and use WithInputIter option.

Example
package main

import (
	"fmt"
	"log"

	"github.com/wader/gojq"
)

func main() {
	query, err := gojq.Parse("reduce inputs as $x (0; . + $x)")
	if err != nil {
		log.Fatalln(err)
	}
	code, err := gojq.Compile(
		query,
		gojq.WithInputIter(gojq.NewIter(1, 2, 3, 4, 5)),
	)
	if err != nil {
		log.Fatalln(err)
	}
	iter := code.Run(nil)
	for {
		v, ok := iter.Next()
		if !ok {
			break
		}
		if err, ok := v.(error); ok {
			log.Fatalln(err)
		}
		fmt.Printf("%#v\n", v)
	}

}
Output:

15

func WithIterFunction

func WithIterFunction(name string, minarity, maxarity int, f func(any, []any) Iter) CompilerOption

WithIterFunction is a compiler option for adding a custom iterator function. This is like the WithFunction option, but you can add a function which returns an Iter to emit multiple values. You cannot define both iterator and non-iterator functions of the same name (with possibly different arities). See also NewIter, which can be used to convert values or an error to an Iter.

Example
package main

import (
	"fmt"
	"log"

	"github.com/wader/gojq"
)

// Implementation of range/2 using WithIterFunction option.
type rangeIter struct {
	value, max int
}

func (iter *rangeIter) Next() (any, bool) {
	if iter.value >= iter.max {
		return nil, false
	}
	v := iter.value
	iter.value++
	return v, true
}

func main() {
	query, err := gojq.Parse("f(3; 7)")
	if err != nil {
		log.Fatalln(err)
	}
	code, err := gojq.Compile(
		query,
		gojq.WithIterFunction("f", 2, 2, func(_ any, xs []any) gojq.Iter {
			if x, ok := xs[0].(int); ok {
				if y, ok := xs[1].(int); ok {
					return &rangeIter{x, y}
				}
			}
			return gojq.NewIter(fmt.Errorf("f cannot be applied to: %v", xs))
		}),
	)
	if err != nil {
		log.Fatalln(err)
	}
	iter := code.Run(nil)
	for {
		v, ok := iter.Next()
		if !ok {
			break
		}
		if err, ok := v.(error); ok {
			log.Fatalln(err)
		}
		fmt.Printf("%#v\n", v)
	}

}
Output:

3
4
5
6

func WithModuleLoader

func WithModuleLoader(moduleLoader ModuleLoader) CompilerOption

WithModuleLoader is a compiler option for module loader. If you want to load modules from the filesystem, use NewModuleLoader.

Example
package main

import (
	"fmt"
	"log"

	"github.com/wader/gojq"
)

type moduleLoader struct{}

func (*moduleLoader) LoadModule(name string) (*gojq.Query, error) {
	switch name {
	case "module1":
		return gojq.Parse(`
			module { name: "module1", test: 42 };
			import "module2" as foo;
			def g: foo::f;
		`)
	case "module2":
		return gojq.Parse(`
			def f: .foo;
		`)
	case "module3":
		return gojq.Parse("")
	}
	return nil, fmt.Errorf("module not found: %q", name)
}

func main() {
	query, err := gojq.Parse(`
		import "module1" as m;
		m::g
	`)
	if err != nil {
		log.Fatalln(err)
	}
	code, err := gojq.Compile(
		query,
		gojq.WithModuleLoader(&moduleLoader{}),
	)
	if err != nil {
		log.Fatalln(err)
	}
	input := map[string]any{"foo": 42}
	iter := code.Run(input)
	for {
		v, ok := iter.Next()
		if !ok {
			break
		}
		if err, ok := v.(error); ok {
			log.Fatalln(err)
		}
		fmt.Printf("%#v\n", v)
	}

}
Output:

42

func WithVariables

func WithVariables(variables []string) CompilerOption

WithVariables is a compiler option for variable names. The variables can be used in the query. You have to give the values to *Code.Run in the same order.

Example
package main

import (
	"fmt"
	"log"

	"github.com/wader/gojq"
)

func main() {
	query, err := gojq.Parse("$x * 100 + $y, $z")
	if err != nil {
		log.Fatalln(err)
	}
	code, err := gojq.Compile(
		query,
		gojq.WithVariables([]string{
			"$x", "$y", "$z",
		}),
	)
	if err != nil {
		log.Fatalln(err)
	}
	iter := code.Run(nil, 12, 42, 128)
	for {
		v, ok := iter.Next()
		if !ok {
			break
		}
		if err, ok := v.(error); ok {
			log.Fatalln(err)
		}
		fmt.Printf("%#v\n", v)
	}

}
Output:

1242
128

type ConstArray

type ConstArray struct {
	Elems []*ConstTerm `json:"elems,omitempty"`
}

ConstArray ...

func (*ConstArray) String

func (e *ConstArray) String() string

type ConstObject

type ConstObject struct {
	KeyVals []*ConstObjectKeyVal `json:"keyvals,omitempty"`
}

ConstObject ...

func (*ConstObject) String

func (e *ConstObject) String() string

func (*ConstObject) ToValue

func (e *ConstObject) ToValue() map[string]any

ToValue converts the object to map[string]any.

type ConstObjectKeyVal

type ConstObjectKeyVal struct {
	Key       string     `json:"key,omitempty"`
	KeyString string     `json:"key_string,omitempty"`
	Val       *ConstTerm `json:"val,omitempty"`
}

ConstObjectKeyVal ...

func (*ConstObjectKeyVal) String

func (e *ConstObjectKeyVal) String() string

type ConstTerm

type ConstTerm struct {
	Object *ConstObject `json:"object,omitempty"`
	Array  *ConstArray  `json:"array,omitempty"`
	Number string       `json:"number,omitempty"`
	Str    string       `json:"str,omitempty"`
	Null   bool         `json:"null,omitempty"`
	True   bool         `json:"true,omitempty"`
	False  bool         `json:"false,omitempty"`
}

ConstTerm ...

func (*ConstTerm) String

func (e *ConstTerm) String() string

type Foreach

type Foreach struct {
	Query   *Query   `json:"query,omitempty"`
	Pattern *Pattern `json:"pattern,omitempty"`
	Start   *Query   `json:"start,omitempty"`
	Update  *Query   `json:"update,omitempty"`
	Extract *Query   `json:"extract,omitempty"`
}

Foreach ...

func (*Foreach) String

func (e *Foreach) String() string

type Func

type Func struct {
	Name string   `json:"name,omitempty"`
	Args []*Query `json:"args,omitempty"`
}

Func ...

func (*Func) String

func (e *Func) String() string

type FuncDef

type FuncDef struct {
	Name string   `json:"name,omitempty"`
	Args []string `json:"args,omitempty"`
	Body *Query   `json:"body,omitempty"`
}

FuncDef ...

func (*FuncDef) Minify

func (e *FuncDef) Minify()

Minify ...

func (*FuncDef) String

func (e *FuncDef) String() string

type HaltError

type HaltError exitCodeError

HaltError is an error emitted by halt and halt_error functions. It implements ValueError, and if the value is nil, discard the error and stop the iteration. Consider a query like "1, halt, 2"; the first value is 1, and the second value is a HaltError with nil value. You might think the iterator should not emit an error this case, but it should so that we can recognize the halt error to stop the outer loop of iterating input values; echo 1 2 3 | gojq "., halt".

func (*HaltError) Error

func (err *HaltError) Error() string

func (*HaltError) ExitCode

func (err *HaltError) ExitCode() int

ExitCode returns the exit code of the error.

func (*HaltError) Value

func (err *HaltError) Value() any

Value returns the value of the error. This implements ValueError, but halt error is not catchable by try-catch.

type If

type If struct {
	Cond *Query    `json:"cond,omitempty"`
	Then *Query    `json:"then,omitempty"`
	Elif []*IfElif `json:"elif,omitempty"`
	Else *Query    `json:"else,omitempty"`
}

If ...

func (*If) String

func (e *If) String() string

type IfElif

type IfElif struct {
	Cond *Query `json:"cond,omitempty"`
	Then *Query `json:"then,omitempty"`
}

IfElif ...

func (*IfElif) String

func (e *IfElif) String() string

type Import

type Import struct {
	ImportPath  string       `json:"import_path,omitempty"`
	ImportAlias string       `json:"import_alias,omitempty"`
	IncludePath string       `json:"include_path,omitempty"`
	Meta        *ConstObject `json:"meta,omitempty"`
}

Import ...

func (*Import) String

func (e *Import) String() string

type Index

type Index struct {
	Name    string  `json:"name,omitempty"`
	Str     *String `json:"str,omitempty"`
	Start   *Query  `json:"start,omitempty"`
	End     *Query  `json:"end,omitempty"`
	IsSlice bool    `json:"is_slice,omitempty"`
}

Index ...

func (*Index) String

func (e *Index) String() string

type Iter

type Iter interface {
	Next() (any, bool)
}

Iter is an interface for an iterator.

func NewIter

func NewIter(values ...any) Iter

NewIter creates a new Iter from values.

type JQValue

type JQValue interface {
	// JQValueLength is length of value, ex: value | length
	JQValueLength() any // int

	// JQValueSliceLen slice length
	JQValueSliceLen() any // int

	// JQValueIndex look up index for value, ex: value[index]
	// index -1 outside after slice, -2 outside before slice
	JQValueIndex(index int) any // value

	// JQValueSlice slices value, ex: value[start:end]
	// start and end indexes are translated and clamped using JQValueSliceLen
	JQValueSlice(start int, end int) any // []any

	// JQValueKey look up key value of value: ex: value[name]
	JQValueKey(name string) any // value

	// JQValueEach each of value, ex: value[]
	JQValueEach() any // []PathValue

	// JQValueKeys keys for value, ex: value | keys
	JQValueKeys() any // []string

	// JQValueHas check if value has key, ex: value | has(key)
	JQValueHas(key any) any // bool

	// JQValueType type of value, ex: value | type
	JQValueType() string // a JQType* constant

	// JQValueToNumber is value represented as a number, ex: value | tonumber
	JQValueToNumber() any // number

	// JQValueToString is value represented as a string, ex: value | tostring
	JQValueToString() any // string

	// JQValue value represented as a gojq compatible value
	JQValueToGoJQ() any // value
}

JQValue represents something that can be a jq value All functions with return type any can return error on error array = []any boolean = bool null = nil number = int | float64 | *big.Int object = map[string]any string = string value = number | boolean | string | array | object | null

type Label

type Label struct {
	Ident string `json:"ident,omitempty"`
	Body  *Query `json:"body,omitempty"`
}

Label ...

func (*Label) String

func (e *Label) String() string

type ModuleLoader

type ModuleLoader any

ModuleLoader is the interface for loading modules.

Implement following optional methods. Use NewModuleLoader to load local modules.

LoadInitModules() ([]*Query, error)
LoadModule(string) (*Query, error)
LoadModuleWithMeta(string, map[string]any) (*Query, error)
LoadJSON(string) (any, error)
LoadJSONWithMeta(string, map[string]any) (any, error)

func NewModuleLoader

func NewModuleLoader(paths []string) ModuleLoader

NewModuleLoader creates a new ModuleLoader loading local modules in the paths. Note that user can load modules outside the paths using "search" path of metadata. Empty paths are ignored, so specify "." for the current working directory.

type Object

type Object struct {
	KeyVals []*ObjectKeyVal `json:"key_vals,omitempty"`
}

Object ...

func (*Object) String

func (e *Object) String() string

type ObjectKeyVal

type ObjectKeyVal struct {
	Key       string  `json:"key,omitempty"`
	KeyString *String `json:"key_string,omitempty"`
	KeyQuery  *Query  `json:"key_query,omitempty"`
	Val       *Query  `json:"val,omitempty"`
}

ObjectKeyVal ...

func (*ObjectKeyVal) String

func (e *ObjectKeyVal) String() string

type Operator

type Operator int

Operator ...

const (
	OpPipe Operator = iota + 1
	OpComma
	OpAdd
	OpSub
	OpMul
	OpDiv
	OpMod
	OpEq
	OpNe
	OpGt
	OpLt
	OpGe
	OpLe
	OpAnd
	OpOr
	OpAlt
	OpAssign
	OpModify
	OpUpdateAdd
	OpUpdateSub
	OpUpdateMul
	OpUpdateDiv
	OpUpdateMod
	OpUpdateAlt
)

Operators ...

func OperatorFromString

func OperatorFromString(s string) Operator

String implements fmt.Stringer.

func (Operator) GoString

func (op Operator) GoString() (str string)

GoString implements fmt.GoStringer.

func (Operator) MarshalJSON

func (op Operator) MarshalJSON() ([]byte, error)

func (Operator) String

func (op Operator) String() string

String implements fmt.Stringer.

func (*Operator) UnmarshalJSON

func (op *Operator) UnmarshalJSON(text []byte) error

type ParseError

type ParseError struct {
	Offset int    // the error occurred after reading Offset bytes
	Token  string // the Token that caused the error (may be empty)
	// contains filtered or unexported fields
}

ParseError represents a description of a query parsing error.

func (*ParseError) Error

func (err *ParseError) Error() string

type PathValue

type PathValue struct {
	Path, Value any
}

PathValue is a part of a jq path expression

type Pattern

type Pattern struct {
	Name   string           `json:"name,omitempty"`
	Array  []*Pattern       `json:"array,omitempty"`
	Object []*PatternObject `json:"object,omitempty"`
}

Pattern ...

func (*Pattern) String

func (e *Pattern) String() string

type PatternObject

type PatternObject struct {
	Key       string   `json:"key,omitempty"`
	KeyString *String  `json:"key_string,omitempty"`
	KeyQuery  *Query   `json:"key_query,omitempty"`
	Val       *Pattern `json:"val,omitempty"`
}

PatternObject ...

func (*PatternObject) String

func (e *PatternObject) String() string

type Query

type Query struct {
	Meta     *ConstObject `json:"meta,omitempty"`
	Imports  []*Import    `json:"imports,omitempty"`
	FuncDefs []*FuncDef   `json:"func_defs,omitempty"`
	Term     *Term        `json:"term,omitempty"`
	Left     *Query       `json:"left,omitempty"`
	Op       Operator     `json:"op,omitempty"`
	Right    *Query       `json:"right,omitempty"`
	Func     string       `json:"func,omitempty"`
}

Query represents the abstract syntax tree of a jq query.

func Parse

func Parse(src string) (*Query, error)

Parse a query string, and returns the query struct.

If parsing failed, it returns an error of type *ParseError, which has the byte offset and the invalid token. The byte offset is the scanned bytes when the error occurred. The token is empty if the error occurred after scanning the entire query string.

func (*Query) Run

func (e *Query) Run(v any) Iter

Run the query.

It is safe to call this method in goroutines, to reuse a parsed *Query. But for arguments, do not give values sharing same data between goroutines.

Example
package main

import (
	"fmt"
	"log"

	"github.com/wader/gojq"
)

func main() {
	query, err := gojq.Parse(".foo | ..")
	if err != nil {
		log.Fatalln(err)
	}
	input := map[string]any{"foo": []any{1, 2, 3}}
	iter := query.Run(input)
	for {
		v, ok := iter.Next()
		if !ok {
			break
		}
		if err, ok := v.(error); ok {
			log.Fatalln(err)
		}
		fmt.Printf("%#v\n", v)
	}

}
Output:

[]interface {}{1, 2, 3}
1
2
3

func (*Query) RunWithContext

func (e *Query) RunWithContext(ctx context.Context, v any) Iter

RunWithContext runs the query with context.

Example
package main

import (
	"context"
	"fmt"
	"log"
	"time"

	"github.com/wader/gojq"
)

func main() {
	query, err := gojq.Parse("def f: f; f, f")
	if err != nil {
		log.Fatalln(err)
	}
	ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
	defer cancel()
	iter := query.RunWithContext(ctx, nil)
	for {
		v, ok := iter.Next()
		if !ok {
			break
		}
		if err, ok := v.(error); ok {
			fmt.Println(err)
			continue
		}
		_ = v
	}

}
Output:

context deadline exceeded

func (*Query) String

func (e *Query) String() string

type Reduce

type Reduce struct {
	Query   *Query   `json:"query,omitempty"`
	Pattern *Pattern `json:"pattern,omitempty"`
	Start   *Query   `json:"start,omitempty"`
	Update  *Query   `json:"update,omitempty"`
}

Reduce ...

func (*Reduce) String

func (e *Reduce) String() string

type String

type String struct {
	Str     string   `json:"str,omitempty"`
	Queries []*Query `json:"queries,omitempty"`
}

String ...

func (*String) String

func (e *String) String() string

type Suffix

type Suffix struct {
	Index    *Index `json:"index,omitempty"`
	Iter     bool   `json:"iter,omitempty"`
	Optional bool   `json:"optional,omitempty"`
	Bind     *Bind  `json:"bind,omitempty"`
}

Suffix ...

func (*Suffix) String

func (e *Suffix) String() string

type Term

type Term struct {
	Type       TermType  `json:"type,omitempty"`
	Index      *Index    `json:"index,omitempty"`
	Func       *Func     `json:"func,omitempty"`
	Object     *Object   `json:"object,omitempty"`
	Array      *Array    `json:"array,omitempty"`
	Number     string    `json:"number,omitempty"`
	Unary      *Unary    `json:"unary,omitempty"`
	Format     string    `json:"format,omitempty"`
	Str        *String   `json:"str,omitempty"`
	If         *If       `json:"if,omitempty"`
	Try        *Try      `json:"try,omitempty"`
	Reduce     *Reduce   `json:"reduce,omitempty"`
	Foreach    *Foreach  `json:"foreach,omitempty"`
	Label      *Label    `json:"label,omitempty"`
	Break      string    `json:"break,omitempty"`
	Query      *Query    `json:"query,omitempty"`
	SuffixList []*Suffix `json:"suffix_list,omitempty"`
}

Term ...

func (*Term) String

func (e *Term) String() string

type TermType

type TermType int

TermType represents the type of Term.

const (
	TermTypeIdentity TermType = iota + 1
	TermTypeRecurse
	TermTypeNull
	TermTypeTrue
	TermTypeFalse
	TermTypeIndex
	TermTypeFunc
	TermTypeObject
	TermTypeArray
	TermTypeNumber
	TermTypeUnary
	TermTypeFormat
	TermTypeString
	TermTypeIf
	TermTypeTry
	TermTypeReduce
	TermTypeForeach
	TermTypeLabel
	TermTypeBreak
	TermTypeQuery
)

TermType list.

func TermTypeFromString

func TermTypeFromString(s string) TermType

GoString implements fmt.GoStringer.

func (TermType) GoString

func (termType TermType) GoString() (str string)

GoString implements fmt.GoStringer.

func (TermType) MarshalJSON

func (termType TermType) MarshalJSON() ([]byte, error)

func (*TermType) UnmarshalJSON

func (termType *TermType) UnmarshalJSON(text []byte) error

type Try

type Try struct {
	Body  *Query `json:"body,omitempty"`
	Catch *Query `json:"catch,omitempty"`
}

Try ...

func (*Try) String

func (e *Try) String() string

type Unary

type Unary struct {
	Op   Operator `json:"op,omitempty"`
	Term *Term    `json:"term,omitempty"`
}

Unary ...

func (*Unary) String

func (e *Unary) String() string

type ValueError

type ValueError interface {
	error
	Value() any
}

ValueError is an interface for errors with a value for internal function. Return an error implementing this interface when you want to catch error values (not error messages) by try-catch, just like built-in error function. Refer to WithFunction to add a custom internal function.

Directories

Path Synopsis
Package cli implements the gojq command.
Package cli implements the gojq command.
cmd
gojq
gojq - Go implementation of jq
gojq - Go implementation of jq

Jump to

Keyboard shortcuts

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