fix(jsonpath): Properly handle len of object in array, len of int and len of bool (#372)

This commit is contained in:
TwiN
2022-11-19 17:25:40 -05:00
committed by GitHub
parent e9f46c58f8
commit 4f569b7a0e
3 changed files with 258 additions and 191 deletions

View File

@ -20,6 +20,7 @@ func Eval(path string, b []byte) (string, int, error) {
return walk(path, object)
}
// walk traverses the object and returns the value as a string as well as its length
func walk(path string, object interface{}) (string, int, error) {
var keys []string
startOfCurrentKey, bracketDepth := 0, 0
@ -41,7 +42,15 @@ func walk(path string, object interface{}) (string, int, error) {
currentKey := keys[0]
switch value := extractValue(currentKey, object).(type) {
case map[string]interface{}:
return walk(strings.Replace(path, fmt.Sprintf("%s.", currentKey), "", 1), value)
newPath := strings.Replace(path, fmt.Sprintf("%s.", currentKey), "", 1)
if path == newPath {
// If the path hasn't changed, it means we're at the end of the path
// So we'll treat it as a string by re-marshaling it to JSON since it's a map.
// Note that the output JSON will be minified.
b, err := json.Marshal(value)
return string(b), len(b), err
}
return walk(newPath, value)
case string:
if len(keys) > 1 {
return "", 0, fmt.Errorf("couldn't walk through '%s', because '%s' was a string instead of an object", keys[1], currentKey)
@ -50,7 +59,8 @@ func walk(path string, object interface{}) (string, int, error) {
case []interface{}:
return fmt.Sprintf("%v", value), len(value), nil
case interface{}:
return fmt.Sprintf("%v", value), 1, nil
newValue := fmt.Sprintf("%v", value)
return newValue, len(newValue), nil
default:
return "", 0, fmt.Errorf("couldn't walk through '%s' because type was '%T', but expected 'map[string]interface{}'", currentKey, value)
}

View File

@ -47,7 +47,7 @@ func TestEval(t *testing.T) {
ExpectedError: false,
},
{
Name: "array-of-maps",
Name: "array-of-objects",
Path: "ids[1].id",
Data: `{"ids": [{"id": 1}, {"id": 2}]}`,
ExpectedOutput: "2",
@ -87,7 +87,15 @@ func TestEval(t *testing.T) {
ExpectedError: false,
},
{
Name: "array-of-maps-at-root",
Name: "array-of-objects-at-root",
Path: "[0]",
Data: `[{"id": 1}, {"id": 2}]`,
ExpectedOutput: `{"id":1}`,
ExpectedOutputLength: 8,
ExpectedError: false,
},
{
Name: "array-of-objects-with-int-at-root",
Path: "[0].id",
Data: `[{"id": 1}, {"id": 2}]`,
ExpectedOutput: "1",
@ -95,7 +103,7 @@ func TestEval(t *testing.T) {
ExpectedError: false,
},
{
Name: "array-of-maps-at-root-and-invalid-index",
Name: "array-of-objects-at-root-and-invalid-index",
Path: "[5].id",
Data: `[{"id": 1}, {"id": 2}]`,
ExpectedOutput: "",
@ -119,7 +127,7 @@ func TestEval(t *testing.T) {
ExpectedError: false,
},
{
Name: "map-of-nested-arrays",
Name: "object-with-nested-arrays",
Path: "data[1][1]",
Data: `{"data": [["a", "b", "c"], ["d", "eeeee", "f"]]}`,
ExpectedOutput: "eeeee",
@ -127,7 +135,7 @@ func TestEval(t *testing.T) {
ExpectedError: false,
},
{
Name: "map-of-arrays-of-maps",
Name: "object-with-arrays-of-objects",
Path: "data[0].apps[1].name",
Data: `{"data": [{"apps": [{"name":"app1"}, {"name":"app2"}, {"name":"app3"}]}]}`,
ExpectedOutput: "app2",
@ -135,7 +143,7 @@ func TestEval(t *testing.T) {
ExpectedError: false,
},
{
Name: "map-of-arrays-of-maps-with-missing-element",
Name: "object-with-arrays-of-objects-with-missing-element",
Path: "data[0].apps[1].name",
Data: `{"data": [{"apps": []}]}`,
ExpectedOutput: "",