-- | Important: it is required that the Hashable and Eq instances used for HashSet respect
-- whatever is used for serialization, since Redis will decide equality only on serialized values.

module HLRDB.Structures.Set where

import Data.Hashable
import Data.HashSet as S
import Database.Redis as Redis
import HLRDB.Primitives.Redis
import HLRDB.Internal


-- | Retrieve the elements of a set from Redis
smembers :: (MonadRedis m , Eq b , Hashable b) => RedisSet a b -> a -> m (HashSet b)
smembers :: RedisSet a b -> a -> m (HashSet b)
smembers p :: RedisSet a b
p@(RSet (E a -> ByteString
_ b -> Identity ByteString
_ Identity ByteString -> b
d)) =
    ([ByteString] -> HashSet b) -> m [ByteString] -> m (HashSet b)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ([b] -> HashSet b
forall a. (Eq a, Hashable a) => [a] -> HashSet a
S.fromList ([b] -> HashSet b)
-> ([ByteString] -> [b]) -> [ByteString] -> HashSet b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (ByteString -> b) -> [ByteString] -> [b]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Identity ByteString -> b
d (Identity ByteString -> b)
-> (ByteString -> Identity ByteString) -> ByteString -> b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Identity ByteString
forall (f :: * -> *) a. Applicative f => a -> f a
pure))
  (m [ByteString] -> m (HashSet b))
-> (a -> m [ByteString]) -> a -> m (HashSet b)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Redis (Either Reply [ByteString]) -> m [ByteString]
forall (m :: * -> *) a.
MonadRedis m =>
Redis (Either Reply a) -> m a
unwrap
  (Redis (Either Reply [ByteString]) -> m [ByteString])
-> (a -> Redis (Either Reply [ByteString])) -> a -> m [ByteString]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Redis (Either Reply [ByteString])
forall (m :: * -> *) (f :: * -> *).
RedisCtx m f =>
ByteString -> m (f [ByteString])
Redis.smembers
  (ByteString -> Redis (Either Reply [ByteString]))
-> (a -> ByteString) -> a -> Redis (Either Reply [ByteString])
forall b c a. (b -> c) -> (a -> b) -> a -> c
. RedisSet a b -> a -> ByteString
forall v a b. RedisStructure v a b -> a -> ByteString
primKey RedisSet a b
p

-- | Test if an item is a member of a set
sismember :: MonadRedis m => RedisSet a b -> a -> b -> m Bool
sismember :: RedisSet a b -> a -> b -> m Bool
sismember p :: RedisSet a b
p@(RSet (E a -> ByteString
_ b -> Identity ByteString
e Identity ByteString -> b
_)) a
k =
    Redis (Either Reply Bool) -> m Bool
forall (m :: * -> *) a.
MonadRedis m =>
Redis (Either Reply a) -> m a
unwrap
  (Redis (Either Reply Bool) -> m Bool)
-> (b -> Redis (Either Reply Bool)) -> b -> m Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> ByteString -> Redis (Either Reply Bool)
forall (m :: * -> *) (f :: * -> *).
RedisCtx m f =>
ByteString -> ByteString -> m (f Bool)
Redis.sismember (RedisSet a b -> a -> ByteString
forall v a b. RedisStructure v a b -> a -> ByteString
primKey RedisSet a b
p a
k)
  (ByteString -> Redis (Either Reply Bool))
-> (b -> ByteString) -> b -> Redis (Either Reply Bool)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Identity ByteString -> ByteString
forall a. Identity a -> a
runIdentity
  (Identity ByteString -> ByteString)
-> (b -> Identity ByteString) -> b -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. b -> Identity ByteString
e

-- | Add items to a set
sadd :: (MonadRedis m , Traversable t) => RedisSet a b -> a -> t b -> m ()
sadd :: RedisSet a b -> a -> t b -> m ()
sadd p :: RedisSet a b
p@(RSet (E a -> ByteString
_ b -> Identity ByteString
e Identity ByteString -> b
_)) a
k =
  ([ByteString] -> Redis ()) -> (b -> ByteString) -> t b -> m ()
forall (m :: * -> *) e (t :: * -> *) b a.
(MonadRedis m, Monoid e, Traversable t) =>
([b] -> Redis e) -> (a -> b) -> t a -> m e
fixEmpty (Redis Integer -> Redis ()
forall (f :: * -> *) a. Functor f => f a -> f ()
ignore (Redis Integer -> Redis ())
-> ([ByteString] -> Redis Integer) -> [ByteString] -> Redis ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Redis (Either Reply Integer) -> Redis Integer
forall (m :: * -> *) a.
MonadRedis m =>
Redis (Either Reply a) -> m a
unwrap (Redis (Either Reply Integer) -> Redis Integer)
-> ([ByteString] -> Redis (Either Reply Integer))
-> [ByteString]
-> Redis Integer
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> [ByteString] -> Redis (Either Reply Integer)
forall (m :: * -> *) (f :: * -> *).
RedisCtx m f =>
ByteString -> [ByteString] -> m (f Integer)
Redis.sadd (RedisSet a b -> a -> ByteString
forall v a b. RedisStructure v a b -> a -> ByteString
primKey RedisSet a b
p a
k)) (Identity ByteString -> ByteString
forall a. Identity a -> a
runIdentity (Identity ByteString -> ByteString)
-> (b -> Identity ByteString) -> b -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. b -> Identity ByteString
e)

