Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions nri-redis/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# 0.4.2.0

- Adds `zcard`, `zrem`, and `zremRangeByScore` to `Redis.SortedSet`.

# 0.4.1.1

- Require `nri-prelude >= 0.7.0.0`
Expand Down
2 changes: 1 addition & 1 deletion nri-redis/nri-redis.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ cabal-version: 1.18
-- see: https://github.com/sol/hpack

name: nri-redis
version: 0.4.1.1
version: 0.4.2.0
synopsis: An intuitive hedis wrapper library.
description: Please see the README at <https://github.com/NoRedInk/haskell-libraries/tree/trunk/nri-redis#readme>.
category: Web
Expand Down
2 changes: 1 addition & 1 deletion nri-redis/package.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ synopsis: An intuitive hedis wrapper library.
description: Please see the README at <https://github.com/NoRedInk/haskell-libraries/tree/trunk/nri-redis#readme>.
homepage: https://github.com/NoRedInk/haskell-libraries/tree/trunk/nri-redis#readme
author: NoRedInk
version: 0.4.1.1
version: 0.4.2.0
maintainer: haskell-open-source@noredink.com
copyright: 2026 NoRedInk Corp.
github: NoRedInk/haskell-libraries/nri-redis
Expand Down
12 changes: 12 additions & 0 deletions nri-redis/src/Redis/Handler.hs
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,10 @@ doRawQuery query =
|> Database.Redis.zadd (toB key)
|> PreparedQuery
|> map (Ok << Prelude.fromIntegral)
Internal.Zcard key ->
Database.Redis.zcard (toB key)
|> PreparedQuery
|> map (Ok << Prelude.fromIntegral)
Internal.Zrange key start stop ->
Database.Redis.zrange
(toB key)
Expand All @@ -344,6 +348,14 @@ doRawQuery query =
Database.Redis.zrank (toB key) member
|> PreparedQuery
|> map (Ok << map Prelude.fromIntegral)
Internal.Zrem key vals ->
Database.Redis.zrem (toB key) (NonEmpty.toList vals)
|> PreparedQuery
|> map (Ok << Prelude.fromIntegral)
Internal.ZremRangeByScore key lower upper ->
Database.Redis.zremrangebyscore (toB key) lower upper
|> PreparedQuery
|> map (Ok << Prelude.fromIntegral)
Internal.Zrevrank key member ->
Database.Redis.zrevrank (toB key) member
|> PreparedQuery
Expand Down
15 changes: 15 additions & 0 deletions nri-redis/src/Redis/Internal.hs
Original file line number Diff line number Diff line change
Expand Up @@ -117,9 +117,12 @@ cmds query'' =
Smembers key -> [unwords ["SMEMBERS", key]]
Ttl key -> [unwords ["TTL", key]]
Zadd key vals -> [unwords ("ZADD" : key : List.concatMap (\(_, val) -> ["*****", Text.fromFloat val]) (Dict.toList vals))]
Zcard key -> [unwords ["ZCARD", key]]
Zrange key start stop -> [unwords ["ZRANGE", key, Text.fromInt start, Text.fromInt stop]]
ZrangeByScoreWithScores key start stop -> [unwords ["ZRANGE", key, "BYSCORE", Text.fromFloat start, Text.fromFloat stop, "WITHSCORES"]]
Zrank key _ -> [unwords ["ZRANK", key, "*****"]]
Zrem key vals -> [unwords ("ZREM" : key : List.map (\_ -> "*****") (NonEmpty.toList vals))]
ZremRangeByScore key lower upper -> [unwords ["ZREMRANGEBYSCORE", key, Text.fromFloat lower, Text.fromFloat upper]]
Zrevrank key _ -> [unwords ["ZREVRANK", key, "*****"]]
Pure _ -> []
Apply f x -> cmds f ++ cmds x
Expand Down Expand Up @@ -175,9 +178,12 @@ data Query a where
Smembers :: Text -> Query (List ByteString)
Ttl :: Text -> Query Int
Zadd :: Text -> Dict.Dict ByteString Float -> Query Int
Zcard :: Text -> Query Int
Zrange :: Text -> Int -> Int -> Query [ByteString]
ZrangeByScoreWithScores :: Text -> Float -> Float -> Query [(ByteString, Float)]
Zrank :: Text -> ByteString -> Query (Maybe Int)
Zrem :: Text -> NonEmpty ByteString -> Query Int
ZremRangeByScore :: Text -> Float -> Float -> Query Int
Zrevrank :: Text -> ByteString -> Query (Maybe Int)
-- The constructors below are not Redis-related, but support using functions
-- like `map` and `map2` on queries.
Expand Down Expand Up @@ -329,9 +335,12 @@ mapKeys fn query' =
Smembers key -> Task.map Smembers (fn key)
Ttl key -> Task.map Ttl (fn key)
Zadd key vals -> Task.map (\newKey -> Zadd newKey vals) (fn key)
Zcard key -> Task.map Zcard (fn key)
Zrange key start stop -> Task.map (\newKey -> Zrange newKey start stop) (fn key)
ZrangeByScoreWithScores key start stop -> Task.map (\newKey -> ZrangeByScoreWithScores newKey start stop) (fn key)
Zrank key member -> Task.map (\newKey -> Zrank newKey member) (fn key)
Zrem key vals -> Task.map (\newKey -> Zrem newKey vals) (fn key)
ZremRangeByScore key lower upper -> Task.map (\newKey -> ZremRangeByScore newKey lower upper) (fn key)
Zrevrank key member -> Task.map (\newKey -> Zrevrank newKey member) (fn key)
Pure x -> Task.succeed (Pure x)
Apply f x -> Task.map2 Apply (mapKeys fn f) (mapKeys fn x)
Expand Down Expand Up @@ -373,9 +382,12 @@ mapReturnedKeys fn query' =
Smembers key -> Smembers key
Ttl key -> Ttl key
Zadd key vals -> Zadd key vals
Zcard key -> Zcard key
Zrange key start stop -> Zrange key start stop
ZrangeByScoreWithScores key start stop -> ZrangeByScoreWithScores key start stop
Zrank key member -> Zrank key member
Zrem key vals -> Zrem key vals
ZremRangeByScore key lower upper -> ZremRangeByScore key lower upper
Zrevrank key member -> Zrevrank key member
Pure x -> Pure x
Apply f x -> Apply (mapReturnedKeys fn f) (mapReturnedKeys fn x)
Expand Down Expand Up @@ -434,9 +446,12 @@ keysTouchedByQuery query' =
-- so it doesn't auto-extending the TTL.
Ttl _ -> Set.empty
Zadd key _ -> Set.singleton key
Zcard key -> Set.singleton key
Zrange key _ _ -> Set.singleton key
ZrangeByScoreWithScores key _ _ -> Set.singleton key
Zrank key _ -> Set.singleton key
Zrem key _ -> Set.singleton key
ZremRangeByScore key _ _ -> Set.singleton key
Zrevrank key _ -> Set.singleton key
WithResult _ q -> keysTouchedByQuery q

