summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChayim I. Kirshen <c@kirshen.com>2021-10-31 15:46:32 +0200
committerChayim I. Kirshen <c@kirshen.com>2021-10-31 15:46:32 +0200
commitade01832cdc9fb711023a60849181981f2b4ee81 (patch)
tree40a8f85d26b2c935a02e2f51245d26a0adff0b53
parentb8948d4a3049d393ad1c07bfb6054486e94ae2b9 (diff)
downloadredis-py-ade01832cdc9fb711023a60849181981f2b4ee81.tar.gz
json test conversion continues
-rw-r--r--tests/test_json.py511
-rw-r--r--tests/testdata/jsontestdata.py617
2 files changed, 1125 insertions, 3 deletions
diff --git a/tests/test_json.py b/tests/test_json.py
index fb36fc0..3c89ae3 100644
--- a/tests/test_json.py
+++ b/tests/test_json.py
@@ -1,7 +1,9 @@
import pytest
import redis
from redis.commands.json.path import Path
+from redis import exceptions
from .conftest import skip_ifmodversion_lt
+from .testdata.jsontestdata import nested_large_key
@pytest.fixture
@@ -234,8 +236,11 @@ def test_objlenshouldsucceed(client):
# assert client.keys() == []
# assert client.get("foo") is None
+
+######### DUAL
+
@pytest.mark.redismod
-def test_jsondollardelete(client):
+def test_json_delete_with_dollar(client):
doc1 = {"a": 1, "nested": {"a": 2, "b": 3}}
assert client.json().set("doc1", "$", doc1)
assert client.json().delete("doc1", "$..a") == 2
@@ -270,7 +275,7 @@ def test_jsondollardelete(client):
client.json().delete("not_a_document", "..a")
@pytest.mark.redismod
-def test_jsondollarforget(client):
+def test_json_forget_with_dollar(client):
doc1 = {"a": 1, "nested": {"a": 2, "b": 3}}
assert client.json().set("doc1", "$", doc1)
assert client.json().forget("doc1", "$..a") == 2
@@ -302,4 +307,504 @@ def test_jsondollarforget(client):
assert client.json().forget("doc3") == 1
assert client.json().get("doc3", "$") is None
- client.json().forget("not_a_document", "..a") \ No newline at end of file
+ client.json().forget("not_a_document", "..a")
+
+@pytest.mark.redismod
+def test_set_and_get_with_dollar(client):
+ # Test set and get on large nested key
+ assert client.json().set("doc1", "$", nested_large_key, "XX") is None
+ assert client.json().set("doc1", "$", nested_large_key, "NX")
+ assert client.json().get('doc1', '$') == [nested_large_key]
+ assert client.json().set("doc1", "$", nested_large_key, "NX") is None
+
+ # Test single path
+ assert client.json().get('doc1', '$..tm') == [[46,876.85],[134.761,"jcoels",None]]
+
+ # Test multi get and set
+ assert client.json().get('doc1', '$..foobar') == [3.141592,1.61803398875]
+
+ # Set multi existing values
+ client.json().set('doc1', '$..foobar', '"new_val"')
+ assert client.json().get('doc1', '$..foobar') == ["new_val","new_val"]
+
+ # Test multi set and get on small nested key
+ nested_simple_key = {"a":1,"nested":{"a":2,"b":3}}
+ client.json().set('doc2', '$', nested_simple_key)
+ assert client.json().get('doc2', '$') == [nested_simple_key]
+ # Set multi existing values
+ client.json().set('doc2', '$..a', '4.2')
+ assert client.json().get('doc2', '$') == \
+ [{"a":4.2,"nested":{"a":4.2,"b":3}}]
+
+
+ # Test multi paths
+ assert client.json().get('doc1', '$..tm', '$..nu') == \
+ [[[46,876.85],[134.761,"jcoels",None]],[[377,"qda",True]]]
+ # Test multi paths - if one path is none-legacy - result format is not legacy
+ assert client.json().get('doc1', '..tm', '$..nu') == \
+ [[[46,876.85],[134.761,"jcoels",None]],[[377,"qda",True]]]
+
+ # Test missing key
+ assert client.json().get('docX', '..tm', '$..nu') is None
+ # Test missing path
+ assert client.json().get('doc1', '..tm', '$..back_in_nov') == \
+ [[[46,876.85],[134.761,"jcoels",None]],[]]
+ assert client.json().get('doc2', '..a', '..b', '$.back_in_nov') == \
+ [[4.2,4.2],[3],[]]
+
+ # Test legacy multi path (all paths are legacy)
+ client.json().get('doc1', '..nu', '..tm') == \
+ {"..nu":[377,"qda",True],"..tm":[46,876.85]}
+ # Test legacy single path
+ client.json().get('doc1', '..tm') == '[46,876.85]'
+
+ # Test missing legacy path (should return an error for a missing path)
+ client.json().set('doc2', '$.nested.b', None)
+
+ with pytest.raises(exceptions.DataError):
+ client.json.get('doc2', '.a', '.nested.b', '.back_in_nov', '.ttyl')
+ client.json.get('JSON.GET', 'doc2', '.back_in_nov')
+
+@pytest.mark.redismod
+def test_json_mget_dollar(client):
+ # Test mget with multi paths
+ client.json().set('doc1', '$', {"a":1, "b": 2, "nested": {"a": 3}, "c": None, "nested2": {"a": None}})
+ client.json().set('doc2', '$', {"a":4, "b": 5, "nested": {"a": 6}, "c": None, "nested2": {"a": [None]}})
+ # Compare also to single JSON.GET
+ assert client.json().get('doc1', '$..a') == [1,3,None]
+ assert client.json().get('doc2', '$..a') == [4,6,[None]]
+
+ # Test mget with single path
+ client.json().mget('doc1', '$..a') == [1,3,None]
+ # Test mget with multi path
+ client.json().mget('doc1', 'doc2', '$..a') == [[1,3,None], [4,6,[None]]]
+
+ # Test missing key
+ client.json().mget('doc1', 'missing_doc', '$..a') == [[1,3,None], None]
+ res = client.json().mget('missing_doc1', 'missing_doc2', '$..a')
+ assert res == [None, None]
+
+@pytest.mark.redismod
+def test_numby_commands_dollar(env):
+
+ r = env
+
+ # Test NUMINCRBY
+ client.json().set('doc1', '$', {"a":"b","b":[{"a":2}, {"a":5.0}, {"a":"c"}]})
+ # Test multi
+ assert client.json().numincrby('doc1', '$..a', '2') == [None, 4, 7.0, None]
+
+ assert client.json().numincrby('doc1', '$..a', '2.5') == [None, 6.5, 9.5, None]
+ # Test single
+ assert client.json().numincrby('doc1', '$.b[1].a', '2') == [11.5]
+
+ assert client.json().numincrby('doc1', '$.b[2].a', '2') == [None]
+ assert client.json().numincrby('doc1', '$.b[1].a', '3.5') == [15.0]
+
+ # Test NUMMULTBY
+ client.json().set('doc1', '$', {"a":"b","b":[{"a":2}, {"a":5.0}, {"a":"c"}]})
+
+ assert client.json().nummultby('doc1', '$..a', '2') == [None, 4, 10, None]
+ assert client.json().nummultby('doc1', '$..a', '2.5') == [None,10.0,25.0,None]
+ # Test single
+ assert client.json().nummultby('doc1', '$.b[1].a', '2') == [50.0]
+ assert client.json().nummultby('doc1', '$.b[2].a', '2') == [None]
+ assert client.json().nummultby('doc1', '$.b[1].a', '3') == [150.0]
+
+ # Test NUMPOWBY
+ client.json().set('doc1', '$', {"a":"b","b":[{"a":2}, {"a":5.0}, {"a":"c"}]})
+ # Test multi
+ assert client.json().numpowby('doc1', '$..a', '2') == [None, 4, 25, None]
+ # Avoid json.loads to verify the underlying type (integer/float)
+ assert client.json().numpowby('doc1', '$..a', '2') == [None,16,625.0,None]
+
+ # Test single
+ assert client.json().numpowby('JSON.NUMPOWBY', 'doc1', '$.b[1].a', '2') == [390625.0]
+ assert client.json().numpowby('JSON.NUMPOWBY', 'doc1', '$.b[2].a', '2') == [None]
+ assert client.json().numpowby('JSON.NUMPOWBY', 'doc1', '$.b[1].a', '3') == [5.960464477539062e16]
+
+ # Test missing key
+ with pytest.raises(exceptions.DataError):
+ client.json().numincrby('non_existing_doc', '$..a', '2')
+ client.json().nummultby('non_existing_doc', '$..a', '2')
+
+ # TODO fixme
+ r.expect('JSON.NUMPOWBY', 'non_existing_doc', '$..a', '2')
+
+ # Test legacy NUMINCRBY
+ client.json().set('doc1', '$', {"a":"b","b":[{"a":2}, {"a":5.0}, {"a":"c"}]})
+ client.json().numincrby('doc1', '.b[0].a', '3') == 5
+
+ # Test legacy NUMMULTBY
+ client.json().set('doc1', '$', {"a":"b","b":[{"a":2}, {"a":5.0}, {"a":"c"}]})
+ client.json().nummultby('doc1', '.b[0].a', '3') == 6
+
+@pytest.mark.redismod
+def test_strappend_dollar(client):
+
+ client.json().set('doc1', '$', {"a":"foo", "nested1": {"a": "hello"}, "nested2": {"a": 31}})
+ # Test multi
+ client.json().strappend('doc1', '$..a', '"bar"') == [6, 8, None]
+
+
+ client.json().get('doc1', '$') == [{"a":"foobar","nested1":{"a":"hellobar"},"nested2":{"a":31}}]
+ # Test single
+ client.json().strappend('doc1', '$.nested1.a', '"baz"') == [11]
+
+ client.json().get('doc1', '$') == [{"a":"foobar","nested1":{"a":"hellobarbaz"},"nested2":{"a":31}}]
+
+ # Test missing key
+ with pytest.raises(exceptions.DataError):
+ client.json().strappend('non_existing_doc', '$..a', '"err"')
+
+ # Test multi
+ client.json().strappend('doc1', '.*.a', '"bar"') == 8
+ client.json.get('doc1', '$') == [{"a":"foo","nested1":{"a":"hellobar"},"nested2":{"a":31}}]
+
+ # Test missing path
+ with pytest.raises(exceptions.DataError):
+ client.json().strappend('doc1', '"piu"')
+
+@pytest.mark.redismod
+def test_strlen_dollar(client):
+
+ # Test multi
+ client.json().set('doc1', '$', {"a":"foo", "nested1": {"a": "hello"}, "nested2": {"a": 31}})
+ res1 = client.json().strlen('doc1', '$..a') [3, 5, None]
+
+ res2 = client.json().strappend('doc1', '$..a', '"bar"') == [6, 8, None]
+ res1 = client.json().strlen('doc1', '$..a')
+ assert res1 == res2
+
+ # Test single
+ client.json().strlen('doc1', '$.nested1.a') == [8]
+ client.json().strlen('doc1', '$.nested2.a') == [None]
+
+ # Test missing key
+ with pytest.raises(exceptions.DataError):
+ client.json().strlen('non_existing_doc', '$..a')
+
+@pytest.mark.redismod
+def test_arrappend_dollar(client):
+ client.json().set('doc1', '$', {"a":["foo"], "nested1": {"a": ["hello", None, "world"]}, "nested2": {"a": 31}})
+ # Test multi
+ client.json().arrappend('doc1', '$..a', '"bar"', '"racuda"') == [3, 5, None]
+ assert client.json().get('doc1', '$') == \
+ [{"a": ["foo", "bar", "racuda"], "nested1": {"a": ["hello", None, "world", "bar", "racuda"]}, "nested2": {"a": 31}}]
+
+ # Test single
+ assert client.json().arrappend('doc1', '$.nested1.a', '"baz"') == [6]
+ assert client.json().get('doc1', '$') == \
+ [{"a": ["foo", "bar", "racuda"], "nested1": {"a": ["hello", None, "world", "bar", "racuda", "baz"]}, "nested2": {"a": 31}}]
+
+ # Test missing key
+ with pytest.raises(exceptions.DataError):
+ client.json.arrappend('non_existing_doc', '$..a')
+
+ # Test legacy
+ client.json().set('doc1', '$', {"a":["foo"], "nested1": {"a": ["hello", None, "world"]}, "nested2": {"a": 31}})
+ # Test multi (all paths are updated, but return result of last path)
+ assert client.json().arrappend('doc1', '..a', '"bar"', '"racuda"') == 5
+
+ assert client.json.get('doc1', '$') == \
+ [{"a": ["foo", "bar", "racuda"], "nested1": {"a": ["hello", None, "world", "bar", "racuda"]}, "nested2": {"a": 31}}]
+ # Test single
+ assert client.json().arrappend('doc1', '.nested1.a', '"baz"') == 6
+ assert client.json().get('doc1', '$') == \
+ [{"a": ["foo", "bar", "racuda"], "nested1": {"a": ["hello", None, "world", "bar", "racuda", "baz"]}, "nested2": {"a": 31}}]
+
+ # Test missing key
+ with pytest.raises(exceptions.DataError):
+ client.json.arrappend('non_existing_doc', '$..a')
+
+@pytest.mark.redismod
+def test_arrinsert_dollar(client):
+ client.json().set('doc1', '$', {"a":["foo"], "nested1": {"a": ["hello", None, "world"]}, "nested2": {"a": 31}})
+ # Test multi
+ assert client.json().arrinsert('doc1', '$..a', '1', '"bar"', '"racuda"') == [3, 5, None]
+
+ assert client.json().get('doc1', '$') == \
+ [{"a": ["foo", "bar", "racuda"], "nested1": {"a": ["hello", "bar", "racuda", None, "world"]}, "nested2": {"a": 31}}]
+ # Test single
+ assert client.json().arrinsert('doc1', '$.nested1.a', -2, '"baz"') == [6]
+ assert client.json().get('doc1', '$') == \
+ [{"a": ["foo", "bar", "racuda"], "nested1": {"a": ["hello", "bar", "racuda", "baz", None, "world"]}, "nested2": {"a": 31}}]
+
+ # Test missing key
+ with pytest.raises(exceptions.DataError):
+ client.json.arrappend('non_existing_doc', '$..a')
+
+ # Test legacy
+ client.json().set('doc1', '$', {"a":["foo"], "nested1": {"a": ["hello", None, "world"]}, "nested2": {"a": 31}})
+ assert client.json().arrappend('doc1', '..a', '1', '"bar"', '"racuda"') == 5
+
+ assert client.json().get('doc1', '$') == \
+ [{"a": ["foo", "bar", "racuda"], "nested1": {"a": ["hello", "bar", "racuda", None, "world"]}, "nested2": {"a": 31}}]
+ # Test single
+ assert client.json().arrinsert('doc1', '.nested1.a', -2, '"baz"') == 6
+ assert client.json().get('doc1', '$') == \
+ [{"a": ["foo", "bar", "racuda"], "nested1": {"a": ["hello", "bar", "racuda", "baz", None, "world"]}, "nested2": {"a": 31}}]
+
+ # Test missing key
+ with pytest.raises(exceptions.DataError):
+ client.json.arrinsert('non_existing_doc', '$..a')
+
+@pytest.mark.redismod
+def test_arrlen_dollar(client):
+
+ client.json().set('doc1', '$', {"a":["foo"], "nested1": {"a": ["hello", None, "world"]}, "nested2": {"a": 31}})
+
+ # Test multi
+ assert client.json().arrlen('doc1', '$..a') == [1, 3, None]
+ assert client.json().arrappend('doc1', '$..a', '"non"', '"abba"', '"stanza"') == \
+ [4, 6, None]
+
+ client.json().clear('doc1', '$.a')
+ assert client.json.arrlen('doc1', '$..a') == [0, 6, None]
+ # Test single
+ assert client.json().arrlen('doc1', '$.nested1.a') == [6]
+
+ # Test missing key
+ with pytest.raises(exceptions.DataError):
+ client.json.arrappend('non_existing_doc', '$..a')
+
+ # Test legacy
+ client.json().set('doc1', '$', {"a":["foo"], "nested1": {"a": ["hello", None, "world"]}, "nested2": {"a": 31}})
+ # Test multi (return result of last path)
+ assert client.json().arrlen('doc1', '$..a') == [1, 3, None]
+ assert client.json().arrappend('doc1', '..a', '"non"', '"abba"', '"stanza"') == 6
+
+ # Test single
+ assert client.json().arrlen('doc1', '.nested1.a') = 6
+
+ # Test missing key
+ assert client.json().arrlen('non_existing_doc', '..a') is None
+
+@pytest.mark.redismod
+def test_arrpop_dollar(client):
+ client.json().set('doc1', '$', {"a":["foo"], "nested1": {"a": ["hello", None, "world"]}, "nested2": {"a": 31}})
+ # Test multi
+ assert client.json().arrpop('doc1', '$..a', '1') == ['"foo"', 'null', None]
+
+ assert client.json().get('doc1', '$') == \
+ [{"a": [], "nested1": {"a": ["hello", "world"]}, "nested2": {"a": 31}}]
+
+ assert client.json().arrpop('doc1', '$..a', '-1') == [None, '"world"', None]
+ assert client.json().get('doc1', '$') == \
+ [{"a": [], "nested1": {"a": ["hello"]}, "nested2": {"a": 31}}]
+
+ # Test single
+ assert client.json().arrpop('doc1', '$.nested1.a', -2) == ['"hello"']
+ assert client.json().get('doc1', '$') == \
+ [{"a": [], "nested1": {"a": []}, "nested2": {"a": 31}}]
+
+ # Test missing key
+ with pytest.raises(exceptions.DataError):
+ client.json().arrpop('non_existing_doc', '..a')
+
+ # Test legacy
+ client.json().set('doc1', '$', {"a":["foo"], "nested1": {"a": ["hello", None, "world"]}, "nested2": {"a": 31}})
+ # Test multi (all paths are updated, but return result of last path)
+ client.json().arrpop('doc1', '..a', '1') is None
+ assert client.json().get('doc1', '$') == \
+ [{"a": [], "nested1": {"a": ["hello", "world"]}, "nested2": {"a": 31}}]
+
+ # Test single
+ assert client.json().arrpop('doc1', '.nested1.a', -2, '"baz"') == '"hello"'
+ assert client.json().get('doc1', '$') == \
+ [{"a": [], "nested1": {"a": ["world"]}, "nested2": {"a": 31}}]
+
+ # Test missing key
+ with pytest.raises(exceptions.DataError):
+ client.json().arrpop('non_existing_doc', '..a')
+
+@pytest.mark.redismod
+def test_arrtrim_dollar(client):
+
+ client.json().set('doc1', '$', {"a":["foo"], "nested1": {"a": ["hello", None, "world"]}, "nested2": {"a": 31}})
+ # Test multi
+ assert client.json().arrtrim('doc1', '$..a', '1', -1) == [0, 2, None]
+ assert client.json().get('doc1', '$') == \
+ [{"a": [], "nested1": {"a": [None, "world"]}, "nested2": {"a": 31}}]
+
+ assert client.json().arrtrim('doc1', '$..a', '1', '1') == [0, 1, None]
+ assert client.json().get('doc1', '$') == \
+ [{"a": [], "nested1": {"a": ["world"]}, "nested2": {"a": 31}}]
+ # Test single
+ assert client.json().arrtrim('doc1', '$.nested1.a', 1, 0) == [0]
+ assert client.json().get('doc1', '$') == \
+ [{"a": [], "nested1": {"a": []}, "nested2": {"a": 31}}]
+
+ # Test missing key
+ with pytest.raises(exceptions.DataError):
+ client.json().arrtrim('non_existing_doc', '..a', '0')
+
+ # Test legacy
+ client.json().set('doc1', '$', {"a":["foo"], "nested1": {"a": ["hello", None, "world"]}, "nested2": {"a": 31}})
+
+ # Test multi (all paths are updated, but return result of last path)
+ assert client.json().arrtrim('doc1', '..a', '1', '-1') == 2
+ res = r.execute_command('JSON.GET', 'doc1', '$') == \
+ [{"a": [], "nested1": {"a": [None, "world"]}, "nested2": {"a": 31}}]
+ # Test single
+ assert client.json().arrtrim('doc1', '.nested1.a', '1', '1') == 1
+ assert client.json().get('doc1', '$') == \
+ [{"a": [], "nested1": {"a": ["world"]}, "nested2": {"a": 31}}]
+
+ # Test missing key
+ with pytest.raises(exceptions.DataError):
+ client.json().arrtrim('non_existing_doc', '..a')
+
+@pytest.mark.redismod
+def test_objkeys_dollar(client):
+ client.json().set('doc1', '$', {"nested1": {"a": {"foo": 10, "bar": 20}}, "a":["foo"], "nested2": {"a": {"baz":50}}})
+
+ # Test multi
+ assert client.json().objkeys('doc1', '$..a') == [["foo", "bar"], None, ["baz"]]
+
+ # Test single
+ assert client.json().object('doc1', '$.nested1.a') == [["foo", "bar"]]
+
+ # Test legacy
+ assert client.json().objkeys('doc1', '.*.a') == ["foo", "bar"]
+ # Test single
+ assert client.json().objkeys('doc1', '.nested2.a') == ["baz"]
+
+ # Test missing key
+ assert client.json().objkeys('non_existing_doc', '..a') is None
+
+ # Test missing key
+ with pytest.raises(exceptions.DataError):
+ client.json().objkeys('doc1', '$.nowhere')
+
+@pytest.mark.redismod
+def test_objlen_dollar(client):
+ client.json().set('doc1', '$', {"nested1": {"a": {"foo": 10, "bar": 20}}, "a":["foo"], "nested2": {"a": {"baz":50}}})
+ # Test multi
+ assert client.json().objlen('doc1', '$..a') == [2, None, 1]
+ # Test single
+ assert client.json().objlen('doc1', '$.nested1.a') == [2]
+
+ # Test missing key
+ assert client.json().objlen('non_existing_doc', '$..a') is None
+
+ # Test missing path
+ with pytest.raises(exceptions.DataError):
+ client.json().objlen('doc1', '$.nowhere')
+
+
+ # Test legacy
+ assert client.json().objlen('doc1', '.*.a') == 2
+
+ # Test single
+ assert client.json().objlen('doc1', '.nested2.a') == 1
+
+ # Test missing key
+ assert client.json.objlen('non_existing_doc', '..a') is None
+
+ # Test missing path
+ with pytest.raises(exceptions.DataError):
+ client.json().objlen('doc1', '.nowhere')
+
+@pytest.mark.redismod
+def load_types_data(nested_key_name):
+ types_data = {
+ 'object': {},
+ 'array': [],
+ 'string': 'str',
+ 'integer': 42,
+ 'number': 1.2,
+ 'boolean': False,
+ 'null': None,
+
+ }
+ jdata = {}
+ types = []
+ for i, (k, v) in zip(range(1, len(types_data) + 1), iter(types_data.items())):
+ jdata["nested" + str(i)] = {nested_key_name: v}
+ types.append(k)
+
+ return jdata, types
+
+@pytest.mark.redismod
+def test_type_dollar(client):
+ jdata, jtypes = load_types_data('a')
+ client.json().set('doc1', '$', jdata)
+ # Test multi
+ assert client.json().type('JSON.TYPE', 'doc1', '$..a') == jtypes
+
+ # Test single
+ assert client.json().type('doc1', '$.nested2.a') == [jtypes[1]]
+
+ # Test legacy
+ assert client.json().type('doc1', '..a') == jtypes[0]
+ # Test missing path (defaults to root)
+ assert client.json().type('doc1') == 'object'
+
+ # Test missing key
+ assert client.json().type('non_existing_doc', '..a') is None
+
+@pytest.mark.redismod
+def test_clear_dollar(client):
+
+ client.json().set('doc1', '$', {"nested1": {"a": {"foo": 10, "bar": 20}}, "a":["foo"], "nested2": {"a": "claro"}, "nested3": {"a": {"baz":50}}})
+ # Test multi
+ assert client.json().clear('doc1', '$..a') == 3
+
+ assert client.json().get('doc1', '$') == \
+ [{"nested1": {"a": {}}, "a": [], "nested2": {"a": "claro"}, "nested3": {"a": {}}}]
+
+ # Test single
+ client.json().set('doc1', '$', {"nested1": {"a": {"foo": 10, "bar": 20}}, "a":["foo"], "nested2": {"a": "claro"}, "nested3": {"a": {"baz":50}}})
+ assert client.json().clear('doc1', '$.nested1.a') == 1
+ assert client.json().get('doc1', '$') == \
+ [{"nested1": {"a": {}}, "a": ["foo"], "nested2": {"a": "claro"}, "nested3": {"a": {"baz": 50}}}]
+
+ # Test missing path (defaults to root)
+ assert client.json().clear('doc1') == 1
+ assert client.json().get('doc1', '$') == [{}]
+
+ # Test missing key
+ with pytest.raises(exceptions.DataError):
+ client.json().clear('non_existing_doc', '$..a')
+
+@pytest.mark.redismod
+def test_toggle_dollar(client):
+ client.json().set('doc1', '$', {"a":["foo"], "nested1": {"a": False}, "nested2": {"a": 31}, "nested3": {"a": True}})
+ # Test multi
+ assert client.json().toggle('doc1', '$..a') == [None, 1, None, 0]
+ assert client.json().get('doc1', '$') == \
+ [{"a": ["foo"], "nested1": {"a": True}, "nested2": {"a": 31}, "nested3": {"a": False}}]
+
+ # Test single
+ assert client.json().toggle('doc1', '$.nested1.a') == [0]
+ assert client.json().get('JSON.GET', 'doc1', '$') == \
+ [{"a": ["foo"], "nested1": {"a": False}, "nested2": {"a": 31}, "nested3": {"a": False}}]
+
+ # Test missing key
+ with pytest.raises(exceptions.DataError):
+ client.json().toggle('non_existing_doc', '$..a')
+
+@pytest.mark.redismod
+def test_debug_dollar(client):
+
+ jdata, jtypes = load_types_data('a')
+
+ client.json().set('doc1', '$', jdata)
+
+ # Test multi
+ assert client.json().debug('MEMORY', 'doc1', '$..a') == \
+ [72, 24, 24, 16, 16, 1, 0]
+
+ # Test single
+ assert client.json().debug('MEMORY', 'doc1', '$.nested2.a') == [24]
+
+ # Test legacy
+ assert client.json().debug('MEMORY', 'doc1', '..a') == 72
+
+ # Test missing path (defaults to root)
+ assert client.json().debug('MEMORY', 'doc1') == 72
+
+ # Test missing key
+ with pytest.raises(exceptions.DataError):
+ client.json().debug('non_existing_doc', '$..a') \ No newline at end of file
diff --git a/tests/testdata/jsontestdata.py b/tests/testdata/jsontestdata.py
new file mode 100644
index 0000000..744fe21
--- /dev/null
+++ b/tests/testdata/jsontestdata.py
@@ -0,0 +1,617 @@
+nested_large_key = r"""
+{
+ "jkra": [
+ 154,
+ 4472,
+ [
+ 8567,
+ false,
+ 363.84,
+ 5276,
+ "ha",
+ "rizkzs",
+ 93
+ ],
+ false
+ ],
+ "hh": 20.77,
+ "mr": 973.217,
+ "ihbe": [
+ 68,
+ [
+ true,
+ {
+ "lqe": [
+ 486.363,
+ [
+ true,
+ {
+ "mp": {
+ "ory": "rj",
+ "qnl": "tyfrju",
+ "hf": null
+ },
+ "uooc": 7418,
+ "xela": 20,
+ "bt": 7014,
+ "ia": 547,
+ "szec": 68.73
+ },
+ null
+ ],
+ 3622,
+ "iwk",
+ null
+ ],
+ "fepi": 19.954,
+ "ivu": {
+ "rmnd": 65.539,
+ "bk": 98,
+ "nc": "bdg",
+ "dlb": {
+ "hw": {
+ "upzz": [
+ true,
+ {
+ "nwb": [
+ 4259.47
+ ],
+ "nbt": "yl"
+ },
+ false,
+ false,
+ 65,
+ [
+ [
+ [],
+ 629.149,
+ "lvynqh",
+ "hsk",
+ [],
+ 2011.932,
+ true,
+ []
+ ],
+ null,
+ "ymbc",
+ null
+ ],
+ "aj",
+ 97.425,
+ "hc",
+ 58
+ ]
+ },
+ "jq": true,
+ "bi": 3333,
+ "hmf": "pl",
+ "mrbj": [
+ true,
+ false
+ ]
+ }
+ },
+ "hfj": "lwk",
+ "utdl": "aku",
+ "alqb": [
+ 74,
+ 534.389,
+ 7235,
+ [
+ null,
+ false,
+ null
+ ]
+ ]
+ },
+ null,
+ {
+ "lbrx": {
+ "vm": "ubdrbb"
+ },
+ "tie": "iok",
+ "br": "ojro"
+ },
+ 70.558,
+ [
+ {
+ "mmo": null,
+ "dryu": null
+ }
+ ]
+ ],
+ true,
+ null,
+ false,
+ {
+ "jqun": 98,
+ "ivhq": [
+ [
+ [
+ 675.936,
+ [
+ 520.15,
+ 1587.4,
+ false
+ ],
+ "jt",
+ true,
+ {
+ "bn": null,
+ "ygn": "cve",
+ "zhh": true,
+ "aak": 9165,
+ "skx": true,
+ "qqsk": 662.28
+ },
+ {
+ "eio": 9933.6,
+ "agl": null,
+ "pf": false,
+ "kv": 5099.631,
+ "no": null,
+ "shly": 58
+ },
+ [
+ null,
+ [
+ "uiundu",
+ 726.652,
+ false,
+ 94.92,
+ 259.62,
+ {
+ "ntqu": null,
+ "frv": null,
+ "rvop": "upefj",
+ "jvdp": {
+ "nhx": [],
+ "bxnu": {},
+ "gs": null,
+ "mqho": null,
+ "xp": 65,
+ "ujj": {}
+ },
+ "ts": false,
+ "kyuk": [
+ false,
+ 58,
+ {},
+ "khqqif"
+ ]
+ },
+ 167,
+ true,
+ "bhlej",
+ 53
+ ],
+ 64,
+ {
+ "eans": "wgzfo",
+ "zfgb": 431.67,
+ "udy": [
+ {
+ "gnt": [],
+ "zeve": {}
+ },
+ {
+ "pg": {},
+ "vsuc": {},
+ "dw": 19,
+ "ffo": "uwsh",
+ "spk": "pjdyam",
+ "mc": [],
+ "wunb": {},
+ "qcze": 2271.15,
+ "mcqx": null
+ },
+ "qob"
+ ],
+ "wo": "zy"
+ },
+ {
+ "dok": null,
+ "ygk": null,
+ "afdw": [
+ 7848,
+ "ah",
+ null
+ ],
+ "foobar": 3.141592,
+ "wnuo": {
+ "zpvi": {
+ "stw": true,
+ "bq": {},
+ "zord": true,
+ "omne": 3061.73,
+ "bnwm": "wuuyy",
+ "tuv": 7053,
+ "lepv": null,
+ "xap": 94.26
+ },
+ "nuv": false,
+ "hhza": 539.615,
+ "rqw": {
+ "dk": 2305,
+ "wibo": 7512.9,
+ "ytbc": 153,
+ "pokp": null,
+ "whzd": null,
+ "judg": [],
+ "zh": null
+ },
+ "bcnu": "ji",
+ "yhqu": null,
+ "gwc": true,
+ "smp": {
+ "fxpl": 75,
+ "gc": [],
+ "vx": 9352.895,
+ "fbzf": 4138.27,
+ "tiaq": 354.306,
+ "kmfb": {},
+ "fxhy": [],
+ "af": 94.46,
+ "wg": {},
+ "fb": null
+ }
+ },
+ "zvym": 2921,
+ "hhlh": [
+ 45,
+ 214.345
+ ],
+ "vv": "gqjoz"
+ },
+ [
+ "uxlu",
+ null,
+ "utl",
+ 64,
+ [
+ 2695
+ ],
+ [
+ false,
+ null,
+ [
+ "cfcrl",
+ [],
+ [],
+ 562,
+ 1654.9,
+ {},
+ null,
+ "sqzud",
+ 934.6
+ ],
+ {
+ "hk": true,
+ "ed": "lodube",
+ "ye": "ziwddj",
+ "ps": null,
+ "ir": {},
+ "heh": false
+ },
+ true,
+ 719,
+ 50.56,
+ [
+ 99,
+ 6409,
+ null,
+ 4886,
+ "esdtkt",
+ {},
+ null
+ ],
+ [
+ false,
+ "bkzqw"
+ ]
+ ],
+ null,
+ 6357
+ ],
+ {
+ "asvv": 22.873,
+ "vqm": {
+ "drmv": 68.12,
+ "tmf": 140.495,
+ "le": null,
+ "sanf": [
+ true,
+ [],
+ "vyawd",
+ false,
+ 76.496,
+ [],
+ "sdfpr",
+ 33.16,
+ "nrxy",
+ "antje"
+ ],
+ "yrkh": 662.426,
+ "vxj": true,
+ "sn": 314.382,
+ "eorg": null
+ },
+ "bavq": [
+ 21.18,
+ 8742.66,
+ {
+ "eq": "urnd"
+ },
+ 56.63,
+ "fw",
+ [
+ {},
+ "pjtr",
+ null,
+ "apyemk",
+ [],
+ [],
+ false,
+ {}
+ ],
+ {
+ "ho": null,
+ "ir": 124,
+ "oevp": 159,
+ "xdrv": 6705,
+ "ff": [],
+ "sx": false
+ },
+ true,
+ null,
+ true
+ ],
+ "zw": "qjqaap",
+ "hr": {
+ "xz": 32,
+ "mj": 8235.32,
+ "yrtv": null,
+ "jcz": "vnemxe",
+ "ywai": [
+ null,
+ 564,
+ false,
+ "vbr",
+ 54.741
+ ],
+ "vw": 82,
+ "wn": true,
+ "pav": true
+ },
+ "vxa": 881
+ },
+ "bgt",
+ "vuzk",
+ 857
+ ]
+ ]
+ ],
+ null,
+ null,
+ {
+ "xyzl": "nvfff"
+ },
+ true,
+ 13
+ ],
+ "npd": null,
+ "ha": [
+ [
+ "du",
+ [
+ 980,
+ {
+ "zdhd": [
+ 129.986,
+ [
+ "liehns",
+ 453,
+ {
+ "fuq": false,
+ "dxpn": {},
+ "hmpx": 49,
+ "zb": "gbpt",
+ "vdqc": null,
+ "ysjg": false,
+ "gug": 7990.66
+ },
+ "evek",
+ [
+ {}
+ ],
+ "dfywcu",
+ 9686,
+ null
+ ]
+ ],
+ "gpi": {
+ "gt": {
+ "qe": 7460,
+ "nh": "nrn",
+ "czj": 66.609,
+ "jwd": true,
+ "rb": "azwwe",
+ "fj": {
+ "csn": true,
+ "foobar": 1.61803398875,
+ "hm": "efsgw",
+ "zn": "vbpizt",
+ "tjo": 138.15,
+ "teo": {},
+ "hecf": [],
+ "ls": false
+ }
+ },
+ "xlc": 7916,
+ "jqst": 48.166,
+ "zj": "ivctu"
+ },
+ "jl": 369.27,
+ "mxkx": null,
+ "sh": [
+ true,
+ 373,
+ false,
+ "sdis",
+ 6217,
+ {
+ "ernm": null,
+ "srbo": 90.798,
+ "py": 677,
+ "jgrq": null,
+ "zujl": null,
+ "odsm": {
+ "pfrd": null,
+ "kwz": "kfvjzb",
+ "ptkp": false,
+ "pu": null,
+ "xty": null,
+ "ntx": [],
+ "nq": 48.19,
+ "lpyx": []
+ },
+ "ff": null,
+ "rvi": [
+ "ych",
+ {},
+ 72,
+ 9379,
+ 7897.383,
+ true,
+ {},
+ 999.751,
+ false
+ ]
+ },
+ true
+ ],
+ "ghe": [
+ 24,
+ {
+ "lpr": true,
+ "qrs": true
+ },
+ true,
+ false,
+ 7951.94,
+ true,
+ 2690.54,
+ [
+ 93,
+ null,
+ null,
+ "rlz",
+ true,
+ "ky",
+ true
+ ]
+ ],
+ "vet": false,
+ "olle": null
+ },
+ "jzm",
+ true
+ ],
+ null,
+ null,
+ 19.17,
+ 7145,
+ "ipsmk"
+ ],
+ false,
+ {
+ "du": 6550.959,
+ "sps": 8783.62,
+ "nblr": {
+ "dko": 9856.616,
+ "lz": {
+ "phng": "dj"
+ },
+ "zeu": 766,
+ "tn": "dkr"
+ },
+ "xa": "trdw",
+ "gn": 9875.687,
+ "dl": null,
+ "vuql": null
+ },
+ {
+ "qpjo": null,
+ "das": {
+ "or": {
+ "xfy": null,
+ "xwvs": 4181.86,
+ "yj": 206.325,
+ "bsr": [
+ "qrtsh"
+ ],
+ "wndm": {
+ "ve": 56,
+ "jyqa": true,
+ "ca": null
+ },
+ "rpd": 9906,
+ "ea": "dvzcyt"
+ },
+ "xwnn": 9272,
+ "rpx": "zpr",
+ "srzg": {
+ "beo": 325.6,
+ "sq": null,
+ "yf": null,
+ "nu": [
+ 377,
+ "qda",
+ true
+ ],
+ "sfz": "zjk"
+ },
+ "kh": "xnpj",
+ "rk": null,
+ "hzhn": [
+ null
+ ],
+ "uio": 6249.12,
+ "nxrv": 1931.635,
+ "pd": null
+ },
+ "pxlc": true,
+ "mjer": false,
+ "hdev": "msr",
+ "er": null
+ },
+ "ug",
+ null,
+ "yrfoix",
+ 503.89,
+ 563
+ ],
+ "tcy": 300,
+ "me": 459.17,
+ "tm": [
+ 134.761,
+ "jcoels",
+ null
+ ],
+ "iig": 945.57,
+ "ad": "be"
+ },
+ "ltpdm",
+ null,
+ 14.53
+ ],
+ "xi": "gxzzs",
+ "zfpw": 1564.87,
+ "ow": null,
+ "tm": [
+ 46,
+ 876.85
+ ],
+ "xejv": null
+}
+""" \ No newline at end of file