diff --git a/redis/src/main/scala/zio/redis/api/SortedSets.scala b/redis/src/main/scala/zio/redis/api/SortedSets.scala index 359560aef..4d0eff0b4 100644 --- a/redis/src/main/scala/zio/redis/api/SortedSets.scala +++ b/redis/src/main/scala/zio/redis/api/SortedSets.scala @@ -792,7 +792,7 @@ trait SortedSets { * * @param key Key of the set * @param keys Keys of the rest sets - * @return list of scores or None associated with the specified member values (a double precision floating point + * @return List of scores or None associated with the specified member values (a double precision floating point * number). */ final def zMScore[K: Schema]( @@ -802,6 +802,58 @@ trait SortedSets { val command = RedisCommand(Zmscore, NonEmptyList(ArbitraryInput[K]()), ChunkOutput(OptionalOutput(DoubleOutput))) command.run((key, keys.toList)) } + + /** + * Return a random element from the sorted set value stored at key. + * + * @param key Key of a sorted set + * @return Return a random element from the sorted set value stored at key. + */ + final def zRandMember[K: Schema, M: Schema](key: K): ZIO[RedisExecutor, RedisError, Option[M]] = { + val command = RedisCommand(ZRandMember, ArbitraryInput[K](), OptionalOutput(ArbitraryOutput[M]())) + command.run(key) + } + + /** + * Return random elements from the sorted set value stored at key. + * + * @param key Key of a sorted set + * @param count If the provided count argument is positive, return an array of distinct elements. + * The array's length is either count or the sorted set's cardinality (ZCARD), whichever is lower + * @return Return an array of elements from the sorted set value stored at key. + */ + final def zRandMember[K: Schema, M: Schema](key: K, count: Long): ZIO[RedisExecutor, RedisError, Option[Chunk[M]]] = { + val command = RedisCommand( + ZRandMember, + Tuple2(ArbitraryInput[K](), LongInput), + OptionalOutput(ChunkOutput(ArbitraryOutput[M]())) + ) + command.run((key, count)) + } + + /** + * Return random elements from the sorted set value stored at key. + * + * @param key Key of a sorted set + * @param count If the provided count argument is positive, return an array of distinct elements. + * The array's length is either count or the sorted set's cardinality (ZCARD), whichever is lower + * @return When the additional count argument is passed, the command returns an array of elements, or an empty array when key does not exist. + * If the WITHSCORES modifier is used, the reply is a list elements and their scores from the sorted set. + */ + final def zRandMemberWithScores[K: Schema, M: Schema]( + key: K, + count: Long + ): ZIO[RedisExecutor, RedisError, Option[Chunk[MemberScore[M]]]] = { + val command = RedisCommand( + ZRandMember, + Tuple3(ArbitraryInput[K](), LongInput, ArbitraryInput[String]()), + OptionalOutput( + ChunkTuple2Output(ArbitraryOutput[M](), DoubleOutput) + .map(_.map { case (m, s) => MemberScore(s, m) }) + ) + ) + command.run((key, count, WithScores.stringify)) + } } private[redis] object SortedSets { @@ -834,4 +886,5 @@ private[redis] object SortedSets { final val ZUnion = "ZUNION" final val ZUnionStore = "ZUNIONSTORE" final val Zmscore = "ZMSCORE" + final val ZRandMember = "ZRANDMEMBER" } diff --git a/redis/src/test/scala/zio/redis/SortedSetsSpec.scala b/redis/src/test/scala/zio/redis/SortedSetsSpec.scala index bd0b09d91..0c312648a 100644 --- a/redis/src/test/scala/zio/redis/SortedSetsSpec.scala +++ b/redis/src/test/scala/zio/redis/SortedSetsSpec.scala @@ -1667,6 +1667,55 @@ trait SortedSetsSpec extends BaseSpec { card <- zUnionStore(dest, 2, first, second)(Some(::(2, List(3))), Some(Aggregate.Max)) } yield assert(card)(equalTo(4L)) } + ), + suite("zRandMember")( + testM("key does not exist") { + for { + first <- uuid + notExists <- uuid + _ <- zAdd(first)(MemberScore(1d, "a"), MemberScore(2d, "b"), MemberScore(3d, "c"), MemberScore(4d, "d")) + ret <- zRandMember[String, String](notExists) + } yield assert(ret)(isNone) + }, + testM("key does not exist with count") { + for { + first <- uuid + notExists <- uuid + _ <- zAdd(first)(MemberScore(1d, "a"), MemberScore(2d, "b"), MemberScore(3d, "c"), MemberScore(4d, "d")) + ret <- zRandMember[String, String](notExists, 1) + } yield assert(ret)(isNone) + }, + testM("get an element") { + for { + first <- uuid + _ <- zAdd(first)(MemberScore(1d, "a"), MemberScore(2d, "b"), MemberScore(3d, "c"), MemberScore(4d, "d")) + ret <- zRandMember[String, String](first) + } yield assert(ret)(isSome) + }, + testM("get elements with count") { + for { + first <- uuid + _ <- zAdd(first)(MemberScore(1d, "a"), MemberScore(2d, "b"), MemberScore(3d, "c"), MemberScore(4d, "d")) + ret <- zRandMember[String, String](first, 2) + } yield assert(ret)(isSome) && assert(ret.get.size)(equalTo(2)) + } + ), + suite("zRandMemberWithScores")( + testM("key does not exist") { + for { + first <- uuid + notExists <- uuid + _ <- zAdd(first)(MemberScore(1d, "a"), MemberScore(2d, "b"), MemberScore(3d, "c"), MemberScore(4d, "d")) + ret <- zRandMemberWithScores[String, String](notExists, 1) + } yield assert(ret)(isNone) + }, + testM("get elements with count") { + for { + first <- uuid + _ <- zAdd(first)(MemberScore(1d, "a"), MemberScore(2d, "b"), MemberScore(3d, "c"), MemberScore(4d, "d")) + ret <- zRandMemberWithScores[String, String](first, 2) + } yield assert(ret)(isSome) && assert(ret.get.size)(equalTo(2)) + } ) )