{-# LANGUAGE FlexibleInstances, GeneralizedNewtypeDeriving, MultiParamTypeClasses, OverloadedStrings #-} {- | Module : Servant.PostgreSQL.Prelude Copyright : (c) Zalora SEA 2014 License : BSD3 Maintainer : Alp Mestanogullari Stability : experimental An helpful wrapper around 'Int64' that you can tie to the standard response types in "Servant.Response.Prelude" with the instances defined in this module. -} module Servant.PostgreSQL.Prelude ( PGResult , ToPGResult(..) , toPGResult , pgresultOfInts , pgresultOfInt64 , module Servant.Context.PostgreSQL ) where import Data.Foldable import Data.Int import Data.Monoid import Database.PostgreSQL.Simple import Servant.Context.PostgreSQL import Servant.Prelude import Servant.Response.Prelude -- | A wrapper around 'Int64', which is what -- PG hands us back when running -- 'Database.PostgreSQL.Simple.execute'. -- -- The @o@ type parameter lets us tag -- the result with the operation that -- we're running. This lets us turn -- results into a proper response -- (response body + status) differently -- for 'Add' and 'Update' for example. newtype PGResult o = PGResult { pgres :: Int64 } deriving (Eq, Ord, Num, Show) -- | Run a database action and convert its -- result to a 'PGResult'. -- -- This will only typecheck on queries that -- return 'Int64' or @['Only' 'Int']@, or a custom -- type of yours for which you provide a 'ToPGResult' -- instance. toPGResult :: ToPGResult r => IO r -> IO (PGResult o) toPGResult = fmap fromRes -- | Run an 'IO' action that returns @['Only' 'Int']@ -- and convert the result to a 'PGResult'. pgresultOfInts :: IO [Only Int] -> IO (PGResult o) pgresultOfInts = toPGResult -- | Run an 'IO' action that returns 'Int64' and -- convert the result to a 'PGResult'. pgresultOfInt64 :: IO Int64 -> IO (PGResult o) pgresultOfInt64 = toPGResult -- | Class of types that can be converted to a -- 'PGResult'. -- -- This package provides instances for 'Int64' -- and @['Only' 'Int']@ class ToPGResult r where fromRes :: r -> PGResult o instance ToPGResult Int64 where fromRes = PGResult instance ToPGResult [Only Int] where fromRes ns = PGResult n where n = getSum $ foldMap (Sum . fromIntegral . fromOnly) ns -- | If the 'Int64' is smaller than 1, status 400 and a -- suitable error message. Status 201 and empty message otherwise. instance Response (UpdateResponse Add) (PGResult Add) where toResponse n = (response, statuscode) where response = UpdateResponse successful msg successful = n > 0 msg = if successful then "" else "no entry added" statuscode = if successful then status201 else status400 -- | If the 'Int64' is smaller than 1, status 400 and a -- suitable error message. Status200 and empty message otherwise. instance Response (UpdateResponse Delete) (PGResult Delete) where toResponse n = (response, statuscode) where response = UpdateResponse successful msg successful = n > 0 msg = if successful then "" else "couldn't delete: target entry doesn't exist" statuscode = if successful then status200 else status404 -- | If the 'Int64' is smaller than 1, status 400 and a -- suitable error message. Status200 and empty message otherwise. instance Response (UpdateResponse Update) (PGResult Update) where toResponse n = (response, statuscode) where response = UpdateResponse successful msg successful = n > 0 msg = if successful then "" else "couldn't update: target entry doesn't exist" statuscode = if successful then status200 else status404