module HLRDB.Internal
(
probIO
, primKey
, unwrap
, unwrapCursor
, unwrapCreatedBool
, unwrapCreated
, unwrapDeleted
, ignore
, fixEmpty
, fixEmpty'
, foldM
, decodeMInteger
, readInt
, Int64
, runIdentity
, MSET(..)
, HLRDB.Internal.splitWith
) where
import Data.Functor.Identity
import Database.Redis
import Data.ByteString hiding (foldr)
import HLRDB.Primitives.Redis
import qualified Data.ByteString as S
import qualified Data.ByteString.Unsafe as B
import GHC.Int
import Control.Monad.IO.Class
import System.Random (randomRIO)
probIO :: (MonadIO m) => Double -> m a -> m (Maybe a)
probIO pr a =
if pr >= 1.0 then Just <$> a else do
r :: Double <- liftIO $ randomRIO (0, 1.0)
if r <= pr
then Just <$> a
else return Nothing
{-# INLINE primKey #-}
primKey :: RedisStructure v a b -> a -> ByteString
primKey (RKeyValue (E e _ _)) k = e k
primKey (RKeyValueInteger e _ _) k = e k
primKey (RList (E e _ _) _) k = e k
primKey (RHSet (E e _ _) _) k = e k
primKey (RSet (E e _ _)) k = e k
primKey (RSortedSet (E e _ _) _) k = e k
failRedis :: Reply -> Redis a
failRedis = fail . (++) "Unexpected Redis response: " . show
{-# INLINE unwrap #-}
unwrap :: MonadRedis m => Redis (Either Reply a) -> m a
unwrap r = do
res <- liftRedis r
case res of
Left e -> liftRedis $ failRedis e
Right i -> return i
{-# INLINE unwrapCursor #-}
unwrapCursor :: MonadRedis m => (a -> b) -> Redis (Either Reply (Cursor , a)) -> m (Maybe Cursor , b)
unwrapCursor f =
let g (c , x) = (if c == cursor0 then Nothing else Just c , f x) in
fmap g . unwrap
{-# INLINE unwrapCreatedBool #-}
unwrapCreatedBool :: MonadRedis m => Redis (Either Reply Bool) -> m (ActionPerformed Creation)
unwrapCreatedBool = fmap (\b -> if b then FreshlyCreated 1 else FreshlyCreated 0) . unwrap
{-# INLINE unwrapCreated #-}
unwrapCreated :: MonadRedis m => Redis (Either Reply Integer) -> m (ActionPerformed Creation)
unwrapCreated = fmap FreshlyCreated . unwrap
{-# INLINE unwrapDeleted #-}
unwrapDeleted :: MonadRedis m => Redis (Either Reply Integer) -> m (ActionPerformed Deletion)
unwrapDeleted = fmap Deleted . unwrap
{-# INLINE ignore #-}
ignore :: Functor f => f a -> f ()
ignore = fmap (const ())
{-# INLINE fixEmpty #-}
fixEmpty :: (MonadRedis m , Monoid e, Traversable t) => ([ b ] -> Redis e) -> (a -> b) -> t a -> m e
fixEmpty f e t = case foldr ((:) . e) [] t of
[] -> pure mempty
xs -> liftRedis $ f xs
{-# INLINE fixEmpty' #-}
fixEmpty' :: (MonadRedis m, Traversable t, Integral i) => ([ b ] -> Redis i) -> (a -> b) -> t a -> m i
fixEmpty' f e t = case foldr ((:) . e) [] t of
[] -> pure 0
xs -> liftRedis $ f xs
{-# INLINE foldM #-}
foldM :: (Foldable t) => (a -> b) -> t a -> [ b ]
foldM f t = foldr (\a xs -> f a : xs) [] t
decodeMInteger :: Maybe ByteString -> Int64
decodeMInteger Nothing = 0
decodeMInteger (Just bs) = readInt bs
readInt :: ByteString -> Int64
readInt as
| S.null as = 0
| otherwise =
case B.unsafeHead as of
45 -> loop True 0 0 (B.unsafeTail as)
43 -> loop False 0 0 (B.unsafeTail as)
_ -> loop False 0 0 as
where
loop :: Bool -> Int64 -> Int64 -> S.ByteString -> Int64
loop neg !i !n !ps
| S.null ps = end neg i n
| otherwise =
case B.unsafeHead ps of
w
| w >= 0x30 && w <= 0x39 ->
loop
neg
(i + 1)
(n * 10 + (fromIntegral w - 0x30))
(B.unsafeTail ps)
| otherwise -> end neg i n
end _ 0 _ = 0
end True _ n = negate n
end _ _ n = n
type DList a = ([ a ] -> [ a ])
newtype MSET = MSET { runMSET :: DList (ByteString , Maybe ByteString) }
instance Semigroup MSET where
(<>) (MSET as) (MSET bs) = MSET (as . bs)
instance Monoid MSET where
mempty = MSET $ (<>) []
splitWith :: (a -> Either b c) -> [ a ] -> ([ b ] , [ c ])
splitWith f = foldr g mempty
where
g x (as , bs) = case f x of
Left a -> (a : as , bs)
Right b -> (as , b : bs)