diff --git a/.github/workflows/release-build.yaml b/.github/workflows/release-build.yaml index dc20889..013e9c2 100644 --- a/.github/workflows/release-build.yaml +++ b/.github/workflows/release-build.yaml @@ -10,7 +10,7 @@ jobs: matrix: goos: [linux, windows, darwin] goarch: ["386", amd64, arm64] - goversion: ["1.16", "1.17"] + goversion: ["1.17"] exclude: - goarch: "386" goos: darwin diff --git a/jsonpath.go b/jsonpath.go index d68fa61..448749e 100644 --- a/jsonpath.go +++ b/jsonpath.go @@ -3,6 +3,7 @@ package jsonpath import ( "encoding/json" "fmt" + "strconv" "strings" "github.com/evilmonkeyinc/jsonpath/token" @@ -95,19 +96,42 @@ func (query *JSONPath) Query(root interface{}) (interface{}, error) { // QueryString will return the result of the JSONPath query applied against the specified JSON data. func (query *JSONPath) QueryString(jsonData string) (interface{}, error) { jsonData = strings.TrimSpace(jsonData) + if jsonData == "" { + return nil, getInvalidJSONData(errDataIsUnexpectedTypeOrNil) + } var root interface{} + if strings.HasPrefix(jsonData, "{") && strings.HasSuffix(jsonData, "}") { + // object root = make(map[string]interface{}) + if err := json.Unmarshal([]byte(jsonData), &root); err != nil { + return nil, getInvalidJSONData(err) + } } else if strings.HasPrefix(jsonData, "[") && strings.HasSuffix(jsonData, "]") { + // array root = make([]interface{}, 0) + if err := json.Unmarshal([]byte(jsonData), &root); err != nil { + return nil, getInvalidJSONData(err) + } + } else if len(jsonData) > 2 && strings.HasPrefix(jsonData, "\"") && strings.HasPrefix(jsonData, "\"") { + // string + root = jsonData[1 : len(jsonData)-1] + } else if strings.ToLower(jsonData) == "true" { + // bool true + root = true + } else if strings.ToLower(jsonData) == "false" { + // bool false + root = false + } else if val, err := strconv.ParseInt(jsonData, 10, 64); err == nil { + // integer + root = val + } else if val, err := strconv.ParseFloat(jsonData, 64); err == nil { + // float + root = val } else { return nil, getInvalidJSONData(errDataIsUnexpectedTypeOrNil) } - if err := json.Unmarshal([]byte(jsonData), &root); err != nil { - return nil, getInvalidJSONData(err) - } - return query.Query(root) } diff --git a/jsonpath_test.go b/jsonpath_test.go index 552fd84..6ba8410 100644 --- a/jsonpath_test.go +++ b/jsonpath_test.go @@ -900,6 +900,7 @@ func Test_JSONPath_QueryString(t *testing.T) { sampleQuery, _ := Compile("$.expensive") altSampleQuery, _ := Compile("$..author") lengthQuery, _ := Compile("$.length") + rootQuery, _ := Compile("$") type input struct { jsonPath *JSONPath @@ -923,6 +924,60 @@ func Test_JSONPath_QueryString(t *testing.T) { err: "invalid data. unexpected type or nil", }, }, + { + input: input{ + jsonPath: rootQuery, + jsonData: "42", + }, + expected: expected{ + value: int64(42), + }, + }, + { + input: input{ + jsonPath: rootQuery, + jsonData: "3.14", + }, + expected: expected{ + value: float64(3.14), + }, + }, + { + input: input{ + jsonPath: rootQuery, + jsonData: "true", + }, + expected: expected{ + value: true, + }, + }, + { + input: input{ + jsonPath: rootQuery, + jsonData: "false", + }, + expected: expected{ + value: false, + }, + }, + { + input: input{ + jsonPath: rootQuery, + jsonData: "not a json string", + }, + expected: expected{ + err: "invalid data. unexpected type or nil", + }, + }, + { + input: input{ + jsonPath: rootQuery, + jsonData: `"json string"`, + }, + expected: expected{ + value: "json string", + }, + }, { input: input{ jsonPath: &JSONPath{ diff --git a/test/README.md b/test/README.md index 415daf8..7bd7d40 100644 --- a/test/README.md +++ b/test/README.md @@ -154,7 +154,7 @@ This implementation would be closer to the `Scalar consensus` as it does not alw |`$.*.*`|`[[1, 2, 3], [4, 5, 6]]`|`[1 2 3 4 5 6]`|`[[1 2 3] [4 5 6]]`|:no_entry:| |`$..*`|`{ "key": "value", "another key": { "complex": "string", "primitives": [0, 1] } }`|`[string value 0 1 [0 1] map[complex:string primitives:[0 1]]]`|`[string value 0 1 [0 1] map[complex:string primitives:[0 1]]]`|:white_check_mark:| |`$..*`|`[ 40, null, 42 ]`|`[40 42 ]`|`[40 42 ]`|:white_check_mark:| -|`$..*`|`42`|`nil`|`nil`|:white_check_mark:| +|`$..*`|`42`|`[]`|`[]`|:white_check_mark:| |`$a`|`{"a": 1, "$a": 2}`|`nil`|`nil`|:white_check_mark:| |`.key`|`{ "key": "value" }`|`nil`|`nil`|:white_check_mark:| |`key`|`{ "key": "value" }`|`nil`|`nil`|:white_check_mark:| @@ -256,9 +256,9 @@ This implementation would be closer to the `Scalar consensus` as it does not alw |`$..`|`[{"a": {"b": "c"}}, [0, 1]]`|none|`[[map[a:map[b:c]] [0 1]] map[a:map[b:c]] map[b:c] c [0 1] 0 1]`|:question:| |`$.key..`|`{"some key": "value", "key": {"complex": "string", "primitives": [0, 1]}}`|none|`[map[complex:string primitives:[0 1]] [0 1] 0 1 string]`|:question:| |`$`|`{ "key": "value", "another key": { "complex": [ "a", 1 ] } }`|`map[another key:map[complex:[a 1]] key:value]`|`map[another key:map[complex:[a 1]] key:value]`|:white_check_mark:| -|`$`|`42`|`42`|`nil`|:no_entry:| -|`$`|`false`|`false`|`nil`|:no_entry:| -|`$`|`true`|`false`|`nil`|:no_entry:| +|`$`|`42`|`42`|`42`|:white_check_mark:| +|`$`|`false`|`false`|`false`|:white_check_mark:| +|`$`|`true`|`true`|`true`|:white_check_mark:| |`$[(@.length-1)]`|`["first", "second", "third", "forth", "fifth"]`|`nil`|`fifth`|:no_entry:| diff --git a/test/dot_test.go b/test/dot_test.go index 4f7bbd2..f4f7c17 100644 --- a/test/dot_test.go +++ b/test/dot_test.go @@ -342,9 +342,9 @@ func Test_Dot(t *testing.T) { { query: `$..*`, data: `42`, - expected: nil, - consensus: nil, - expectedError: "invalid data. unexpected type or nil", + expected: []interface{}{}, + consensus: []interface{}{}, + expectedError: "", }, { query: `$a`, diff --git a/test/misc_test.go b/test/misc_test.go index b9620e8..118e841 100644 --- a/test/misc_test.go +++ b/test/misc_test.go @@ -48,25 +48,25 @@ func Test_Misc(t *testing.T) { expectedError: "", }, { - query: `$`, // TODO : should we support more than [] and {} + query: `$`, data: `42`, - expected: nil, - consensus: float64(42), - expectedError: "invalid data. unexpected type or nil", + expected: int64(42), + consensus: int64(42), + expectedError: "", }, { - query: `$`, // TODO : should we support more than [] and {} + query: `$`, data: `false`, - expected: nil, + expected: false, consensus: false, - expectedError: "invalid data. unexpected type or nil", + expectedError: "", }, { - query: `$`, // TODO : should we support more than [] and {} + query: `$`, data: `true`, - expected: nil, - consensus: false, - expectedError: "invalid data. unexpected type or nil", + expected: true, + consensus: true, + expectedError: "", }, { query: `$[(@.length-1)]`,