Skip to content

Commit

Permalink
feat: add jsonpath and jmespath functions
Browse files Browse the repository at this point in the history
  • Loading branch information
moshloop committed Dec 26, 2024
1 parent d020e01 commit 3411c96
Show file tree
Hide file tree
Showing 10 changed files with 146 additions and 12 deletions.
45 changes: 45 additions & 0 deletions coll/jq.go → coll/json.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import (
"reflect"

"github.com/itchyny/gojq"
"github.com/jmespath/go-jmespath"
"github.com/ohler55/ojg/jp"
)

// JQ -
Expand Down Expand Up @@ -52,6 +54,49 @@ func JQ(ctx context.Context, jqExpr string, in interface{}) (interface{}, error)
return out, nil
}

func JMESPath(jmesPath string, in interface{}) (interface{}, error) {
// convert input to a supported type, if necessary
in, err := jqConvertType(in)
if err != nil {
return nil, fmt.Errorf("type conversion: %w", err)
}

if inString, ok := in.(string); ok {
var v map[string]any
if err := json.Unmarshal([]byte(inString), &v); err == nil {
in = v
}
}
result, err := jmespath.Search(jmesPath, in)

if err != nil {
return nil, fmt.Errorf("%+w", err)
}

return result, nil
}

func JSONPath(jsonPath string, in interface{}) (interface{}, error) {
// convert input to a supported type, if necessary
in, err := jqConvertType(in)
if err != nil {
return nil, fmt.Errorf("type conversion: %w", err)
}

if inString, ok := in.(string); ok {
var v map[string]any
if err := json.Unmarshal([]byte(inString), &v); err == nil {
in = v
}
}

x, err := jp.ParseString(jsonPath)
if err != nil {
return nil, err
}
return x.Get(in), nil
}

