cqrs-example-0.8.0: src/CQRSExample/WaiParameters.hs
module CQRSExample.WaiParameters
( runParameters
, lookGUID
, requireBool
, requireDay
, requireDuration
, requireGUID
, requireText
) where
import Control.Applicative ((<*>))
import Control.Monad (liftM)
import Control.Monad.Trans.Resource (ResourceT)
import Control.Monad.Trans.Reader (ask, ReaderT, runReaderT)
import Data.ByteString (ByteString)
import qualified Data.ByteString.Char8 as B8
import Data.Conduit (($$))
import Data.CQRS
import Data.CQRS.GUID (hexDecode)
import Data.Text (Text)
import qualified Data.Text.Encoding as TE
import Data.Time (Day)
import Data.Time.Format (parseTime)
import Network.HTTP.Types (Query)
import Network.Wai (Application, Request, Response, queryString, requestBody)
import Network.Wai.Parse (lbsSink, parseRequestBody, Param)
import Prelude hiding (mapM)
import System.Locale (defaultTimeLocale)
import CQRSExample.Duration (Duration)
import qualified CQRSExample.Duration as D
-- Type of the monad.
type ParametersT = ReaderT ([Param], Query)
runParameters :: ParametersT (ResourceT IO) Response -> Application
runParameters r req = do
-- TODO: Impose a max body length.
(params, _) <- requestBody req $$ parseRequestBody lbsSink req
runReaderT r (params, queryString req)
look :: Monad m => ByteString -> ParametersT m (Maybe ByteString)
look n = do
(ps, qs) <- ask
let mq = lookup n qs
let mp = lookup n ps
return $ maybe mp id mq
required :: Monad m => ByteString -> ParametersT m (Maybe a) -> ParametersT m a
required n = flip (>>=) require
where
require (Just a) = return a
require Nothing = fail $ "Missing/invalid parameter '" ++ (B8.unpack n) ++ "'"
lookText :: Monad m => ByteString -> ParametersT m (Maybe Text)
lookText n = liftM (maybe Nothing decode) $ look n
where decode = either (const Nothing) Just . TE.decodeUtf8'
requireText :: Monad m => ByteString -> ParametersT m Text
requireText = required <*> lookText
lookGUID :: Monad m => ByteString -> ParametersT m (Maybe GUID)
lookGUID n = liftM (maybe Nothing hexDecode) $ look n
requireGUID :: Monad m => ByteString -> ParametersT m GUID
requireGUID = required <*> lookGUID
lookInteger :: Monad m => ByteString -> ParametersT m (Maybe Integer)
lookInteger n = liftM (maybe Nothing (f . B8.readInteger)) $ look n
where
f (Just (x, "")) = Just x
f _ = Nothing
requiredInteger :: Monad m => ByteString -> ParametersT m Integer
requiredInteger = required <*> lookInteger
requireDuration :: Monad m => ByteString -> ParametersT m Duration
requireDuration n = liftM D.minutes $ requiredInteger n
lookDay :: Monad m => ByteString -> ParametersT m (Maybe Day)
lookDay n = liftM (maybe Nothing parseDay) $ look n
where parseDay = parseTime defaultTimeLocale "%F" . B8.unpack
requireDay :: Monad m => ByteString -> ParametersT m Day
requireDay = required <*> lookDay
lookBool :: Monad m => ByteString -> ParametersT m (Maybe Bool)
lookBool n = liftM f $ look n
where
f (Just "true") = Just True
f (Just "false") = Just False
f _ = Nothing
requireBool :: Monad m => ByteString -> ParametersT m Bool
requireBool = required <*> lookBool