-- | Remove items from a set
srem :: (MonadRedis m , Traversable t) => RedisSet a b -> a -> t b -> m ()
srem :: RedisSet a b -> a -> t b -> m ()
srem p :: RedisSet a b
p@(RSet (E a -> ByteString
_ b -> Identity ByteString
e Identity ByteString -> b
_)) a
k =
  ([ByteString] -> Redis ()) -> (b -> ByteString) -> t b -> m ()
forall (m :: * -> *) e (t :: * -> *) b a.
(MonadRedis m, Monoid e, Traversable t) =>
([b] -> Redis e) -> (a -> b) -> t a -> m e
fixEmpty (Redis Integer -> Redis ()
forall (f :: * -> *) a. Functor f => f a -> f ()
ignore (Redis Integer -> Redis ())
-> ([ByteString] -> Redis Integer) -> [ByteString] -> Redis ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Redis (Either Reply Integer) -> Redis Integer
forall (m :: * -> *) a.
MonadRedis m =>
Redis (Either Reply a) -> m a
unwrap (Redis (Either Reply Integer) -> Redis Integer)
-> ([ByteString] -> Redis (Either Reply Integer))
-> [ByteString]
-> Redis Integer
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> [ByteString] -> Redis (Either Reply Integer)
forall (m :: * -> *) (f :: * -> *).
RedisCtx m f =>
ByteString -> [ByteString] -> m (f Integer)
Redis.srem (RedisSet a b -> a -> ByteString
forall v a b. RedisStructure v a b -> a -> ByteString
primKey RedisSet a b
p a
k)) (Identity ByteString -> ByteString
forall a. Identity a -> a
runIdentity (Identity ByteString -> ByteString)
-> (b -> Identity ByteString) -> b -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. b -> Identity ByteString
e)

-- | Retrieve the cardinality of a set
scard :: MonadRedis m => RedisSet a b -> a -> m Integer
scard :: RedisSet a b -> a -> m Integer
scard RedisSet a b
p =
    Redis (Either Reply Integer) -> m Integer
forall (m :: * -> *) a.
MonadRedis m =>
Redis (Either Reply a) -> m a
unwrap
  (Redis (Either Reply Integer) -> m Integer)
-> (a -> Redis (Either Reply Integer)) -> a -> m Integer
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Redis (Either Reply Integer)
forall (m :: * -> *) (f :: * -> *).
RedisCtx m f =>
ByteString -> m (f Integer)
Redis.scard
  (ByteString -> Redis (Either Reply Integer))
-> (a -> ByteString) -> a -> Redis (Either Reply Integer)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. RedisSet a b -> a -> ByteString
forall v a b. RedisStructure v a b -> a -> ByteString
primKey RedisSet a b
p

-- | Retrieve a random element from a set. The underlying Redis primitive uses a poor but efficient distribution, biased by the underlying hash bucket allocation.
srandmember :: MonadRedis m => RedisSet a b -> a -> m (Maybe b)
srandmember :: RedisSet a b -> a -> m (Maybe b)
srandmember p :: RedisSet a b
p@(RSet (E a -> ByteString
_ b -> Identity ByteString
_ Identity ByteString -> b
d)) =
    ((Maybe ByteString -> Maybe b)
-> m (Maybe ByteString) -> m (Maybe b)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ((Maybe ByteString -> Maybe b)
 -> m (Maybe ByteString) -> m (Maybe b))
-> ((ByteString -> b) -> Maybe ByteString -> Maybe b)
-> (ByteString -> b)
-> m (Maybe ByteString)
-> m (Maybe b)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (ByteString -> b) -> Maybe ByteString -> Maybe b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap) (Identity ByteString -> b
d (Identity ByteString -> b)
-> (ByteString -> Identity ByteString) -> ByteString -> b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Identity ByteString
forall (f :: * -> *) a. Applicative f => a -> f a
pure)
  (m (Maybe ByteString) -> m (Maybe b))
