----------------------------------------------------------------------------- -- | -- Module : Database.PostgreSQL.Simple.URL -- Copyright : 2014-2018 © Futurice OY, Oleg Grenrus -- License : MIT (see the file LICENSE) -- -- Maintainer : Oleg Grenrus -- ---------------------------------------------------------------------------- module Database.PostgreSQL.Simple.URL (parseDatabaseUrl, uriToConnectInfo) where import Control.Applicative import Data.List.Split import Database.PostgreSQL.Simple import Network.URI import Prelude -- | Parse string url into `ConnectInfo`. -- -- >>> parseDatabaseUrl "postgres://foo:bar@example.com:2345/database" -- Just (ConnectInfo {connectHost = "example.com", connectPort = 2345, connectUser = "foo", connectPassword = "bar", connectDatabase = "database"}) -- -- >>> parseDatabaseUrl "postgresql://foo:bar@example.com:2345/database" -- Just (ConnectInfo {connectHost = "example.com", connectPort = 2345, connectUser = "foo", connectPassword = "bar", connectDatabase = "database"}) -- parseDatabaseUrl :: String -> Maybe ConnectInfo parseDatabaseUrl databaseUrl = parseURI databaseUrl >>= uriToConnectInfo uriToConnectInfo :: URI -> Maybe ConnectInfo uriToConnectInfo uri | uriScheme uri /= "postgres:" && uriScheme uri /= "postgresql:" = Nothing | otherwise = ($ defaultConnectInfo) <$> mkConnectInfo uri type ConnectInfoChange = ConnectInfo -> ConnectInfo mkConnectInfo :: URI -> Maybe ConnectInfoChange mkConnectInfo uri = case uriPath uri of ('/' : rest) | not (null rest) -> Just $ uriParameters uri _ -> Nothing uriParameters :: URI -> ConnectInfoChange uriParameters uri = (\info -> info { connectDatabase = tail $ uriPath uri }) . maybe id uriAuthParameters (uriAuthority uri) dropLast :: [a] -> [a] dropLast [] = [] dropLast [_] = [] dropLast (x:xs) = x : dropLast xs uriAuthParameters :: URIAuth -> ConnectInfoChange uriAuthParameters uriAuth = port . host . auth where port = case uriPort uriAuth of (':' : p) -> \info -> info { connectPort = read p } _ -> id host = case uriRegName uriAuth of h -> \info -> info { connectHost = h } auth = case splitOn ":" (uriUserInfo uriAuth) of [""] -> id [u] -> \info -> info { connectUser = dropLast u } [u, p] -> \info -> info { connectUser = u, connectPassword = dropLast p } _ -> id