diff --git a/coredis/commands/core.py b/coredis/commands/core.py index a32fc519..08b1d1df 100644 --- a/coredis/commands/core.py +++ b/coredis/commands/core.py @@ -2153,6 +2153,21 @@ async def hpexpireat( CommandName.HPEXPIREAT, *pieces, callback=TupleCallback[int]() ) + @versionadded(version="4.18.0") + @redis_command( + CommandName.HPERSIST, version_introduced="7.4.0", group=CommandGroup.HASH + ) + async def hpersist(self, key: KeyT, fields: Parameters[StringT]) -> Tuple[int, ...]: + """ + Removes the expiration time for each specified field + """ + pieces: CommandArgList = [key, PrefixToken.FIELDS, len(list(fields))] + pieces.extend(fields) + + return await self.execute_command( + CommandName.HPERSIST, *pieces, callback=TupleCallback[int]() + ) + @redis_command( CommandName.HGET, group=CommandGroup.HASH, diff --git a/coredis/pipeline.pyi b/coredis/pipeline.pyi index 82bc3eb8..266814e0 100644 --- a/coredis/pipeline.pyi +++ b/coredis/pipeline.pyi @@ -270,6 +270,9 @@ class Pipeline(ObjectProxy, Generic[AnyStr]): # type: ignore async def hmset( self, key: "KeyT", field_values: "Mapping[StringT, ValueT]" ) -> Pipeline[AnyStr]: ... + async def hpersist( + self, key: "KeyT", fields: "Parameters[StringT]" + ) -> Pipeline[AnyStr]: ... async def hpexpire( self, key: "KeyT", @@ -1406,6 +1409,9 @@ class ClusterPipeline(ObjectProxy, Generic[AnyStr]): # type: ignore async def hmset( self, key: "KeyT", field_values: "Mapping[StringT, ValueT]" ) -> ClusterPipeline[AnyStr]: ... + async def hpersist( + self, key: "KeyT", fields: "Parameters[StringT]" + ) -> ClusterPipeline[AnyStr]: ... async def hpexpire( self, key: "KeyT", diff --git a/docs/source/compatibility.rst b/docs/source/compatibility.rst index 6f16b0dd..12862285 100644 --- a/docs/source/compatibility.rst +++ b/docs/source/compatibility.rst @@ -1156,6 +1156,24 @@ Sets the values of multiple fields. +HPERSIST +******** + +Removes the expiration time for each specified field + +- Documentation: `HPERSIST `_ +- Implementation: :meth:`~coredis.Redis.hpersist` + +- New in redis: 7.4.0 + + + +- .. versionadded:: 4.18.0 + + + + + HPEXPIRE ******** @@ -1336,16 +1354,6 @@ Returns all values in a hash. -HPERSIST [X] -************ - -Removes the expiration time for each specified field - -- Documentation: `HPERSIST `_ - -- Not Implemented - - diff --git a/tests/commands/test_hash.py b/tests/commands/test_hash.py index c3b91eb1..eec876cd 100644 --- a/tests/commands/test_hash.py +++ b/tests/commands/test_hash.py @@ -195,6 +195,15 @@ async def test_hpttl(self, client, _s): "a", ["1", "2", "5"] ) + @pytest.mark.min_server_version("7.4.0") + async def test_hpersist(self, client, _s): + await client.hset("a", {"1": 1, "2": 2, "3": 3, "4": 4}) + assert (-2,) == await client.hpersist("missing", ["1"]) + await client.hpexpire("a", 5000, ["1"]) + assert (pytest.approx(5000, abs=1000),) == await client.hpttl("a", ["1"]) + assert (1,) == await client.hpersist("a", ["1"]) + assert (-1,) == await client.hpttl("a", ["1"]) + async def test_hgetall(self, client, _s): h = {_s("a1"): _s("1"), _s("a2"): _s("2"), _s("a3"): _s("3")} await client.hset("a", h)