purescript-postgresql-client/test/Main.purs

154 lines
5.0 KiB
Haskell

module Test.Main
( main
) where
import Prelude
import Control.Monad.Aff (Aff, launchAff)
import Control.Monad.Aff.AVar (AVAR)
import Control.Monad.Aff.Console (CONSOLE)
import Control.Monad.Eff (Eff)
import Control.Monad.Eff.Class (liftEff)
import Control.Monad.Eff.Exception (EXCEPTION, error)
import Control.Monad.Eff.Now (NOW)
import Control.Monad.Error.Class (catchError, throwError, try)
import Data.DateTime.Instant (Instant, unInstant)
import Data.Decimal as D
import Data.Foldable (all)
import Data.JSDate (toInstant)
import Data.JSDate as JSDate
import Data.Maybe (Maybe(..), fromJust)
import Data.Newtype (unwrap)
import Database.PostgreSQL (Connection, POSTGRESQL, PoolConfiguration, Query(Query), Row0(Row0), Row1(Row1), Row2(Row2), Row3(Row3), Row9(Row9), execute, newPool, query, scalar, withConnection, withTransaction)
import Math ((%))
import Partial.Unsafe (unsafePartial)
import Test.Assert (ASSERT, assert)
import Test.Unit (suite)
import Test.Unit as Test.Unit
import Test.Unit.Console (TESTOUTPUT)
import Test.Unit.Main (runTest)
withRollback
:: eff
. Connection
-> Aff (postgreSQL :: POSTGRESQL | eff) Unit
-> Aff (postgreSQL :: POSTGRESQL | eff) Unit
withRollback conn action = do
execute conn (Query "BEGIN TRANSACTION") Row0
catchError (action >>= const rollback) (\e -> rollback >>= const (throwError e))
where
rollback = execute conn (Query "ROLLBACK") Row0
test
:: eff
. Connection
-> String
-> Aff ( postgreSQL :: POSTGRESQL | eff) Unit
-> Test.Unit.TestSuite (postgreSQL :: POSTGRESQL | eff)
test conn t a = Test.Unit.test t (withRollback conn a)
now :: eff. Eff (now :: NOW | eff) Instant
now = unsafePartial $ (fromJust <<< toInstant) <$> JSDate.now
main :: eff. Eff (assert :: ASSERT, avar :: AVAR, console :: CONSOLE, exception :: EXCEPTION, now :: NOW, postgreSQL :: POSTGRESQL, testOutput :: TESTOUTPUT | eff) Unit
main = void $ launchAff do
pool <- newPool config
withConnection pool \conn -> do
execute conn (Query """
CREATE TEMPORARY TABLE foods (
name text NOT NULL,
delicious boolean NOT NULL,
price NUMERIC(4,2) NOT NULL,
added TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (name)
)
""") Row0
liftEff $ runTest $ do
suite "Postgresql client" $ do
let
testCount n = do
count <- scalar conn (Query """
SELECT count(*) = $1
FROM foods
""") (Row1 n)
liftEff <<< assert $ count == Just true
Test.Unit.test "transaction commit" $ do
withTransaction conn do
execute conn (Query """
INSERT INTO foods (name, delicious, price)
VALUES ($1, $2, $3)
""") (Row3 "pork" true (D.fromString "8.30"))
testCount 1
testCount 1
execute conn (Query """
DELETE FROM foods
""") Row0
Test.Unit.test "transaction rollback" $ do
_ <- try $ withTransaction conn do
execute conn (Query """
INSERT INTO foods (name, delicious, price)
VALUES ($1, $2, $3)
""") (Row3 "pork" true (D.fromString "8.30"))
testCount 1
throwError $ error "fail"
testCount 0
let
insertFood =
execute conn (Query """
INSERT INTO foods (name, delicious, price)
VALUES ($1, $2, $3), ($4, $5, $6), ($7, $8, $9)
""") (Row9
"pork" true (D.fromString "8.30")
"sauerkraut" false (D.fromString "3.30")
"rookworst" true (D.fromString "5.60"))
test conn "select column subset" $ do
insertFood
names <- query conn (Query """
SELECT name, delicious
FROM foods
WHERE delicious
ORDER BY name ASC
""") Row0
liftEff <<< assert $ names == [Row2 "pork" true, Row2 "rookworst" true]
test conn "select default instant value" $ do
before <- liftEff $ (unwrap <<< unInstant) <$> now
insertFood
added <- query conn (Query """
SELECT added
FROM foods
""") Row0
after <- liftEff $ (unwrap <<< unInstant) <$> now
-- | timestamps are fetched without milliseconds so we have to
-- | round before value down
liftEff <<< assert $ all
(\(Row1 t) ->
( unwrap $ unInstant t) >= (before - before % 1000.0)
&& after >= (unwrap $ unInstant t))
added
test conn "select decimal" $ do
insertFood
sauerkrautPrice <- query conn (Query """
SELECT price
FROM foods
WHERE NOT delicious
""") Row0
liftEff <<< assert $ sauerkrautPrice == [Row1 (D.fromString "3.30")]
config :: PoolConfiguration
config =
{ user: "postgres"
, password: "lol123"
, host: "127.0.0.1"
, port: 5432
, database: "purspg"
, max: 10
, idleTimeoutMillis: 1000
}