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

189 lines
5.0 KiB
Haskell
Raw Normal View History

2016-12-22 18:12:38 +00:00
module Database.PostgreSQL
( module Row
, module Value
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
, command
2016-12-22 18:12:38 +00:00
, execute
, query
2017-01-12 16:12:59 +00:00
, scalar
, unsafeQuery
2016-12-22 18:12:38 +00:00
) where
2017-12-04 21:43:36 +00:00
import Prelude
2018-07-15 17:51:17 +00:00
import Effect.Aff (Aff, bracket)
import Effect.Aff.Compat (EffectFnAff, fromEffectFnAff)
import Effect (Effect)
import Effect.Class (liftEffect)
import Effect.Exception (error)
2017-12-04 21:43:36 +00:00
import Control.Monad.Error.Class (catchError, throwError)
import Data.Array (head)
2016-12-22 18:12:38 +00:00
import Data.Either (Either(..))
2018-07-15 17:51:17 +00:00
import 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)
2018-07-15 17:51:17 +00:00
import Database.PostgreSQL.Row (class FromSQLRow, class ToSQLRow, Row0(..), Row1(..), Row10(..), Row11(..), Row12(..), Row13(..), Row14(..), Row15(..), Row16(..), Row17(..), Row18(..), Row19(..), Row2(..), Row3(..), Row4(..), Row5(..), Row6(..), Row7(..), Row8(..), Row9(..), fromSQLRow, toSQLRow) as Row
import Database.PostgreSQL.Value (class FromSQLValue)
2018-07-15 17:51:17 +00:00
import Database.PostgreSQL.Value (class FromSQLValue, class ToSQLValue, fromSQLValue, instantFromString, instantToString, null, toSQLValue, unsafeIsBuffer) as Value
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.
2018-07-15 17:51:17 +00:00
newPool :: PoolConfiguration -> Aff Pool
newPool = liftEffect <<< ffiNewPool
foreign import ffiNewPool
2018-07-15 17:51:17 +00:00
:: PoolConfiguration
-> Effect Pool
2016-12-22 18:12:38 +00:00
2017-12-05 21:12:01 +00:00
-- | Run an action with a connection. The connection is released to the pool
-- | when the action returns.
withConnection
2018-07-15 17:51:17 +00:00
:: a
2016-12-22 18:12:38 +00:00
. Pool
2018-07-15 17:51:17 +00:00
-> (Connection -> Aff a)
-> Aff a
withConnection p k =
2017-12-04 21:43:36 +00:00
bracket
(connect p)
2018-07-15 17:51:17 +00:00
(liftEffect <<< _.done)
2017-12-04 21:43:36 +00:00
(k <<< _.connection)
2017-12-04 21:43:36 +00:00
connect
2018-07-15 17:51:17 +00:00
:: Pool
2017-12-04 21:43:36 +00:00
-> Aff
{ connection :: Connection
2018-07-15 17:51:17 +00:00
, done :: Effect Unit
2017-12-04 21:43:36 +00:00
}
2018-07-15 17:51:17 +00:00
connect = fromEffectFnAff <<< ffiConnect
2017-12-04 21:43:36 +00:00
foreign import ffiConnect
2018-07-15 17:51:17 +00:00
:: Pool
-> EffectFnAff
2017-12-04 21:43:36 +00:00
{ connection :: Connection
2018-07-15 17:51:17 +00:00
, done :: Effect Unit
2017-12-04 21:43:36 +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
2018-07-15 17:51:17 +00:00
:: a
2016-12-22 18:12:38 +00:00
. Connection
2018-07-15 17:51:17 +00:00
-> Aff a
-> Aff a
2016-12-22 18:12:38 +00:00
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
2018-07-15 17:51:17 +00:00
:: i o
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
2018-07-15 17:51:17 +00:00
-> Aff 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
2018-07-15 17:51:17 +00:00
:: i o
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
2018-07-15 17:51:17 +00:00
-> Aff (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
2018-07-15 17:51:17 +00:00
:: i o
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
2018-07-15 17:51:17 +00:00
-> Aff (Maybe o)
2017-01-12 16:12:59 +00:00
scalar conn sql values =
query conn sql values
<#> map (case _ of Row1 a -> a) <<< head
2017-01-12 16:12:59 +00:00
unsafeQuery
2018-07-15 17:51:17 +00:00
:: Connection
2017-12-04 21:43:36 +00:00
-> String
-> Array Foreign
2018-07-15 17:51:17 +00:00
-> Aff (Array (Array Foreign))
unsafeQuery c s = fromEffectFnAff <<< ffiUnsafeQuery c s
foreign import ffiUnsafeQuery
2018-07-15 17:51:17 +00:00
:: Connection
2016-12-22 18:12:38 +00:00
-> String
-> Array Foreign
2018-07-15 17:51:17 +00:00
-> EffectFnAff (Array (Array Foreign))
2016-12-22 18:12:38 +00:00
2018-10-09 06:30:12 +00:00
-- | Execute a PostgreSQL query and return its command tag value
-- | (how many rows were affected by the query). This may be useful
-- | for example with DELETE or UPDATE queries.
command
:: i
. ToSQLRow i
=> Connection
-> Query i Int
-> i
-> Aff Int
command conn (Query sql) values =
unsafeCommand conn sql (toSQLRow values)
unsafeCommand
:: Connection
-> String
-> Array Foreign
-> Aff Int
unsafeCommand c s = fromEffectFnAff <<< ffiUnsafeCommand c s
foreign import ffiUnsafeCommand
:: Connection
-> String
-> Array Foreign
-> EffectFnAff Int