hasql-1.9.3.2: hspec/Hasql/StatementSpec.hs
module Hasql.StatementSpec (spec) where
import Hasql.Decoders qualified as Decoders
import Hasql.Encoders qualified as Encoders
import Hasql.Session qualified as Session
import Hasql.Statement qualified as Statement
import Hasql.TestingKit.Testcontainers qualified as Testcontainers
import Test.Hspec
import Prelude
spec :: Spec
spec = aroundAll Testcontainers.withConnection do
describe "Statement Functionality" do
describe "Prepared statements" do
it "allows reuse of the same prepared statement on different types" \connection -> do
let statement1 =
Statement.Statement
"select $1"
(Encoders.param (Encoders.nonNullable Encoders.text))
(Decoders.singleRow (Decoders.column (Decoders.nonNullable Decoders.text)))
True
let statement2 =
Statement.Statement
"select $1"
(Encoders.param (Encoders.nonNullable Encoders.int8))
(Decoders.singleRow (Decoders.column (Decoders.nonNullable Decoders.int8)))
True
result <-
Session.run
( do
result1 <- Session.statement "ok" statement1
result2 <- Session.statement (1 :: Int64) statement2
return (result1, result2)
)
connection
result `shouldBe` Right ("ok", 1 :: Int64)
describe "Row counting" do
it "counts affected rows correctly" \connection -> do
let dropTable = Statement.Statement "drop table if exists a" mempty Decoders.noResult True
let createTable = Statement.Statement "create table a (id bigserial not null, name varchar not null, primary key (id))" mempty Decoders.noResult True
let insertRow = Statement.Statement "insert into a (name) values ('a')" mempty Decoders.noResult False
let deleteRows = Statement.Statement "delete from a" mempty Decoders.rowsAffected False
result <-
Session.run
( do
Session.statement () dropTable
Session.statement () createTable
replicateM_ 100 (Session.statement () insertRow)
affectedRows <- Session.statement () deleteRows
Session.statement () dropTable
return affectedRows
)
connection
result `shouldBe` Right 100
describe "Auto-incremented columns" do
it "returns auto-incremented column results" \connection -> do
let dropTable = Statement.Statement "drop table if exists a" mempty Decoders.noResult True
let createTable = Statement.Statement "create table a (id bigserial not null, name varchar not null, primary key (id))" mempty Decoders.noResult True
let insertRow = Statement.Statement "insert into a (name) values ('a') returning id" mempty (Decoders.singleRow (Decoders.column (Decoders.nonNullable Decoders.int8))) False
let insertRow2 = Statement.Statement "insert into a (name) values ('b') returning id" mempty (Decoders.singleRow (Decoders.column (Decoders.nonNullable Decoders.int8))) False
result <-
Session.run
( do
Session.statement () dropTable
Session.statement () createTable
id1 <- Session.statement () insertRow
id2 <- Session.statement () insertRow2
Session.statement () dropTable
return (id1, id2)
)
connection
result `shouldBe` Right (1 :: Int64, 2 :: Int64)
describe "List decoding" do
it "decodes lists correctly" \connection -> do
let statement =
Statement.Statement
"values (1,2), (3,4), (5,6)"
mempty
(Decoders.rowList ((,) <$> (Decoders.column (Decoders.nonNullable Decoders.int8)) <*> (Decoders.column (Decoders.nonNullable Decoders.int8))))
True
result <- Session.run (Session.statement () statement) connection
result `shouldBe` Right [(1 :: Int64, 2 :: Int64), (3, 4), (5, 6)]