Skip to content

Commit e91cf41

Browse files
committed
Added scan commands
1 parent d0dd9f2 commit e91cf41

File tree

3 files changed

+137
-8
lines changed

3 files changed

+137
-8
lines changed

codegen/GenCmds.hs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -86,10 +86,10 @@ blacklist = [ manual "AUTH" ["auth"]
8686
["Condition", "SetOpts(..)"]
8787
, manualWithType "ZADD"
8888
["zadd", "zaddOpts"]
89-
["ZaddOpts(..)"]
89+
["ZaddOpts(..)", "defaultZaddOpts"]
9090
, manualWithType "MIGRATE"
9191
["migrate", "migrateMultiple"]
92-
["MigrateOpts(..)"]
92+
["MigrateOpts(..)", "defaultMigrateOpts"]
9393
, manual "RESTORE"
9494
["restore", "restoreReplace"]
9595
, manualWithType "CLIENT REPLY"
@@ -102,14 +102,16 @@ blacklist = [ manual "AUTH" ["auth"]
102102
, manual "SPOP" ["spop"]
103103
, manual "INFO" ["info", "infoSection"]
104104
, manual "EXISTS" ["exists"]
105+
, manualWithType "SCAN"
106+
["scan", "scanOpts"]
107+
["Cursor", "cursor0", "ScanOpts(..)", "defaultScanOpts"]
108+
, manual "SSCAN" ["sscan", "sscanOpts"]
109+
, manual "HSCAN" ["hscan", "hscanOpts"]
110+
, manual "ZSCAN" ["zscan", "zscanOpts"]
105111
, unimplemented "COMMAND"
106112
, unimplemented "COMMAND GETKEYS"
107113
, unimplemented "ROLE"
108114
, unimplemented "CLIENT KILL"
109-
, unimplemented "SCAN"
110-
, unimplemented "SSCAN"
111-
, unimplemented "HSCAN"
112-
, unimplemented "ZSCAN"
113115
, unimplemented "ZRANGEBYLEX"
114116
, unimplemented "ZREVRANGEBYLEX"
115117
, unimplemented "ZRANGEBYSCORE"

src/Database/Redis/ManualCommands.hs

Lines changed: 115 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -318,7 +318,7 @@ zstoreInternal
318318
-> ByteString -- ^ destination
319319
-> [ByteString] -- ^ keys
320320
-> [Double] -- ^ weights
321-
-> Aggregate
321+
-> Aggregate
322322
-> m (f Integer)
323323
zstoreInternal cmd dest keys weights aggregate = sendRequest $
324324
concat [ [cmd, dest, encode . toInteger $ length keys], keys
@@ -638,3 +638,117 @@ exists
638638
=> ByteString -- ^ key
639639
-> m (f Bool)
640640
exists key = sendRequest ["EXISTS", key]
641+
642+
newtype Cursor = Cursor ByteString deriving (Show, Eq)
643+
644+
645+
instance RedisArg Cursor where
646+
encode (Cursor c) = encode c
647+
648+
649+
instance RedisResult Cursor where
650+
decode (Bulk (Just s)) = Right $ Cursor s
651+
decode r = Left r
652+
653+
654+
cursor0 :: Cursor
655+
cursor0 = Cursor "0"
656+
657+
658+
scan
659+
:: (RedisCtx m f)
660+
=> Cursor
661+
-> m (f (Cursor, [ByteString])) -- ^ next cursor and values
662+
scan cursor = scanOpts cursor defaultScanOpts
663+
664+
665+
data ScanOpts = ScanOpts
666+
{ scanMatch :: Maybe ByteString
667+
, scanCount :: Maybe Integer
668+
} deriving (Show, Eq)
669+
670+
671+
-- |Redis default 'ScanOpts'. Equivalent to omitting all optional parameters.
672+
--
673+
-- @
674+
-- ScanOpts
675+
-- { scanMatch = Nothing -- don't match any pattern
676+
-- , scanCount = Nothing -- don't set any requirements on number elements returned (works like value @COUNT 10@)
677+
-- }
678+
-- @
679+
--
680+
defaultScanOpts :: ScanOpts
681+
defaultScanOpts = ScanOpts
682+
{ scanMatch = Nothing
683+
, scanCount = Nothing
684+
}
685+
686+
687+
scanOpts
688+
:: (RedisCtx m f)
689+
=> Cursor
690+
-> ScanOpts
691+
-> m (f (Cursor, [ByteString])) -- ^ next cursor and values
692+
scanOpts cursor opts = sendRequest $ addScanOpts ["SCAN", encode cursor] opts
693+
694+
695+
addScanOpts
696+
:: [ByteString] -- ^ main part of scan command
697+
-> ScanOpts
698+
-> [ByteString]
699+
addScanOpts cmd ScanOpts{..} =
700+
concat [cmd, match, count]
701+
where
702+
match = maybeToList scanMatch
703+
count = map encode $ maybeToList scanCount
704+
705+
706+
sscan
707+
:: (RedisCtx m f)
708+
=> ByteString -- ^ key
709+
-> Cursor
710+
-> m (f (Cursor, [ByteString])) -- ^ next cursor and values
711+
sscan key cursor = sscanOpts key cursor defaultScanOpts
712+
713+
714+
sscanOpts
715+
:: (RedisCtx m f)
716+
=> ByteString -- ^ key
717+
-> Cursor
718+
-> ScanOpts
719+
-> m (f (Cursor, [ByteString])) -- ^ next cursor and values
720+
sscanOpts key cursor opts = sendRequest $ addScanOpts ["SSCAN", key, encode cursor] opts
721+
722+
723+
hscan
724+
:: (RedisCtx m f)
725+
=> ByteString -- ^ key
726+
-> Cursor
727+
-> m (f (Cursor, [(ByteString, ByteString)])) -- ^ next cursor and values
728+
hscan key cursor = hscanOpts key cursor defaultScanOpts
729+
730+
731+
hscanOpts
732+
:: (RedisCtx m f)
733+
=> ByteString -- ^ key
734+
-> Cursor
735+
-> ScanOpts
736+
-> m (f (Cursor, [(ByteString, ByteString)])) -- ^ next cursor and values
737+
hscanOpts key cursor opts = sendRequest $ addScanOpts ["HSCAN", key, encode cursor] opts
738+
739+
740+
zscan
741+
:: (RedisCtx m f)
742+
=> ByteString -- ^ key
743+
-> Cursor
744+
-> m (f (Cursor, [(ByteString, Double)])) -- ^ next cursor and values
745+
zscan key cursor = zscanOpts key cursor defaultScanOpts
746+
747+
748+
zscanOpts
749+
:: (RedisCtx m f)
750+
=> ByteString -- ^ key
751+
-> Cursor
752+
-> ScanOpts
753+
-> m (f (Cursor, [(ByteString, Double)])) -- ^ next cursor and values
754+
zscanOpts key cursor opts = sendRequest $ addScanOpts ["ZSCAN", key, encode cursor] opts

test/Test.hs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,9 @@ tests :: Connection -> [Test.Test]
5656
tests conn = map ($conn) $ concat
5757
[ testsMisc, testsKeys, testsStrings, [testHashes], testsLists, testsSets, [testHyperLogLog]
5858
, testsZSets, [testPubSub], [testTransaction], [testScripting]
59-
, testsConnection, testsServer, [testQuit]
59+
, testsConnection, testsServer, [testScans]
60+
-- should always be run last as connection gets closed after it
61+
, [testQuit]
6062
]
6163

6264
------------------------------------------------------------------------------
@@ -521,3 +523,14 @@ testDebugObject = testCase "debugObject/debugSegfault" $ do
521523
set "key" "value" >>=? Ok
522524
Right _ <- debugObject "key"
523525
return ()
526+
527+
testScans :: Test
528+
testScans = testCase "cursors" $ do
529+
set "key" "value" >>=? Ok
530+
scan cursor0 >>=? (cursor0, ["key"])
531+
sadd "set" ["1"] >>=? 1
532+
sscan "set" cursor0 >>=? (cursor0, ["1"])
533+
hset "hash" "k" "v" >>=? True
534+
hscan "hash" cursor0 >>=? (cursor0, [("k", "v")])
535+
zadd "zset" [(42, "2")] >>=? 1
536+
zscan "zset" cursor0 >>=? (cursor0, [("2", 42)])

0 commit comments

Comments
 (0)