Skip to content

Commit

Permalink
support JSON.MERGE Command (#2761)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
shacharPash authored May 16, 2023
1 parent 35b7e09 commit 2d9b5ac
Show file tree
Hide file tree
Showing 4 changed files with 91 additions and 0 deletions.
1 change: 1 addition & 0 deletions redis/commands/json/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ def __init__(
"JSON.GET": self._decode,
"JSON.MGET": bulk_of_jsons(self._decode),
"JSON.SET": lambda r: r and nativestr(r) == "OK",
"JSON.MERGE": lambda r: r and nativestr(r) == "OK",
"JSON.NUMINCRBY": self._decode,
"JSON.NUMMULTBY": self._decode,
"JSON.TOGGLE": self._decode,
Expand Down
22 changes: 22 additions & 0 deletions redis/commands/json/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,28 @@ def set(
pieces.append("XX")
return self.execute_command("JSON.SET", *pieces)

def merge(
self,
name: str,
path: str,
obj: JsonType,
decode_keys: Optional[bool] = False,
) -> Optional[str]:
"""
Sets or updates the JSON value at a path..
``decode_keys`` If set to True, the keys of ``obj`` will be decoded
with utf-8.
For more information see `JSON.MERGE <https://redis.io/commands/json.merge>`_.
"""
if decode_keys:
obj = decode_dict_keys(obj)

pieces = [name, str(path), self._encode(obj)]

return self.execute_command("JSON.MERGE", *pieces)

def set_file(
self,
name: str,
Expand Down
35 changes: 35 additions & 0 deletions tests/test_asyncio/test_json.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,41 @@ async def test_json_get_jset(modclient: redis.Redis):
assert await modclient.exists("foo") == 0


@pytest.mark.redismod
@skip_ifmodversion_lt("2.6.0", "ReJSON") # todo: update after the release
async def test_json_merge(modclient: redis.Redis):
# Test with root path $
assert await modclient.json().set(
"person_data",
"$",
{"person1": {"personal_data": {"name": "John"}}},
)
assert await modclient.json().merge(
"person_data", "$", {"person1": {"personal_data": {"hobbies": "reading"}}}
)
assert await modclient.json().get("person_data") == {
"person1": {"personal_data": {"name": "John", "hobbies": "reading"}}
}

# Test with root path path $.person1.personal_data
assert await modclient.json().merge(
"person_data", "$.person1.personal_data", {"country": "Israel"}
)
assert await modclient.json().get("person_data") == {
"person1": {
"personal_data": {"name": "John", "hobbies": "reading", "country": "Israel"}
}
}

# Test with null value to delete a value
assert await modclient.json().merge(
"person_data", "$.person1.personal_data", {"name": None}
)
assert await modclient.json().get("person_data") == {
"person1": {"personal_data": {"country": "Israel", "hobbies": "reading"}}
}


@pytest.mark.redismod
async def test_nonascii_setgetdelete(modclient: redis.Redis):
assert await modclient.json().set("notascii", Path.root_path(), "hyvää-élève")
Expand Down
33 changes: 33 additions & 0 deletions tests/test_json.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,39 @@ def test_json_get_jset(client):
assert client.exists("foo") == 0


@pytest.mark.redismod
@skip_ifmodversion_lt("2.6.0", "ReJSON") # todo: update after the release
def test_json_merge(client):
# Test with root path $
assert client.json().set(
"person_data",
"$",
{"person1": {"personal_data": {"name": "John"}}},
)
assert client.json().merge(
"person_data", "$", {"person1": {"personal_data": {"hobbies": "reading"}}}
)
assert client.json().get("person_data") == {
"person1": {"personal_data": {"name": "John", "hobbies": "reading"}}
}

# Test with root path path $.person1.personal_data
assert client.json().merge(
"person_data", "$.person1.personal_data", {"country": "Israel"}
)
assert client.json().get("person_data") == {
"person1": {
"personal_data": {"name": "John", "hobbies": "reading", "country": "Israel"}
}
}

# Test with null value to delete a value
assert client.json().merge("person_data", "$.person1.personal_data", {"name": None})
assert client.json().get("person_data") == {
"person1": {"personal_data": {"country": "Israel", "hobbies": "reading"}}
}


@pytest.mark.redismod
def test_nonascii_setgetdelete(client):
assert client.json().set("notascii", Path.root_path(), "hyvää-élève")
Expand Down

0 comments on commit 2d9b5ac

Please sign in to comment.