From d7dbdd1d92aa9cdddd006b1655e415fa52f5cfba Mon Sep 17 00:00:00 2001 From: tidwall Date: Fri, 14 May 2021 08:53:58 -0700 Subject: [PATCH] Add tilde boolean operator This commit adds the new tilde '~' operator, which when used will convert a value to a boolean before comparison. For example, using the following JSON: { "vals": [ { "a": 1, "b": true }, { "a": 2, "b": true }, { "a": 3, "b": false }, { "a": 4, "b": "0" }, { "a": 5, "b": 0 }, { "a": 6, "b": "1" }, { "a": 7, "b": 1 } { "a": 8, "b": "true" }, { "a": 9, "b": false } { "a": 10, "b": null } { "a": 11 } ] } You can now query for all true(ish) values: vals.#(b==~true)# Which returns: [1,2,6,7,8] Or all false(ish) values: vals.#(b==~false)# Which returns: [3,4,5,9,10,11] The last value which was non-existent is treated as "false" --- gjson.go | 9 +++++++++ gjson_test.go | 22 ++++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/gjson.go b/gjson.go index a48b687..9687c0b 100644 --- a/gjson.go +++ b/gjson.go @@ -1174,6 +1174,15 @@ func parseObject(c *parseContext, i int, path string) (int, bool) { } func queryMatches(rp *arrayPathResult, value Result) bool { rpv := rp.query.value + if len(rpv) > 0 && rpv[0] == '~' { + // convert to bool + rpv = rpv[1:] + if value.Bool() { + value = Result{Type: True} + } else { + value = Result{Type: False} + } + } if !value.Exists() { return false } diff --git a/gjson_test.go b/gjson_test.go index 90173e6..04d94b0 100644 --- a/gjson_test.go +++ b/gjson_test.go @@ -2064,3 +2064,25 @@ func TestEncodedQueryString(t *testing.T) { assert(t, Get(json, `friends.#(last=="Mur\nphy").age`).Int() == 44) assert(t, Get(json, `friends.#(last=="Murphy").age`).Int() == 47) } + +func TestBoolConvertQuery(t *testing.T) { + json := `{ + "vals": [ + { "a": 1, "b": true }, + { "a": 2, "b": true }, + { "a": 3, "b": false }, + { "a": 4, "b": "0" }, + { "a": 5, "b": 0 }, + { "a": 6, "b": "1" }, + { "a": 7, "b": 1 } + { "a": 8, "b": "true" }, + { "a": 9, "b": false } + { "a": 10, "b": null } + { "a": 11 } + ] + }` + trues := Get(json, `vals.#(b==~true)#.a`).Raw + falses := Get(json, `vals.#(b==~false)#.a`).Raw + assert(t, trues == "[1,2,6,7,8]") + assert(t, falses == "[3,4,5,9,10,11]") +}