From 87cd3cb5a539d515caf3ac8dd6c8357986ddfb76 Mon Sep 17 00:00:00 2001 From: Yisrael Union Date: Sun, 24 Nov 2024 18:27:32 -0500 Subject: [PATCH] add unlink and random key commands (#930) * add unlink and random key commands * fix tests --- .../main/scala/dev/profunktor/redis4cats/algebra/keys.scala | 3 +++ .../src/main/scala/dev/profunktor/redis4cats/redis.scala | 6 ++++++ .../scala/dev/profunktor/redis4cats/TestScenarios.scala | 4 +++- 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/modules/effects/src/main/scala/dev/profunktor/redis4cats/algebra/keys.scala b/modules/effects/src/main/scala/dev/profunktor/redis4cats/algebra/keys.scala index b8d27710..e259b570 100644 --- a/modules/effects/src/main/scala/dev/profunktor/redis4cats/algebra/keys.scala +++ b/modules/effects/src/main/scala/dev/profunktor/redis4cats/algebra/keys.scala @@ -35,6 +35,7 @@ trait KeyCommands[F[_], K] { def objectIdletime(key: K): F[Option[FiniteDuration]] def persist(key: K): F[Boolean] def pttl(key: K): F[Option[FiniteDuration]] + def randomKey: F[Option[K]] // restores a key with the given serialized value, previously obtained using DUMP without a ttl def restore(key: K, value: Array[Byte]): F[Unit] def restore(key: K, value: Array[Byte], restoreArgs: RestoreArgs): F[Unit] @@ -52,5 +53,7 @@ trait KeyCommands[F[_], K] { def scan(cursor: KeyScanCursor[K], keyScanArgs: KeyScanArgs): F[KeyScanCursor[K]] def typeOf(key: K): F[Option[RedisType]] def ttl(key: K): F[Option[FiniteDuration]] + //This command is very similar to DEL: it removes the specified keys. Just like DEL a key is ignored if it does not exist. However the command performs the actual memory reclaiming in a different thread, so it is not blocking, while DEL is. This is where the command name comes from: the command just unlinks the keys from the keyspace. The actual removal will happen later asynchronously. + def unlink(key: K*): F[Long] } diff --git a/modules/effects/src/main/scala/dev/profunktor/redis4cats/redis.scala b/modules/effects/src/main/scala/dev/profunktor/redis4cats/redis.scala index 6ed88a81..8172958a 100644 --- a/modules/effects/src/main/scala/dev/profunktor/redis4cats/redis.scala +++ b/modules/effects/src/main/scala/dev/profunktor/redis4cats/redis.scala @@ -544,6 +544,9 @@ private[redis4cats] class BaseRedis[F[_]: FutureLift: MonadThrow: Log, K, V]( override def pttl(key: K): F[Option[FiniteDuration]] = async.flatMap(_.pttl(key).futureLift.map(toFiniteDuration(TimeUnit.MILLISECONDS))) + override def randomKey: F[Option[K]] = + async.flatMap(_.randomkey().futureLift.map(Option(_))) + override def restore(key: K, value: Array[Byte]): F[Unit] = async.flatMap(_.restore(key, 0, value).futureLift.void) @@ -580,6 +583,9 @@ private[redis4cats] class BaseRedis[F[_]: FutureLift: MonadThrow: Log, K, V]( override def typeOf(key: K): F[Option[RedisType]] = async.flatMap(_.`type`(key).futureLift.map(RedisType.fromString)) + override def unlink(key: K*): F[Long] = + async.flatMap(_.unlink(key: _*).futureLift.map(x => Long.box(x))) + /******************************* Transactions API **********************************/ // When in a cluster, transactions should run against a single node. diff --git a/modules/tests/src/test/scala/dev/profunktor/redis4cats/TestScenarios.scala b/modules/tests/src/test/scala/dev/profunktor/redis4cats/TestScenarios.scala index 40ed4c50..016d72e4 100644 --- a/modules/tests/src/test/scala/dev/profunktor/redis4cats/TestScenarios.scala +++ b/modules/tests/src/test/scala/dev/profunktor/redis4cats/TestScenarios.scala @@ -233,6 +233,8 @@ trait TestScenarios { self: FunSuite => _ <- redis.set(key1, "some value") exist2 <- redis.exists(key1) _ <- IO(assert(exist2)) + rkey <- redis.randomKey + _ <- IO(assert(rkey.forall(_ == key1))) dump <- redis.dump(key1) _ <- IO(assert(dump.nonEmpty)) _ <- redis.restore(key1, dump.get, RestoreArgs().replace(true)) @@ -301,7 +303,7 @@ trait TestScenarios { self: FunSuite => _ <- IO(assertEquals(kv, Some("v"))) kTtl2 <- redis.ttl("k") _ <- IO(assert(kTtl2.nonEmpty)) - _ <- redis.del("k") + _ <- redis.unlink("k") tpe <- redis.typeOf("k") _ <- IO(assertEquals(tpe, None)) _ <- redis.set("aV", "v")