Feature: JSON.FILTER by devBaunz · Pull Request #1465 · RedisJSON/RedisJSON

thank you for the contribution.

there's a small typo in https://github.com/RedisJSON/RedisJSON/pull/1465/files#diff-fe8692f5492557c8fe9633a9784c4369d58ae070dd14d9e63696f57256a4efe9R1047 (missing a :).

can you please add tests verifying correctness of both the happy path as well as any error paths. eg something like

def testFilterCommandErrors(env):
    env.expect('JSON.FILTER', '{doc}:1', '$').raiseError()
    env.expect('JSON.FILTER', '{doc}:1', '$', '$[?(@.a>0)]').raiseError()
    env.cmd('JSON.SET', '{doc}:1', '$', '{"a":1}')
    env.expect('JSON.FILTER', '{doc}:1', '$', '$[?(@.a>').raiseError()
    env.expect('JSON.FILTER', '{doc}:1', '$..[', '$[?(@.a>0)]').raiseError()
def testFilterCommandBasic(env):
    env.cmd('JSON.SET', '{doc}:1', '$', '{"name":"Alice","age":30,"city":"NYC","active":true}')
    env.cmd('JSON.SET', '{doc}:2', '$', '{"name":"Bob","age":25,"city":"LA","active":false}')
    env.cmd('JSON.SET', '{doc}:3', '$', '{"name":"Charlie","age":35,"city":"NYC","active":true}')
    env.cmd('JSON.SET', '{doc}:4', '$', '{"name":"Diana","age":28,"city":"SF","active":true}')

    res = env.cmd('JSON.FILTER', '{doc}:1', '{doc}:2', '{doc}:3', '{doc}:4', '$', '$[?(@.active==true)]')
    env.assertEqual(len(res), 4)
    env.assertNotEqual(res[0], None)
    env.assertEqual(res[1], None)
    env.assertNotEqual(res[2], None)
    env.assertNotEqual(res[3], None)

    res = env.cmd('JSON.FILTER', '{doc}:1', '{doc}:2', '{doc}:3', '{doc}:4', '$.name', '$[?(@.age>28)]')
    env.assertEqual(len(res), 4)
    env.assertEqual(json.loads(res[0]), ["Alice"])
    env.assertEqual(res[1], None)
    env.assertEqual(json.loads(res[2]), ["Charlie"])
    env.assertEqual(res[3], None)

    res = env.cmd('JSON.FILTER', '{doc}:1', '{doc}:2', '{doc}:3', '{doc}:4', '$', '$[?(@.city=="NYC")]')
    env.assertEqual(len(res), 4)
    env.assertNotEqual(res[0], None)
    env.assertEqual(res[1], None)
    env.assertNotEqual(res[2], None)
    env.assertEqual(res[3], None)

    res = env.cmd('JSON.FILTER', '{doc}:1', '{doc}:missing', '{doc}:3', '$', '$[?(@.active==true)]')
    env.assertEqual(len(res), 3)
    env.assertNotEqual(res[0], None)
    env.assertEqual(res[1], None)
    env.assertNotEqual(res[2], None)

    env.cmd('SET', '{doc}:wrong_type', 'not a json')
    res = env.cmd('JSON.FILTER', '{doc}:1', '{doc}:wrong_type', '{doc}:3', '$', '$[?(@.active==true)]')
    env.assertEqual(len(res), 3)
    env.assertNotEqual(res[0], None)
    env.assertEqual(res[1], None)
    env.assertNotEqual(res[2], None)

    env.cmd('JSON.SET', '{doc}:nested1', '$', '{"user":{"name":"Eve","score":85},"status":"active"}')
    env.cmd('JSON.SET', '{doc}:nested2', '$', '{"user":{"name":"Frank","score":92},"status":"inactive"}')
    env.cmd('JSON.SET', '{doc}:nested3', '$', '{"user":{"name":"Grace","score":78},"status":"active"}')

    res = env.cmd('JSON.FILTER', '{doc}:nested1', '{doc}:nested2', '{doc}:nested3', '$.user.name', '$[?(@.user.score>80)]')
    env.assertEqual(len(res), 3)
    env.assertEqual(json.loads(res[0]), ["Eve"])
    env.assertEqual(json.loads(res[1]), ["Frank"])
    env.assertEqual(res[2], None)

    env.cmd('JSON.SET', '{doc}:arr1', '$', '{"items":[1,2,3],"count":3}')
    env.cmd('JSON.SET', '{doc}:arr2', '$', '{"items":[4,5],"count":2}')
    env.cmd('JSON.SET', '{doc}:arr3', '$', '{"items":[6,7,8,9],"count":4}')

    res = env.cmd('JSON.FILTER', '{doc}:arr1', '{doc}:arr2', '{doc}:arr3', '$.count', '$[?(@.count>2)]')
    env.assertEqual(len(res), 3)
    env.assertEqual(json.loads(res[0]), [3])
    env.assertEqual(res[1], None)
    env.assertEqual(json.loads(res[2]), [4])

    res = env.cmd('JSON.FILTER', '{doc}:1', '{doc}:2', '{doc}:3', '.name', '.[?(@.age>28)]')
    env.assertEqual(len(res), 3)
    env.assertEqual(json.loads(res[0]), "Alice")
    env.assertEqual(res[1], None)
    env.assertEqual(json.loads(res[2]), "Charlie")

    res = env.cmd('JSON.FILTER', '{doc}:1', '{doc}:2', '{doc}:3', '$', '$[?(@.age>100)]')
    env.assertEqual(len(res), 3)
    env.assertEqual(res[0], None)
    env.assertEqual(res[1], None)
    env.assertEqual(res[2], None)

    env.cmd('JSON.SET', '{doc}:multi1', '$', '{"a":1,"nested":{"a":2,"b":3}}')
    env.cmd('JSON.SET', '{doc}:multi2', '$', '{"a":4,"nested":{"a":5,"b":6}}')

    res = env.cmd('JSON.FILTER', '{doc}:multi1', '{doc}:multi2', '$..a', '$[?(@.a>0)]')
    env.assertEqual(len(res), 2)
    env.assertEqual(json.loads(res[0]), [1, 2])
    env.assertEqual(json.loads(res[1]), [4, 5])
def testFilterCommandComplex(env):
    env.cmd('JSON.SET', '{doc}:store1', '$', '{"store":{"book":[{"category":"reference","price":8.95},{"category":"fiction","price":12.99}]}}')
    env.cmd('JSON.SET', '{doc}:store2', '$', '{"store":{"book":[{"category":"fiction","price":8.99},{"category":"fiction","price":22.99}]}}')
    env.cmd('JSON.SET', '{doc}:store3', '$', '{"store":{"book":[{"category":"reference","price":15.00}]}}')

    res = env.cmd('JSON.FILTER', '{doc}:store1', '{doc}:store2', '{doc}:store3', '$.store.book[*].price', '$.store.book[?(@.category=="fiction")]')
    env.assertEqual(len(res), 3)
    env.assertNotEqual(res[0], None)
    env.assertNotEqual(res[1], None)
    env.assertEqual(res[2], None)

    env.cmd('JSON.SET', '{doc}:deep1', '$', '{"level1":{"level2":{"value":10}}}')
    env.cmd('JSON.SET', '{doc}:deep2', '$', '{"level1":{"level2":{"value":5}}}')

    res = env.cmd('JSON.FILTER', '{doc}:deep1', '{doc}:deep2', '$..value', '$..level2[?(@.value>7)]')
    env.assertEqual(len(res), 2)
    env.assertEqual(json.loads(res[0]), [10])
    env.assertEqual(res[1], None)