hedis-pile-0.1.0: src/Database/Redis/Pile.hs
-- | Solution for caching mandatory data with Redis.
--
-- In many cases, requires not just pick up or put the data into the cache.
-- As a rule, data are required.
--
-- ... check the cache ... if the value is missing, run the calculations ...
-- put value to cache ... Tedious
--
-- Solution is quite simple - collapse all of these steps in one operation.
module Database.Redis.Pile (
pile
) where
import qualified Data.ByteString as B
import Control.Monad.IO.Class (liftIO)
import Control.Monad (void)
import qualified Database.Redis as R
import qualified Database.Redis.Tags as RT
-- | Stores computation results in Redis as hashSet. Computation fires only
-- if data absent in cache. Of course, to refresh the data, they must first
-- remove from the cache.
--
-- Computation controls all that will be stored in the cache. To do this,
-- except the results of computation, it may return optional @TTL@ in
-- seconds (Redis convention) and tags for key. About tags see
-- "Database.Redis.Tags".
--
-- Instead get all data from cache, optional parameter allows simply make
-- sure that cache holds HashSet with needed field with needed value. If this
-- is so, 'pile' return 'Nothing'.
--
-- > conn <- connect defaultConnectInfo
-- > runRedis conn $ do
-- > -- do it
-- > r <- pile "mykey" (Just ("etag", "etag")) $
-- > return ([("etag", "etag"), ("val", "myval")], Nothing, Nothing)
-- > liftIO $ print r
-- > -- Just [("etag", "etag"), ("val", "myval")]
-- >
-- > -- once again
-- > r <- pile "mykey" (Just ("etag", "etag")) $
-- > return ([("etag", "etag"), ("val", "myval")], Nothing, Nothing)
-- > liftIO $ print r
-- > -- Nothing
-- >
-- > -- and again without expect
-- > r <- pile "mykey" Nothing $
-- > return ([("etag", "etag"), ("val", "myval")], Nothing, Nothing)
-- > liftIO $ print r
-- > -- Just [("etag", "etag"), ("val", "myval")]
pile ::
B.ByteString
-- ^ Key in cache.
-> Maybe (B.ByteString, B.ByteString)
-- ^ Optional expect field.
-> IO ([(B.ByteString, B.ByteString)],
Maybe Integer,
Maybe (B.ByteString, [B.ByteString]))
-- ^ Computation that returns data and
-- optional TTL and tags.
-> R.Redis (Maybe [(B.ByteString, B.ByteString)])
pile key (Just (ef, ev)) f = do
e <- R.hget key ef
case e of
Right (Just ev') | ev' == ev -> return Nothing
| otherwise -> pile key Nothing f
_ -> pile key Nothing f
pile key Nothing f = do
d <- R.hgetall key
case d of
Right [] -> runF
Right r -> return $ Just r
_ -> runF
where
runF = do
(r, ke, t) <- liftIO f
void $ R.hmset key r
setExpire ke
setTags t
return $ Just r
where
setExpire Nothing = return ()
setExpire (Just ke) = void $ R.expire key ke
setTags Nothing = return ()
setTags (Just (p, ts)) = RT.markTags [key] p ts