valiant-0.1.0.0: integration/ExecuteSpec.hs
module ExecuteSpec (spec) where
import Control.Exception (try)
import Data.Int (Int32, Int64)
import Data.Text (Text)
import Data.Vector.Unboxed qualified as U
import Valiant
import PgWire.Error (PgWireError (..))
import TestSupport
import Test.Hspec
stmtSelectOne :: Statement Int32 (Int32, Text, Maybe Text)
stmtSelectOne = mkStatement
"SELECT id, name, email FROM users WHERE id = $1"
[23] ["id", "name", "email"] "<test>"
stmtListAll :: Statement () (Int32, Text)
stmtListAll = mkStatement
"SELECT id, name FROM users ORDER BY id"
[] ["id", "name"] "<test>"
stmtListIds :: Statement () Int32
stmtListIds = mkStatement
"SELECT id FROM users ORDER BY id"
[] ["id"] "<test>"
stmtInsert :: Statement (Text, Maybe Text) ()
stmtInsert = mkStatement
"INSERT INTO users (name, email) VALUES ($1, $2)"
[25, 25] [] "<test>"
stmtCount :: Statement () Int64
stmtCount = mkStatement
"SELECT count(*) FROM users"
[] ["count"] "<test>"
stmtInsertReturningId :: Statement (Text, Maybe Text) Int32
stmtInsertReturningId = mkStatement
"INSERT INTO users (name, email) VALUES ($1, $2) RETURNING id"
[25, 25] ["id"] "<test>"
stmtInsertMultiReturningId :: Statement () Int32
stmtInsertMultiReturningId = mkStatement
"INSERT INTO users (name, email) VALUES ('X', 'x@test.com'), ('Y', 'y@test.com'), ('Z', 'z@test.com') RETURNING id"
[] ["id"] "<test>"
spec :: Spec
spec = do
describe "fetchOne" $ do
it "returns Nothing for missing row" $ do
withTestConnection $ \conn -> withSchema conn $ do
result <- fetchOne conn stmtSelectOne 999
result `shouldBe` Nothing
it "returns Just for existing row" $ do
withTestConnection $ \conn -> withSchema conn $ do
insertTestUsers conn
result <- fetchOne conn stmtSelectOne 1
case result of
Just (_, name, email) -> do
name `shouldBe` "Alice"
email `shouldBe` Just "alice@example.com"
Nothing -> expectationFailure "Expected Just, got Nothing"
describe "fetchAll" $ do
it "returns empty list for no rows" $ do
withTestConnection $ \conn -> withSchema conn $ do
rows <- fetchAll conn stmtListAll ()
rows `shouldBe` []
it "returns all rows" $ do
withTestConnection $ \conn -> withSchema conn $ do
insertTestUsers conn
rows <- fetchAll conn stmtListAll ()
length rows `shouldBe` 5
describe "fetchAllUnboxed" $ do
it "returns empty unboxed vector for no rows" $ do
withTestConnection $ \conn -> withSchema conn $ do
ids <- fetchAllUnboxed conn stmtListIds () :: IO (U.Vector Int32)
U.length ids `shouldBe` 0
it "returns all rows in an unboxed vector" $ do
withTestConnection $ \conn -> withSchema conn $ do
insertTestUsers conn
ids <- fetchAllUnboxed conn stmtListIds () :: IO (U.Vector Int32)
U.length ids `shouldBe` 5
U.toList ids `shouldSatisfy` all (> 0)
describe "execute" $ do
it "inserts a row and returns rows affected" $ do
withTestConnection $ \conn -> withSchema conn $ do
n <- execute conn stmtInsert ("TestUser", Just "test@example.com")
n `shouldBe` 1
describe "fetchScalar" $ do
it "returns a scalar count" $ do
withTestConnection $ \conn -> withSchema conn $ do
insertTestUsers conn
count <- fetchScalar conn stmtCount ()
count `shouldBe` 5
describe "executeReturning" $ do
it "returns row count and decoded rows for single insert" $ do
withTestConnection $ \conn -> withSchema conn $ do
(n, ids) <- executeReturning conn stmtInsertReturningId ("NewUser", Just "new@example.com")
n `shouldBe` 1
length ids `shouldBe` 1
it "returns row count and decoded rows for multi-value insert" $ do
withTestConnection $ \conn -> withSchema conn $ do
(n, ids) <- executeReturning conn stmtInsertMultiReturningId ()
n `shouldBe` 3
length ids `shouldBe` 3
describe "fetchOneOrThrow" $ do
it "returns the value for an existing row" $ do
withTestConnection $ \conn -> withSchema conn $ do
insertTestUsers conn
(uid, name, email) <- fetchOneOrThrow conn stmtSelectOne 1
name `shouldBe` "Alice"
email `shouldBe` Just "alice@example.com"
uid `shouldSatisfy` (> 0)
it "throws on a missing row" $ do
withTestConnection $ \conn -> withSchema conn $ do
result <- try (fetchOneOrThrow conn stmtSelectOne (-1))
case result of
Left (DecodeError _) -> pure ()
Left err -> expectationFailure $ "Expected DecodeError, got: " <> show err
Right _ -> expectationFailure "Expected an exception, but got a result"