{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE OverloadedStrings #-} module Database.Persist.URL ( fromDatabaseUrl ) where import Control.Monad (MonadPlus, mzero, unless) import Data.ByteString (ByteString, uncons) import Data.Monoid ((<>)) import Data.String.Conversions (ConvertibleStrings(..)) import Data.String.Conversions.Monomorphic (toStrictByteString) import Database.Persist.Postgresql (PostgresConf(..)) import URI.ByteString ( Authority(..) , Host(..) , Port(..) , URI(..) , UserInfo(..) , Scheme(..) , parseURI , strictURIParserOptions ) import qualified Data.ByteString.Char8 as Char8 -- | Build a @'PostgresConf'@ by parsing a database URL String fromDatabaseUrl :: (MonadPlus m, ConvertibleStrings s ByteString) => Int -> s -> m PostgresConf fromDatabaseUrl size url = do uri <- abortLeft $ parseURI strictURIParserOptions $ toStrictByteString url auth <- abortNothing $ uriAuthority uri userInfo <- abortNothing $ authorityUserInfo auth port <- abortNothing $ authorityPort auth dbName <- abortNothing $ snd <$> uncons (uriPath uri) unless (schemeBS (uriScheme uri) == "postgres") mzero return PostgresConf { pgConnStr = "user=" <> uiUsername userInfo <> " password=" <> uiPassword userInfo <> " host=" <> hostBS (authorityHost auth) <> " port=" <> Char8.pack (show $ portNumber port) <> " dbname=" <> dbName , pgPoolSize = size } abortLeft :: (MonadPlus m, Show e) => Either e b -> m b abortLeft = either (const mzero) return abortNothing :: MonadPlus m => Maybe a -> m a abortNothing = maybe mzero return