Skip to content

Commit 2d9b5ac

Browse files
authored
support JSON.MERGE Command (redis#2761)
* support JSON.MERGE Command * linters * try with abc instead person * change @skip_ifmodversion_lt to latest ReJSON 2.4.7 * change version * fix test * linters * add async test
1 parent 35b7e09 commit 2d9b5ac

File tree

4 files changed

+91
-0
lines changed

4 files changed

+91
-0
lines changed

redis/commands/json/__init__.py

+1
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ def __init__(
3838
"JSON.GET": self._decode,
3939
"JSON.MGET": bulk_of_jsons(self._decode),
4040
"JSON.SET": lambda r: r and nativestr(r) == "OK",
41+
"JSON.MERGE": lambda r: r and nativestr(r) == "OK",
4142
"JSON.NUMINCRBY": self._decode,
4243
"JSON.NUMMULTBY": self._decode,
4344
"JSON.TOGGLE": self._decode,

redis/commands/json/commands.py

+22
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,28 @@ def set(
253253
pieces.append("XX")
254254
return self.execute_command("JSON.SET", *pieces)
255255

256+
def merge(
257+
self,
258+
name: str,
259+
path: str,
260+
obj: JsonType,
261+
decode_keys: Optional[bool] = False,
262+
) -> Optional[str]:
263+
"""
264+
Sets or updates the JSON value at a path..
265+
266+
``decode_keys`` If set to True, the keys of ``obj`` will be decoded
267+
with utf-8.
268+
269+
For more information see `JSON.MERGE <https://redis.io/commands/json.merge>`_.
270+
"""
271+
if decode_keys:
272+
obj = decode_dict_keys(obj)
273+
274+
pieces = [name, str(path), self._encode(obj)]
275+
276+
return self.execute_command("JSON.MERGE", *pieces)
277+
256278
def set_file(
257279
self,
258280
name: str,

tests/test_asyncio/test_json.py

+35
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,41 @@ async def test_json_get_jset(modclient: redis.Redis):
3939
assert await modclient.exists("foo") == 0
4040

4141

42+
@pytest.mark.redismod
43+
@skip_ifmodversion_lt("2.6.0", "ReJSON") # todo: update after the release
44+
async def test_json_merge(modclient: redis.Redis):
45+
# Test with root path $
46+
assert await modclient.json().set(
47+
"person_data",
48+
"$",
49+
{"person1": {"personal_data": {"name": "John"}}},
50+
)
51+
assert await modclient.json().merge(
52+
"person_data", "$", {"person1": {"personal_data": {"hobbies": "reading"}}}
53+
)
54+
assert await modclient.json().get("person_data") == {
55+
"person1": {"personal_data": {"name": "John", "hobbies": "reading"}}
56+
}
57+
58+
# Test with root path path $.person1.personal_data
59+
assert await modclient.json().merge(
60+
"person_data", "$.person1.personal_data", {"country": "Israel"}
61+
)
62+
assert await modclient.json().get("person_data") == {
63+
"person1": {
64+
"personal_data": {"name": "John", "hobbies": "reading", "country": "Israel"}
65+
}
66+
}
67+
68+
# Test with null value to delete a value
69+
assert await modclient.json().merge(
70+
"person_data", "$.person1.personal_data", {"name": None}
71+
)
72+
assert await modclient.json().get("person_data") == {
73+
"person1": {"personal_data": {"country": "Israel", "hobbies": "reading"}}
74+
}
75+
76+
4277
@pytest.mark.redismod
4378
async def test_nonascii_setgetdelete(modclient: redis.Redis):
4479
assert await modclient.json().set("notascii", Path.root_path(), "hyvää-élève")

tests/test_json.py

+33
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,39 @@ def test_json_get_jset(client):
4747
assert client.exists("foo") == 0
4848

4949

50+
@pytest.mark.redismod
51+
@skip_ifmodversion_lt("2.6.0", "ReJSON") # todo: update after the release
52+
def test_json_merge(client):
53+
# Test with root path $
54+
assert client.json().set(
55+
"person_data",
56+
"$",
57+
{"person1": {"personal_data": {"name": "John"}}},
58+
)
59+
assert client.json().merge(
60+
"person_data", "$", {"person1": {"personal_data": {"hobbies": "reading"}}}
61+
)
62+
assert client.json().get("person_data") == {
63+
"person1": {"personal_data": {"name": "John", "hobbies": "reading"}}
64+
}
65+
66+
# Test with root path path $.person1.personal_data
67+
assert client.json().merge(
68+
"person_data", "$.person1.personal_data", {"country": "Israel"}
69+
)
70+
assert client.json().get("person_data") == {
71+
"person1": {
72+
"personal_data": {"name": "John", "hobbies": "reading", "country": "Israel"}
73+
}
74+
}
75+
76+
# Test with null value to delete a value
77+
assert client.json().merge("person_data", "$.person1.personal_data", {"name": None})
78+
assert client.json().get("person_data") == {
79+
"person1": {"personal_data": {"country": "Israel", "hobbies": "reading"}}
80+
}
81+
82+
5083
@pytest.mark.redismod
5184
def test_nonascii_setgetdelete(client):
5285
assert client.json().set("notascii", Path.root_path(), "hyvää-élève")

0 commit comments

Comments
 (0)