Expand Down
20 changes: 20 additions & 0 deletions nri-redis/src/Redis/SortedSet.hs
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,12 @@ module Redis.SortedSet
expire,
ping,
zadd,
zcard,
zrange,
zrangeByScoreWithScores,
zrank,
zrem,
zremRangeByScore,
zrevrank,

-- * Running Redis queries
Expand Down Expand Up @@ -82,6 +85,10 @@ data Api key a = Api
--
-- https://redis.io/commands/zadd
zadd :: key -> NonEmptyDict.NonEmptyDict a Float -> Internal.Query Int,
-- | Returns the number of members of the sorted set.
--
-- https://redis.io/commands/zcard
zcard :: key -> Internal.Query Int,
-- | Returns the specified range of elements in the sorted set. The order of
-- elements is from the lowest to the highest score. Elements with the same
-- score are ordered lexicographically. The <start> and <stop> arguments
Expand All @@ -107,6 +114,16 @@ data Api key a = Api
--
-- https://redis.io/commands/zrank
zrank :: key -> a -> Internal.Query (Maybe Int),
-- | Removes the specified members from the sorted set. Members that are
-- not part of the set are ignored. Returns the number of members removed.
--
-- https://redis.io/commands/zrem
zrem :: key -> NonEmpty a -> Internal.Query Int,
-- | Removes all members in the sorted set with a score between the two
-- bounds (inclusive). Returns the number of members removed.
--
-- https://redis.io/commands/zremrangebyscore
zremRangeByScore :: key -> Float -> Float -> Internal.Query Int,
-- | Returns the rank of member in the sorted set stored at key, with the
-- scores ordered from high to low. The rank (or index) is 0-based, which
-- means that the member with the highest score has rank 0.
Expand Down Expand Up @@ -150,6 +167,7 @@ makeApi Codec.Codec {Codec.codecEncoder, Codec.codecDecoder} toKey =
ping = Internal.Ping |> map (\_ -> ()),
zadd = \key vals ->
Internal.Zadd (toKey key) (Data.Map.Strict.mapKeys codecEncoder (NonEmptyDict.toDict vals)),
zcard = \key -> Internal.Zcard (toKey key),
zrange = \key start stop ->
Internal.Zrange (toKey key) start stop
|> Internal.WithResult (Prelude.traverse codecDecoder),
Expand All @@ -162,5 +180,7 @@ makeApi Codec.Codec {Codec.codecEncoder, Codec.codecDecoder} toKey =
)
),
zrank = \key member -> Internal.Zrank (toKey key) (codecEncoder member),
zrem = \key vals -> Internal.Zrem (toKey key) (NonEmpty.map codecEncoder vals),
zremRangeByScore = \key lower upper -> Internal.ZremRangeByScore (toKey key) lower upper,
zrevrank = \key member -> Internal.Zrevrank (toKey key) (codecEncoder member)
}
55 changes: 55 additions & 0 deletions nri-redis/test/Spec/Redis.hs
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,44 @@ queryTests redisHandler =
Redis.SortedSet.zrange sortedSetApi "zrange-works" (-2) (-1)
|> Redis.query redisHandler
|> Expect.andCheck (Expect.equal ["two", "three"]),
Test.test "zcard returns the number of members" <| \() -> do
_ <-
Redis.SortedSet.del sortedSetApi ("zcard-returns-count" :| [])
|> Redis.query redisHandler
|> Expect.succeeds
_ <-
NonEmptyDict.init "one" 1 (Dict.fromList [("two", 2), ("three", 3)])
|> Redis.SortedSet.zadd sortedSetApi "zcard-returns-count"
|> Redis.query redisHandler
|> Expect.succeeds
Redis.SortedSet.zcard sortedSetApi "zcard-returns-count"
|> Redis.query redisHandler
|> Expect.andCheck (Expect.equal 3),
Test.test "zcard on a missing key returns 0" <| \() -> do
_ <-
Redis.SortedSet.del sortedSetApi ("zcard-missing-key" :| [])
|> Redis.query redisHandler
|> Expect.succeeds
Redis.SortedSet.zcard sortedSetApi "zcard-missing-key"
|> Redis.query redisHandler
|> Expect.andCheck (Expect.equal 0),
Test.test "zremRangeByScore removes members in the inclusive score range" <| \() -> do
_ <-
Redis.SortedSet.del sortedSetApi ("zremRangeByScore-trims" :| [])
|> Redis.query redisHandler
|> Expect.succeeds
_ <-
NonEmptyDict.init "one" 1 (Dict.fromList [("two", 2), ("three", 3)])
|> Redis.SortedSet.zadd sortedSetApi "zremRangeByScore-trims"
|> Redis.query redisHandler
|> Expect.succeeds
_ <-
Redis.SortedSet.zremRangeByScore sortedSetApi "zremRangeByScore-trims" 0 2
|> Redis.query redisHandler
|> Expect.andCheck (Expect.equal 2)
Redis.SortedSet.zrange sortedSetApi "zremRangeByScore-trims" 0 (-1)
|> Redis.query redisHandler
|> Expect.andCheck (Expect.equal ["three"]),
Test.test "zrank works as expected" <| \() -> do
_ <-
Redis.SortedSet.del sortedSetApi ("zrank-works" :| [])
Expand Down Expand Up @@ -365,6 +403,23 @@ queryTests redisHandler =
Redis.SortedSet.zrank sortedSetApi "zrank-works-nothing-stored" "foobar"
|> Redis.query redisHandler
|> Expect.andCheck (Expect.equal Nothing),
Test.test "zrem removes only the named members" <| \() -> do
_ <-
Redis.SortedSet.del sortedSetApi ("zrem-removes-named" :| [])
|> Redis.query redisHandler
|> Expect.succeeds
_ <-
NonEmptyDict.init "one" 1 (Dict.fromList [("two", 2), ("three", 3)])
|> Redis.SortedSet.zadd sortedSetApi "zrem-removes-named"
|> Redis.query redisHandler
|> Expect.succeeds
_ <-
Redis.SortedSet.zrem sortedSetApi "zrem-removes-named" ("one" :| ["not-a-member"])
|> Redis.query redisHandler
|> Expect.andCheck (Expect.equal 1)
Redis.SortedSet.zrange sortedSetApi "zrem-removes-named" 0 (-1)
|> Redis.query redisHandler
|> Expect.andCheck (Expect.equal ["two", "three"]),
Test.test "scan iterates over all matching keys in batches" <| \() -> do
let firstKey = "scanTest::key1"
let firstValue = "value 1"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ TracingSpan
Just
( "rootTracingSpanIO"
, SrcLoc
{ srcLocPackage = "nri-redis-0.4.1.1-inplace-tests"
{ srcLocPackage = "nri-redis-0.4.2.0-inplace-tests"
, srcLocModule = "Spec.Redis"
, srcLocFile = "test/Spec/Redis.hs"
, srcLocStartLine = 31
Expand All @@ -29,7 +29,7 @@ TracingSpan
Just
( "query"
, SrcLoc
{ srcLocPackage = "nri-redis-0.4.1.1-inplace-tests"
{ srcLocPackage = "nri-redis-0.4.2.0-inplace-tests"
, srcLocModule = "Spec.Redis"
, srcLocFile = "test/Spec/Redis.hs"
, srcLocStartLine = 126
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ TracingSpan
Just
( "rootTracingSpanIO"
, SrcLoc
{ srcLocPackage = "nri-redis-0.4.1.1-inplace-tests"
{ srcLocPackage = "nri-redis-0.4.2.0-inplace-tests"
, srcLocModule = "Spec.Redis"
, srcLocFile = "test/Spec/Redis.hs"
, srcLocStartLine = 31
Expand All @@ -29,7 +29,7 @@ TracingSpan
Just
( "transaction"
, SrcLoc
{ srcLocPackage = "nri-redis-0.4.1.1-inplace-tests"
{ srcLocPackage = "nri-redis-0.4.2.0-inplace-tests"
, srcLocModule = "Spec.Redis"
, srcLocFile = "test/Spec/Redis.hs"
, srcLocStartLine = 133
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ TracingSpan
Just
( "rootTracingSpanIO"
, SrcLoc
{ srcLocPackage = "nri-redis-0.4.1.1-inplace-tests"
{ srcLocPackage = "nri-redis-0.4.2.0-inplace-tests"
, srcLocModule = "Spec.Redis"
, srcLocFile = "test/Spec/Redis.hs"
, srcLocStartLine = 31
Expand All @@ -29,7 +29,7 @@ TracingSpan
Just
( "query"
, SrcLoc
{ srcLocPackage = "nri-redis-0.4.1.1-inplace-tests"
{ srcLocPackage = "nri-redis-0.4.2.0-inplace-tests"
, srcLocModule = "Spec.Redis"
, srcLocFile = "test/Spec/Redis.hs"
, srcLocStartLine = 98
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ TracingSpan
Just
( "rootTracingSpanIO"
, SrcLoc
{ srcLocPackage = "nri-redis-0.4.1.1-inplace-tests"
{ srcLocPackage = "nri-redis-0.4.2.0-inplace-tests"
, srcLocModule = "Spec.Redis"
, srcLocFile = "test/Spec/Redis.hs"
, srcLocStartLine = 31
Expand All @@ -29,7 +29,7 @@ TracingSpan
Just
( "transaction"
, SrcLoc
{ srcLocPackage = "nri-redis-0.4.1.1-inplace-tests"
{ srcLocPackage = "nri-redis-0.4.2.0-inplace-tests"
, srcLocModule = "Spec.Redis"
, srcLocFile = "test/Spec/Redis.hs"
, srcLocStartLine = 105
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ TracingSpan
Just
( "rootTracingSpanIO"
, SrcLoc
{ srcLocPackage = "nri-redis-0.4.1.1-inplace-tests"
{ srcLocPackage = "nri-redis-0.4.2.0-inplace-tests"
, srcLocModule = "Spec.Redis"
, srcLocFile = "test/Spec/Redis.hs"
, srcLocStartLine = 31
Expand All @@ -29,7 +29,7 @@ TracingSpan
Just
( "query"
, SrcLoc
{ srcLocPackage = "nri-redis-0.4.1.1-inplace-tests"
{ srcLocPackage = "nri-redis-0.4.2.0-inplace-tests"
, srcLocModule = "Spec.Redis"
, srcLocFile = "test/Spec/Redis.hs"
, srcLocStartLine = 112
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ TracingSpan
Just
( "rootTracingSpanIO"
, SrcLoc
{ srcLocPackage = "nri-redis-0.4.1.1-inplace-tests"
{ srcLocPackage = "nri-redis-0.4.2.0-inplace-tests"
, srcLocModule = "Spec.Redis"
, srcLocFile = "test/Spec/Redis.hs"
, srcLocStartLine = 31
Expand All @@ -29,7 +29,7 @@ TracingSpan
Just
( "transaction"
, SrcLoc
{ srcLocPackage = "nri-redis-0.4.1.1-inplace-tests"
{ srcLocPackage = "nri-redis-0.4.2.0-inplace-tests"
, srcLocModule = "Spec.Redis"
, srcLocFile = "test/Spec/Redis.hs"
, srcLocStartLine = 119
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ TracingSpan
Just
( "rootTracingSpanIO"
, SrcLoc
{ srcLocPackage = "nri-redis-0.4.1.1-inplace-tests"
{ srcLocPackage = "nri-redis-0.4.2.0-inplace-tests"
, srcLocModule = "Spec.Redis"
, srcLocFile = "test/Spec/Redis.hs"
, srcLocStartLine = 31
Expand All @@ -29,7 +29,7 @@ TracingSpan
Just
( "query"
, SrcLoc
{ srcLocPackage = "nri-redis-0.4.1.1-inplace-tests"
{ srcLocPackage = "nri-redis-0.4.2.0-inplace-tests"
, srcLocModule = "Spec.Redis"
, srcLocFile = "test/Spec/Redis.hs"
, srcLocStartLine = 84
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ TracingSpan
Just
( "rootTracingSpanIO"
, SrcLoc
{ srcLocPackage = "nri-redis-0.4.1.1-inplace-tests"
{ srcLocPackage = "nri-redis-0.4.2.0-inplace-tests"
, srcLocModule = "Spec.Redis"
, srcLocFile = "test/Spec/Redis.hs"
, srcLocStartLine = 48
Expand All @@ -29,7 +29,7 @@ TracingSpan
Just
( "query"
, SrcLoc
{ srcLocPackage = "nri-redis-0.4.1.1-inplace-tests"
{ srcLocPackage = "nri-redis-0.4.2.0-inplace-tests"
, srcLocModule = "Spec.Redis"
, srcLocFile = "test/Spec/Redis.hs"
, srcLocStartLine = 143
Expand Down
Loading
Loading