purescript-postgresql-client/src/Database/PostgreSQL.purs

166 lines
4.8 KiB
Haskell
Raw Normal View History

2016-12-22 18:12:38 +00:00
module Database.PostgreSQL
( module Row
, module Value
, POSTGRESQL
2016-12-22 18:12:38 +00:00
, PoolConfiguration
, Pool
, Connection
2016-12-22 19:25:17 +00:00
, Query(..)
2016-12-22 18:12:38 +00:00
, newPool
, withConnection
, withTransaction
, execute
, query
2017-01-12 16:12:59 +00:00
, scalar
, unsafeQuery
2016-12-22 18:12:38 +00:00
) where
import Control.Monad.Aff (Aff, makeAff)
import Control.Monad.Eff (kind Effect, Eff)
import Control.Monad.Eff.Class (liftEff)
import Control.Monad.Eff.Exception (Error, error)
import Control.Monad.Error.Class (catchError, throwError, withResource)
import Data.Array (head)
2016-12-22 18:12:38 +00:00
import Data.Either (Either(..))
import Data.Foreign (Foreign)
import Data.Maybe (Maybe(..))
2016-12-22 19:25:17 +00:00
import Data.Newtype (class Newtype)
2016-12-22 18:12:38 +00:00
import Data.Traversable (traverse)
import Database.PostgreSQL.Row (class FromSQLRow, class ToSQLRow, Row0(..), Row1(..), fromSQLRow, toSQLRow)
import Database.PostgreSQL.Row as Row
import Database.PostgreSQL.Value (class FromSQLValue)
import Database.PostgreSQL.Value as Value
2016-12-22 18:12:38 +00:00
import Prelude
2017-04-20 08:05:17 +00:00
foreign import data POSTGRESQL :: Effect
2016-12-22 18:12:38 +00:00
2016-12-24 12:38:36 +00:00
-- | PostgreSQL connection pool configuration.
2016-12-22 18:12:38 +00:00
type PoolConfiguration =
{ user :: String
, password :: String
, host :: String
, port :: Int
, database :: String
, max :: Int
, idleTimeoutMillis :: Int
}
2016-12-24 12:38:36 +00:00
-- | PostgreSQL connection pool.
2017-04-20 08:05:17 +00:00
foreign import data Pool :: Type
2016-12-22 18:12:38 +00:00
2016-12-24 12:38:36 +00:00
-- | PostgreSQL connection.
2017-04-20 08:05:17 +00:00
foreign import data Connection :: Type
2016-12-22 18:12:38 +00:00
2016-12-24 12:38:36 +00:00
-- | PostgreSQL query with parameter (`$1`, `$2`, …) and return types.
2016-12-22 19:25:17 +00:00
newtype Query i o = Query String
derive instance newtypeQuery :: Newtype (Query i o) _
2016-12-24 12:38:36 +00:00
-- | Create a new connection pool.
newPool :: eff. PoolConfiguration -> Aff (postgreSQL :: POSTGRESQL | eff) Pool
newPool = liftEff <<< ffiNewPool
foreign import ffiNewPool
2016-12-22 18:12:38 +00:00
:: eff
. PoolConfiguration
-> Eff (postgreSQL :: POSTGRESQL | eff) Pool
2016-12-22 18:12:38 +00:00
2016-12-24 12:38:36 +00:00
-- | Run an action with a connection. The connection is released to the pool
-- | when the action returns.
withConnection
2016-12-22 18:12:38 +00:00
:: eff a
. Pool
-> (Connection -> Aff (postgreSQL :: POSTGRESQL | eff) a)
-> Aff (postgreSQL :: POSTGRESQL | eff) a
withConnection p k =
withResource (makeAff $ ffiConnect p)
(liftEff <<< _.done)
(k <<< _.connection)
foreign import ffiConnect
:: eff
. Pool
-> (Error -> Eff (postgreSQL :: POSTGRESQL | eff) Unit)
-> ( { connection :: Connection
, done :: Eff (postgreSQL :: POSTGRESQL | eff) Unit
}
-> Eff (postgreSQL :: POSTGRESQL | eff) Unit
)
-> Eff (postgreSQL :: POSTGRESQL | eff) Unit
2016-12-22 18:12:38 +00:00
2016-12-24 12:38:36 +00:00
-- | Run an action within a transaction. The transaction is committed if the
-- | action returns, and rolled back when the action throws. If you want to
-- | change the transaction mode, issue a separate `SET TRANSACTION` statement
-- | within the transaction.
2016-12-22 18:12:38 +00:00
withTransaction
:: eff a
. Connection
-> Aff (postgreSQL :: POSTGRESQL | eff) a
-> Aff (postgreSQL :: POSTGRESQL | eff) a
withTransaction conn action =
execute conn (Query "BEGIN TRANSACTION") Row0
2016-12-22 18:12:38 +00:00
*> catchError (Right <$> action) (pure <<< Left) >>= case _ of
Right a -> execute conn (Query "COMMIT TRANSACTION") Row0 $> a
Left e -> execute conn (Query "ROLLBACK TRANSACTION") Row0 *> throwError e
2016-12-22 18:12:38 +00:00
2016-12-24 12:38:36 +00:00
-- | Execute a PostgreSQL query and discard its results.
2016-12-22 18:12:38 +00:00
execute
2016-12-22 19:25:17 +00:00
:: i o eff
2016-12-22 18:12:38 +00:00
. (ToSQLRow i)
=> Connection
2016-12-22 19:25:17 +00:00
-> Query i o
2016-12-22 18:12:38 +00:00
-> i
-> Aff (postgreSQL :: POSTGRESQL | eff) Unit
2016-12-22 19:25:17 +00:00
execute conn (Query sql) values =
void $ unsafeQuery conn sql (toSQLRow values)
2016-12-22 18:12:38 +00:00
2016-12-24 12:38:36 +00:00
-- | Execute a PostgreSQL query and return its results.
2016-12-22 18:12:38 +00:00
query
:: i o eff
2017-04-20 08:05:17 +00:00
. ToSQLRow i
=> FromSQLRow o
2016-12-22 18:12:38 +00:00
=> Connection
2016-12-22 19:25:17 +00:00
-> Query i o
2016-12-22 18:12:38 +00:00
-> i
-> Aff (postgreSQL :: POSTGRESQL | eff) (Array o)
2016-12-22 19:25:17 +00:00
query conn (Query sql) values =
unsafeQuery conn sql (toSQLRow values)
>>= traverse (fromSQLRow >>> case _ of
Right row -> pure row
Left msg -> throwError (error msg))
2016-12-22 18:12:38 +00:00
-- | Execute a PostgreSQL query and return the first field of the first row in
-- | the result.
2017-01-12 16:12:59 +00:00
scalar
:: i o eff
2017-04-20 08:05:17 +00:00
. ToSQLRow i
=> FromSQLValue o
2017-01-12 16:12:59 +00:00
=> Connection
-> Query i (Row1 o)
2017-01-12 16:12:59 +00:00
-> i
-> Aff (postgreSQL :: POSTGRESQL | eff) (Maybe o)
scalar conn sql values =
query conn sql values
<#> map (case _ of Row1 a -> a) <<< head
2017-01-12 16:12:59 +00:00
unsafeQuery
:: eff
. Connection
-> String
-> Array Foreign
-> Aff (postgreSQL :: POSTGRESQL | eff) (Array (Array Foreign))
unsafeQuery c s a = makeAff $ ffiUnsafeQuery c s a
foreign import ffiUnsafeQuery
2016-12-22 18:12:38 +00:00
:: eff
. Connection
-> String
-> Array Foreign
-> (Error -> Eff (postgreSQL :: POSTGRESQL | eff) Unit)
-> (Array (Array Foreign) -> Eff (postgreSQL :: POSTGRESQL | eff) Unit)
-> Eff (postgreSQL :: POSTGRESQL | eff) Unit
2016-12-22 18:12:38 +00:00
fromRight :: a b. Either a b -> Maybe b
fromRight (Left _) = Nothing
fromRight (Right a) = Just a