{- | Module : Servant.Context.PostgreSQL Copyright : (c) Zalora SEA 2014 License : BSD3 Maintainer : Alp Mestanogullari Stability : experimental Useful functions and instances for using servant with a PostgreSQL database. * Use 'contextOfConnInfo' or 'contextOfConnStr' to create a PostgreSQL 'Context's. * If you want connection-pooling, use 'pooledContextOfConnInfo' and 'pooledContextOfConnStr'. -} module Servant.Context.PostgreSQL ( -- * PostgreSQL 'Context' contextOfConnInfo , contextOfConnStr , -- * PostgreSQL 'Context' with connection pooling pooledContextOfConnInfo , pooledContextOfConnStr ) where import Control.Exception import Data.ByteString (ByteString) import Database.PostgreSQL.Simple import Servant.Context import Servant.Context.Pool -- | Create a @'Context' 'Connection'@ from the given -- 'ConnectInfo'. -- -- This means a new connection will be fired whenever you -- perform a database operation. If you want to avoid that, -- see the /pooledContextOfXXX/ functions. contextOfConnInfo :: ConnectInfo -> Context Connection contextOfConnInfo ci = mkContext f where f act = bracket (connect ci) close act -- | Create a @'Context' 'Connection'@ from the given -- connection string. -- -- This means a new connection will be fired whenever you -- perform a database operation. If you want to avoid that, -- see the /pooledContextOfXXX/ functions. contextOfConnStr :: ByteString -> Context Connection contextOfConnStr str = mkContext f where f act = bracket (connectPostgreSQL str) close act -- | Create a 'Context' that'll use a 'Pool' of -- PostgreSQL 'Connection's internally, from -- a 'ConnectInfo' value. pooledContextOfConnInfo :: Int -- ^ Number of stripes (sub-pools). /Minimum: 1/ -> NominalDiffTime -- ^ amount of time during which an unused -- 'Connection' is kept open -> Int -- ^ Maximum number of resources to keep open -- per stripe. /Minimum: 1/ -> ConnectInfo -- ^ connection information -> IO (Context Connection) pooledContextOfConnInfo nstripes idleDuration maxOpen ci = pooledContext (connect ci) close nstripes idleDuration maxOpen -- | Create a 'Context' that'll use a 'Pool' of -- PostgreSQL 'Connection's internally, from -- a connection string (a 'ByteString'). pooledContextOfConnStr :: Int -- ^ Number of stripes (sub-pools). /Minimum: 1/ -> NominalDiffTime -- ^ amount of time during which an unused -- 'Connection' is kept open -> Int -- ^ Maximum number of resources to keep open -- per stripe. /Minimum: 1/ -> ByteString -- ^ connection string -> IO (Context Connection) pooledContextOfConnStr nstripes idleDuration maxOpen connstr = pooledContext (connectPostgreSQL connstr) close nstripes idleDuration maxOpen {- -- | Simple wrapper around @postgresql-simple@'s @['Only' 'Int']@ newtype PGResult = PGResult { onlyInts :: [Only Int] } deriving (Eq, Show) -- | Create a 'PGResult' by simply wrapping the argument in a /newtype/ resultOfInts :: [Only Int] -> PGResult resultOfInts = PGResult -- | Send status 201 if successful, 400 if not along with an error instance Response (UpdateResponse Add) PGResult where toResponse result = (UpdateResponse successful m, responseStatus) where affected = getSum . foldMap (Sum . fromOnly) $ onlyInts result successful = affected > 0 m = if affected < 1 then "Unknown error. please report this to maintainers" else "" responseStatus = if successful then status201 else status400 -- | Send status 200 if successful, 404 if target not found along with "Not found" instance Response (UpdateResponse Update) PGResult where toResponse result = (UpdateResponse successful m, responseStatus) where affected = getSum . foldMap (Sum . fromOnly) $ onlyInts result successful = affected > 0 m = if affected < 1 then "Not found" else "" responseStatus = if successful then status200 else notFound404 -- | Send status 200 if successful, 404 if target not found along with "Not found" instance Response (UpdateResponse Delete) PGResult where toResponse result = (UpdateResponse successful m, responseStatus) where affected = getSum . foldMap (Sum . fromOnly) $ onlyInts result successful = affected > 0 m = if affected < 1 then "Not found" else "" responseStatus = if successful then status200 else notFound404 -}