Repository: redis/redis-py

Issue:
Add support for JSON.MSET
As defined in https://github.com/RedisJSON/RedisJSON/blob/e4608065002bdf585ad54fbe142e08be18d666a8/commands.json#L142


Discussion:

Resolving patch:
diff --git a/redis/commands/json/__init__.py b/redis/commands/json/__init__.py
--- a/redis/commands/json/__init__.py
+++ b/redis/commands/json/__init__.py
@@ -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.MSET": lambda r: r and nativestr(r) == "OK",
             "JSON.MERGE": lambda r: r and nativestr(r) == "OK",
             "JSON.NUMINCRBY": self._decode,
             "JSON.NUMMULTBY": self._decode,
diff --git a/redis/commands/json/commands.py b/redis/commands/json/commands.py
--- a/redis/commands/json/commands.py
+++ b/redis/commands/json/commands.py
@@ -1,6 +1,6 @@
 import os
 from json import JSONDecodeError, loads
-from typing import Dict, List, Optional, Union
+from typing import Dict, List, Optional, Tuple, Union
 
 from redis.exceptions import DataError
 from redis.utils import deprecated_function
@@ -253,6 +253,23 @@ def set(
             pieces.append("XX")
         return self.execute_command("JSON.SET", *pieces)
 
+    def mset(self, triplets: List[Tuple[str, str, JsonType]]) -> Optional[str]:
+        """
+        Set the JSON value at key ``name`` under the ``path`` to ``obj``
+        for one or more keys.
+
+        ``triplets`` is a list of one or more triplets of key, path, value.
+
+        For the purpose of using this within a pipeline, this command is also
+        aliased to JSON.MSET.
+
+        For more information see `JSON.MSET <https://redis.io/commands/json.mset>`_.
+        """
+        pieces = []
+        for triplet in triplets:
+            pieces.extend([triplet[0], str(triplet[1]), self._encode(triplet[2])])
+        return self.execute_command("JSON.MSET", *pieces)
+
     def merge(
         self,
         name: str,


Test patch:
diff --git a/tests/test_asyncio/test_json.py b/tests/test_asyncio/test_json.py
--- a/tests/test_asyncio/test_json.py
+++ b/tests/test_asyncio/test_json.py
@@ -109,6 +109,17 @@ async def test_mgetshouldsucceed(modclient: redis.Redis):
     assert await modclient.json().mget([1, 2], Path.root_path()) == [1, 2]
 
 
+@pytest.mark.redismod
+@skip_ifmodversion_lt("2.6.0", "ReJSON")  # todo: update after the release
+async def test_mset(modclient: redis.Redis):
+    await modclient.json().mset(
+        [("1", Path.root_path(), 1), ("2", Path.root_path(), 2)]
+    )
+
+    assert await modclient.json().mget(["1"], Path.root_path()) == [1]
+    assert await modclient.json().mget(["1", "2"], Path.root_path()) == [1, 2]
+
+
 @pytest.mark.redismod
 @skip_ifmodversion_lt("99.99.99", "ReJSON")  # todo: update after the release
 async def test_clear(modclient: redis.Redis):
diff --git a/tests/test_json.py b/tests/test_json.py
--- a/tests/test_json.py
+++ b/tests/test_json.py
@@ -115,6 +115,15 @@ def test_mgetshouldsucceed(client):
     assert client.json().mget([1, 2], Path.root_path()) == [1, 2]
 
 
+@pytest.mark.redismod
+@skip_ifmodversion_lt("2.6.0", "ReJSON")  # todo: update after the release
+def test_mset(client):
+    client.json().mset([("1", Path.root_path(), 1), ("2", Path.root_path(), 2)])
+
+    assert client.json().mget(["1"], Path.root_path()) == [1]
+    assert client.json().mget(["1", "2"], Path.root_path()) == [1, 2]
+
+
 @pytest.mark.redismod
 @skip_ifmodversion_lt("99.99.99", "ReJSON")  # todo: update after the release
 def test_clear(client):