packages feed

valiant-bluefin-0.1.0.0: src/Valiant/Bluefin.hs

-- | Bluefin effect adapter for valiant.
--
-- Bluefin uses explicit effect handles rather than type-level effect
-- lists. The 'ValiantHandle' provides database operations that can be
-- passed to functions explicitly.
--
-- @
-- import Bluefin.Eff
-- import Valiant.Bluefin
--
-- myApp :: ValiantHandle e -> Eff e [User]
-- myApp db = do
--   users <- fetchAllB db listUsers ()
--   pure users
--
-- main :: IO ()
-- main = do
--   pool <- newPool defaultPoolConfig { poolConnString = "..." }
--   result <- runValiantB pool $ \\db -> myApp db
--   print result
-- @
module Valiant.Bluefin
  ( -- * Handle
    ValiantHandle

    -- * Runner
  , runValiantB

    -- * Query operations
  , fetchOneB
  , fetchAllB
  , fetchScalarB
  , fetchOneOrThrowB
  , fetchExistsB

    -- * Command operations
  , executeB
  , executeReturningB
  , executeBatchB

    -- * Transaction operations
  , withTransactionB

    -- * Raw access
  , withConnectionB
  ) where

import Data.Int (Int64)
import Valiant (Connection, Pool, Statement, Transaction)
import Valiant qualified
import PgWire.Pool (withResource)

-- | An opaque handle to an valiant database connection pool.
-- Pass this explicitly to functions that need database access.
newtype ValiantHandle e = ValiantHandle { unHandle :: Pool }

-- | Run an action with an valiant database handle backed by a pool.
--
-- @
-- result <- runValiantB pool $ \\db -> do
--   users <- fetchAllB db listUsers ()
--   pure users
-- @
runValiantB :: Pool -> (forall e. ValiantHandle e -> IO a) -> IO a
runValiantB pool f = f (ValiantHandle pool)

-- | Fetch zero or one row.
fetchOneB :: ValiantHandle e -> Statement p r -> p -> IO (Maybe r)
fetchOneB h stmt params =
  withResource (unHandle h) $ \conn -> Valiant.fetchOne conn stmt params

-- | Fetch all rows.
fetchAllB :: ValiantHandle e -> Statement p r -> p -> IO [r]
fetchAllB h stmt params =
  withResource (unHandle h) $ \conn -> Valiant.fetchAll conn stmt params

-- | Fetch exactly one scalar value.
fetchScalarB :: ValiantHandle e -> Statement p r -> p -> IO r
fetchScalarB h stmt params =
  withResource (unHandle h) $ \conn -> Valiant.fetchScalar conn stmt params

-- | Fetch one row, throwing if none returned.
fetchOneOrThrowB :: ValiantHandle e -> Statement p r -> p -> IO r
fetchOneOrThrowB h stmt params =
  withResource (unHandle h) $ \conn -> Valiant.fetchOneOrThrow conn stmt params

-- | Check if a query returns any rows.
fetchExistsB :: ValiantHandle e -> Statement p r -> p -> IO Bool
fetchExistsB h stmt params =
  withResource (unHandle h) $ \conn -> Valiant.fetchExists conn stmt params

-- | Execute a command. Returns rows affected.
executeB :: ValiantHandle e -> Statement p () -> p -> IO Int64
executeB h stmt params =
  withResource (unHandle h) $ \conn -> Valiant.execute conn stmt params

-- | Execute with RETURNING.
executeReturningB :: ValiantHandle e -> Statement p r -> p -> IO (Int64, [r])
executeReturningB h stmt params =
  withResource (unHandle h) $ \conn -> Valiant.executeReturning conn stmt params

-- | Execute a batch of commands (pipelined).
executeBatchB :: ValiantHandle e -> Statement p () -> [p] -> IO Int64
executeBatchB h stmt paramsList =
  withResource (unHandle h) $ \conn -> Valiant.executeBatch conn stmt paramsList

-- | Run an action in a transaction.
withTransactionB :: ValiantHandle e -> (Transaction -> IO a) -> IO a
withTransactionB h = Valiant.withTransaction (unHandle h)

-- | Run an action with a raw connection.
withConnectionB :: ValiantHandle e -> (Connection -> IO a) -> IO a
withConnectionB h = withResource (unHandle h)