Skip to content

nikandfor/jq

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

85 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Documentation Go workflow CircleCI codecov Go Report Card GitHub tag (latest SemVer)

jq

jq is a jq-like library. It's intended to simplify working with unstructured data. It's aimed to be almost fully compatible with original jq. It doesn't use reflection or usafe hacks. It reuses memory -> less allocs -> less gc pressure -> better performance and less memory and cpu usage.

Usage

Data Reshaping

Code is from examples.

	// Suppose some API returns this object where among tons of other useless keys we have this:
	input := `{
		    "data": {
		        "entries": [
		            {"data": {"the actual interesting object": "here"}},
		            {"data": {"the actual interesting object": "here"}},
		            {"data": {"the actual interesting object": "here"}},
		        ],
		        "pagination": {
		            "next_cursor": "some_cursor"
		        }
		    }
		}`

	/*
		And we want:

		{
		    "results": [
		        {"the actual interesting object": "here"},
		        {"the actual interesting object": "here"},
		        {"the actual interesting object": "here"},
		    ],
		    "cursor": "some_cursor"
		}
	*/

	// Prepare filter, decoder, encoder, and buffer.
	// Better to do it once and reuse, but in a single threaded manner.

	// This is equivalent to jq program:
	// {results: [.data.entries[].data], cursor: .data.pagination.next_cursor}
	f := jq.NewObject(
		"results", jq.NewArray(
			jq.NewQuery("data", "entries", jq.NewIter(), "data"),
		),
		"cursor", jq.NewQuery("data", "pagination", "next_cursor"),
	)

	s := jq.NewSandwich(
		jqjson.NewDecoder(),
		jqjson.NewEncoder(),
	)
	s.Reset() // call if s is reused. Process* do it implicitly.

	// read data
	r := strings.NewReader(input) // net.Conn or something

	buf, err := io.ReadAll(r)
	_ = err // if err != nil ...

	var res []byte

	res, err = s.ProcessAll(f, res[:0], buf)
	_ = err // if err != nil ...

	// res now contains what we wanted

Format Conversion

	// Suppose we requested data with the query and got this results in csv format.
	query := "james bond"
	input := `id,graphql_id,name,url,followers
124,ArWqv41,"James Bond","https://page-url.com/profile/124",100500
140,RefqWet,"James Bond Jr.","https://page-url.com/profile/140",1030
`

	// This is equivalent to jq program:
	// {query: "query"} + .
	f := jq.NewPlus(jq.NewObject("query", jq.NewLiteral(query)), jq.Dot{})

	d := jqcsv.NewDecoder()
	d.Tag = cbor.Map
	d.Header = true

	e := jqjson.NewEncoder()
	e.Separator = []byte{'\n'}

	s := jq.NewSandwich(d, e)
	s.Reset() // call if s is reused. Process* do it implicitly.

	buf := []byte(input)
	res, err := s.ProcessAll(f, nil, buf)
	_ = err // if err != nil ...

	_ = res // res is a new line separated list of json objects with `"query": "james bond"` added to each object

Extracting Data From the Hell

	// generated by command
	// jq -nc '{key3: "value"} | {key2: (. | tojson)} | @base64 | {key1: .}'
	data := []byte(`{"key1":"eyJrZXkyIjoie1wia2V5M1wiOlwidmFsdWVcIn0ifQ=="}`)

	f := jq.NewQuery(
		"key1",
		jqbase64.NewDecoder(base64.StdEncoding),
		jqjson.NewDecoder(),
		"key2",
		jqjson.NewDecoder(),
		"key3",
	)

	s := jq.NewSandwich(jqjson.NewDecoder(), nil)
	s.Reset() // call if s is reused. Process* do it implicitly.

	res, _, _, err := s.DecodeApply(f, data, 0)
	_ = err // if err != nil {

	value, err := s.Buffer.Reader().BytesChecked(res)
	_ = err // if err != nil { // not a string (or bytes)

	fmt.Printf("%s\n", value)

Releases

No releases published

Packages

No packages published

Languages