func isSupportableType(in interface{}) bool {
switch in.(type) {
case map[string]interface{},
Expand Down
File renamed without changes.
2 changes: 2 additions & 0 deletions funcs/cel_exports.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions funcs/coll.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ func CreateCollFuncs(ctx context.Context) map[string]interface{} {
f["flatten"] = ns.Flatten
f["mapToKeyVal"] = coll.MapToKeyVal[any]
f["keyValToMap"] = coll.KeyValToMap
f["jsonpath"] = coll.JSONPath
f["jmespath"] = coll.JMESPath
return f
}

Expand Down
66 changes: 66 additions & 0 deletions funcs/coll_gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ require (
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/itchyny/timefmt-go v0.1.6 // indirect
github.com/jeremywohl/flatten v0.0.0-20180923035001-588fe0d4c603 // indirect
github.com/jmespath/go-jmespath v0.4.1-0.20220621161143-b0104c826a24 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/kr/pretty v0.3.1 // indirect
github.com/kr/text v0.2.0 // indirect
Expand Down
3 changes: 3 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,9 @@ github.com/itchyny/timefmt-go v0.1.6 h1:ia3s54iciXDdzWzwaVKXZPbiXzxxnv1SPGFfM/my
github.com/itchyny/timefmt-go v0.1.6/go.mod h1:RRDZYC5s9ErkjQvTvvU7keJjxUYzIISJGxm9/mAERQg=
github.com/jeremywohl/flatten v0.0.0-20180923035001-588fe0d4c603 h1:gSech9iGLFCosfl/DC7BWnpSSh/tQClWnKS2I2vdPww=
github.com/jeremywohl/flatten v0.0.0-20180923035001-588fe0d4c603/go.mod h1:4AmD/VxjWcI5SRB0n6szE2A6s2fsNHDLO0nAlMHgfLQ=
github.com/jmespath/go-jmespath v0.4.1-0.20220621161143-b0104c826a24 h1:liMMTbpW34dhU4az1GN0pTPADwNmvoRSeoZ6PItiqnY=
github.com/jmespath/go-jmespath v0.4.1-0.20220621161143-b0104c826a24/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
Expand Down
19 changes: 11 additions & 8 deletions tests/cel_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -171,10 +171,6 @@ func TestCelFilePath(t *testing.T) {
}

func TestCelJSON(t *testing.T) {
person := Person{
Name: "Aditya",
Address: &Address{City: "Kathmandu"},
}

personJSONString, _ := json.Marshal(person)

Expand All @@ -184,19 +180,26 @@ func TestCelJSON(t *testing.T) {
{nil, `dyn({'name': 'John'}).toJSON()`, `{"name":"John"}`},
{nil, `{'name': 'John'}.toJSON()`, `{"name":"John"}`},
{nil, `1.toJSON()`, `1`},
{map[string]interface{}{"i": person}, "i.toJSON().JSON().name", "Aditya"},
{map[string]interface{}{"i": person}, "i.toJSON().JSON().name", "John Doe"},
{map[string]interface{}{"i": person}, `'["1", "2"]'.JSONArray()[0]`, "1"},
{map[string]interface{}{"i": map[string]string{"name": "aditya"}}, `i.toJSON()`, `{"name":"aditya"}`},

{nil, `'{"name": "John"}'.JSON().name`, `John`},
{nil, `'{"name": "Alice", "age": 30}'.JSON().name`, `Alice`},
{nil, `'[1, 2, 3, 4, 5]'.JSONArray()[0]`, `1`},
{map[string]interface{}{"i": person}, "i.toJSONPretty('\t')", "{\n\t\"Address\": {\n\t\t\"city_name\": \"Kathmandu\"\n\t},\n\t\"name\": \"Aditya\"\n}"},
{nil, "[\"Alice\", 30].toJSONPretty('\t')", "[\n\t\"Alice\",\n\t30\n]"},
{map[string]interface{}{"i": person}, "i.toJSONPretty('\t').JSON().addresses[0].country", "Nepal"},
{nil, "{'name': 'aditya'}.toJSONPretty('\t')", "{\n\t\"name\": \"aditya\"\n}"},

// JQ
{map[string]interface{}{"i": person}, "jsonpath('$.addresses[-1:].city_name', i)[0]", "New York"},
{map[string]interface{}{"i": person}, "jmespath('addresses[*].city_name', i)[0]", "Kathmandu"},
//FIXME: jmespath function return a parse error
{map[string]interface{}{"i": person}, "jmespath('length(addresses)', i)", "3"},
{map[string]interface{}{"i": person}, "jmespath('ceil(`1.2`)', i)", "2"},
//FIXME: jmespath always returns a list
{map[string]interface{}{"i": person}, "jmespath('name', i)", "John Doe"},

{map[string]interface{}{"i": person}, "jq('.Address.city_name', i)", "Kathmandu"},
{map[string]interface{}{"i": person}, "jq('.Address.country', i)", ""},
{map[string]interface{}{"i": personJSONString}, "jq('.Address.city_name', i)", "Kathmandu"},
})
}
Expand Down
15 changes: 11 additions & 4 deletions tests/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ type NoStructTag struct {
}

type Address struct {
City string `json:"city_name"`
City string `json:"city_name"`
Country string `json:"country,omitempty"`
}

type Person struct {
Expand All @@ -28,7 +29,7 @@ var person = Person{
Name: "John Doe",
Age: 25,
Address: &Address{
City: "Nepal",
City: "Kathmandu",
},
MetaData: map[string]any{
"key": "value",
Expand All @@ -39,10 +40,16 @@ var person = Person{
},
Addresses: []Address{
{
City: "Kathmandu",
City: "Kathmandu",
Country: "Nepal",
},
{
City: "Bhaktapur",
Country: "Nepal",
},
{
City: "Bhaktapur",
City: "New York",
Country: "USA",
},
},
}
Expand Down
5 changes: 5 additions & 0 deletions tests/gomplate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,11 @@ func TestGomplate(t *testing.T) {
{map[string]interface{}{"v": "1.2.3-beta.1+c0ff33"}, "{{ (.v | semver).Prerelease }}", "beta.1"},
{map[string]interface{}{"old": "1.2.3", "new": "1.2.3"}, "{{ .old | semverCompare .new }}", "true"},
{map[string]interface{}{"old": "1.2.3", "new": "1.2.4"}, "{{ .old | semverCompare .new }}", "false"},

{map[string]interface{}{"i": person}, `{{ index (jsonpath "$.addresses[-1:].city_name" .i) 0}}`, "New York"},
{map[string]interface{}{"i": person}, `{{ .i | jmespath "addresses[*].city_name | [0]"}}`, "Kathmandu"},
{map[string]interface{}{"i": person}, `{{ .i | jmespath "length(addresses)"}}`, "3"},

{map[string]interface{}{"kv": "a=b,c=d"}, "{{ (.kv | keyValToMap).a }}", "b"},
{inline, `{{.Name}}`, "Jane Doe"},
{inline, `{{ (.Data | base64.Decode | json).name }}`, "John Doe"},
Expand Down

0 comments on commit 3411c96

Please sign in to comment.