-> (a -> m (Maybe ByteString)) -> a -> m (Maybe b)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Redis (Either Reply (Maybe ByteString)) -> m (Maybe ByteString)
forall (m :: * -> *) a.
MonadRedis m =>
Redis (Either Reply a) -> m a
unwrap
  (Redis (Either Reply (Maybe ByteString)) -> m (Maybe ByteString))
-> (a -> Redis (Either Reply (Maybe ByteString)))
-> a
-> m (Maybe ByteString)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Redis (Either Reply (Maybe ByteString))
forall (m :: * -> *) (f :: * -> *).
RedisCtx m f =>
ByteString -> m (f (Maybe ByteString))
Redis.srandmember
  (ByteString -> Redis (Either Reply (Maybe ByteString)))
-> (a -> ByteString)
-> a
-> Redis (Either Reply (Maybe ByteString))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. RedisSet a b -> a -> ByteString
forall v a b. RedisStructure v a b -> a -> ByteString
primKey RedisSet a b
p

-- | Retrieve up to N unique random elements, limited by the cardinality of the set.
srandmemberN :: MonadRedis m => RedisSet a b -> Integer -> a -> m [ b ]
srandmemberN :: RedisSet a b -> Integer -> a -> m [b]
srandmemberN p :: RedisSet a b
p@(RSet (E a -> ByteString
_ b -> Identity ByteString
_ Identity ByteString -> b
d)) Integer
n =
    (([ByteString] -> [b]) -> m [ByteString] -> m [b]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (([ByteString] -> [b]) -> m [ByteString] -> m [b])
-> ((ByteString -> b) -> [ByteString] -> [b])
-> (ByteString -> b)
-> m [ByteString]
-> m [b]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (ByteString -> b) -> [ByteString] -> [b]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap) (Identity ByteString -> b
d (Identity ByteString -> b)
-> (ByteString -> Identity ByteString) -> ByteString -> b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Identity ByteString
forall (f :: * -> *) a. Applicative f => a -> f a
pure)
  (m [ByteString] -> m [b]) -> (a -> m [ByteString]) -> a -> m [b]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Redis (Either Reply [ByteString]) -> m [ByteString]
forall (m :: * -> *) a.
MonadRedis m =>
Redis (Either Reply a) -> m a
unwrap
  (Redis (Either Reply [ByteString]) -> m [ByteString])
-> (a -> Redis (Either Reply [ByteString])) -> a -> m [ByteString]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (ByteString -> Integer -> Redis (Either Reply [ByteString]))
-> Integer -> ByteString -> Redis (Either Reply [ByteString])
forall a b c. (a -> b -> c) -> b -> a -> c
flip ByteString -> Integer -> Redis (Either Reply [ByteString])
forall (m :: * -> *) (f :: * -> *).
RedisCtx m f =>
ByteString -> Integer -> m (f [ByteString])
Redis.srandmemberN Integer
n
  (ByteString -> Redis (Either Reply [ByteString]))
-> (a -> ByteString) -> a -> Redis (Either Reply [ByteString])
forall b c a. (b -> c) -> (a -> b) -> a -> c
. RedisSet a b -> a -> ByteString
forall v a b. RedisStructure v a b -> a -> ByteString
primKey RedisSet a b
p

-- | Use a cursor to iterate a collection
sscan :: MonadRedis m => RedisSet a b -> a -> Cursor -> m (Maybe Cursor , [ b ])
sscan :: RedisSet a b -> a -> Cursor -> m (Maybe Cursor, [b])
sscan p :: RedisSet a b
p@(RSet (E a -> ByteString
_ b -> Identity ByteString
_ Identity ByteString -> b
d)) a
k =
    ([ByteString] -> [b])
-> Redis (Either Reply (Cursor, [ByteString]))
-> m (Maybe Cursor, [b])
forall (m :: * -> *) a b.
MonadRedis m =>
(a -> b) -> Redis (Either Reply (Cursor, a)) -> m (Maybe Cursor, b)
unwrapCursor ((ByteString -> b) -> [ByteString] -> [b]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Identity ByteString -> b
d (Identity ByteString -> b)
-> (ByteString -> Identity ByteString) -> ByteString -> b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Identity ByteString
forall (f :: * -> *) a. Applicative f => a -> f a
pure))
  (Redis (Either Reply (Cursor, [ByteString]))
 -> m (Maybe Cursor, [b]))
-> (Cursor -> Redis (Either Reply (Cursor, [ByteString])))
-> Cursor
-> m (Maybe Cursor, [b])
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Cursor -> Redis (Either Reply (Cursor, [ByteString]))
forall (m :: * -> *) (f :: * -> *).
RedisCtx m f =>
ByteString -> Cursor -> m (f (Cursor, [ByteString]))
Redis.sscan (RedisSet a b -> a -> ByteString
forall v a b. RedisStructure v a b -> a -> ByteString
primKey RedisSet a b
p a
k)