graphql-engine/server/lib/pg-client-hs/bench/Main.hs
Auke Booij 4c016b4c42 Clean up pg-client-hs
- Remove a few unnecessary helper functions
- Delete kind annotations
- Bring GHC warnings and language extensions more in line with those of the `graphql-engine` library
- Constrain unconstrained dependency on `hasql-pool`

PR-URL: https://github.com/hasura/graphql-engine-mono/pull/6251
GitOrigin-RevId: 10c2530f007f70cf1464cec36566ee2264589881
2022-10-07 11:56:55 +00:00

147 lines
4.3 KiB
Haskell

{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TemplateHaskell #-}
module Main
( main,
)
where
-------------------------------------------------------------------------------
import Control.Exception qualified as E
import Control.Monad (unless)
import Control.Monad.Trans.Except (runExceptT)
import Data.ByteString qualified as B
import Data.ByteString.Char8 qualified as BC
import Data.FileEmbed qualified as FE
import Data.Functor.Identity (Identity (..), runIdentity)
import Data.Int (Int64)
import Data.Text qualified as T
import Data.Text.Encoding qualified as TE
import Database.PG.Query qualified as PG
import Hasql.Decoders qualified as HD
import Hasql.Encoders qualified as HE
import Hasql.Pool qualified as HP
import Hasql.Statement qualified as HS
import Hasql.Transaction qualified as HT
import Hasql.Transaction.Sessions qualified as HT
import System.IO.Error qualified as E
import Test.Tasty.Bench qualified as C
import Prelude
-------------------------------------------------------------------------------
withEx :: (Show e) => IO (Either e a) -> IO a
withEx action =
action >>= either (E.throwIO . E.userError . show) return
runCTx :: PG.PGPool -> PG.TxE PG.PGExecErr a -> IO a
runCTx pool tx =
withEx $ runExceptT $ PG.runTx pool (PG.Serializable, Just PG.ReadWrite) tx
runHTx :: HP.Pool -> HT.Transaction a -> IO a
runHTx pool tx =
withEx $ HP.use pool $ HT.transaction HT.Serializable HT.Write tx
type CTx a = PG.TxE PG.PGExecErr a
type HTx = HT.Transaction
benchQ ::
(PG.PGPool, HP.Pool) ->
String ->
(Bool -> CTx B.ByteString, Bool -> HTx B.ByteString) ->
IO C.Benchmark
benchQ (poolC, poolH) n (txC, txH) = do
resC <- runCTx poolC $ txC False
resCP <- runCTx poolC $ txC True
resH <- runHTx poolH $ txH False
resHP <- runHTx poolH $ txH True
unless (resC == resCP && resCP == resH && resH == resHP) $ do
BC.putStrLn $ "pg-client: " <> resC
BC.putStrLn $ "pg-client-prepared: " <> resCP
BC.putStrLn $ "hasql" <> resH
BC.putStrLn $ "hasql-prepared" <> resHP
E.throwIO $ E.userError $ "results are not the same for: " <> n
return $
C.bgroup
n
[ C.bench "pg-client" $ C.whnfIO $ runCTx poolC $ txC False,
C.bench "pg-client-prepared" $ C.whnfIO $ runCTx poolC $ txC True,
C.bench "hasql" $ C.whnfIO $ runHTx poolH $ txH False,
C.bench "hasql-prepared" $ C.whnfIO $ runHTx poolH $ txH True
]
getPoolC :: IO PG.PGPool
getPoolC = do
let connDetails =
PG.CDOptions
PG.ConnOptions
{ PG.connHost = "127.0.0.1",
PG.connPort = 7432,
PG.connUser = "admin",
PG.connPassword = "",
PG.connDatabase = "chinook",
PG.connOptions = Nothing
}
connInfo = PG.ConnInfo 0 connDetails
connParams = PG.ConnParams 1 1 180 False Nothing Nothing False
logger = const (return ())
PG.initPGPool connInfo connParams logger
q1 :: T.Text
q1 = $(FE.embedStringFile "bench/queries/artistByArtistId.sql")
mkTx1C :: Bool -> CTx B.ByteString
mkTx1C isPrepared =
runIdentity . PG.getRow
<$> PG.withQE
PG.PGExecErrTx
(PG.fromText q1)
(Identity (3 :: Int64))
isPrepared
mkTx1H :: Bool -> HTx B.ByteString
mkTx1H isPrepared =
HT.statement 3 $ HS.Statement (TE.encodeUtf8 q1) encoder decoder isPrepared
where
encoder = HE.param $ HE.nonNullable HE.int8
decoder = HD.singleRow $ HD.column $ HD.nonNullable $ HD.custom $ \_ bs -> return bs
q2 :: T.Text
q2 = $(FE.embedStringFile "bench/queries/allArtists.sql")
mkTx2C :: Bool -> CTx B.ByteString
mkTx2C isPrepared =
runIdentity . PG.getRow
<$> PG.withQE
PG.PGExecErrTx
(PG.fromText q2)
()
isPrepared
mkTx2H :: Bool -> HTx B.ByteString
mkTx2H isPrepared =
HT.statement () $ HS.Statement (TE.encodeUtf8 q2) encoder decoder isPrepared
where
encoder = HE.noParams
decoder = HD.singleRow $ HD.column $ HD.nonNullable $ HD.custom $ \_ bs -> return bs
main :: IO ()
main = do
poolC <- getPoolC
poolH <- HP.acquire (1, 180, "postgresql://admin@127.0.0.1:7432/chinook")
benchmarks <-
sequence
[ benchQ (poolC, poolH) "artistByArtistId" (mkTx1C, mkTx1H),
benchQ (poolC, poolH) "allArtists" (mkTx2C, mkTx2H)
]
C.defaultMain benchmarks
PG.destroyPGPool poolC
HP.release poolH