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"
This commit is contained in:
tidwall 2021-05-14 08:53:58 -07:00
parent 51e0e24a13
commit d7dbdd1d92
2 changed files with 31 additions and 0 deletions

View File

@ -1174,6 +1174,15 @@ func parseObject(c *parseContext, i int, path string) (int, bool) {
} }
func queryMatches(rp *arrayPathResult, value Result) bool { func queryMatches(rp *arrayPathResult, value Result) bool {
rpv := rp.query.value 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() { if !value.Exists() {
return false return false
} }

View File

@ -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=="Mur\nphy").age`).Int() == 44)
assert(t, Get(json, `friends.#(last=="Murphy").age`).Int() == 47) 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]")
}