hasql-1.10: src/library-tests/Sharing/ByUnit/Encoders/HstoreSpec.hs
module Sharing.ByUnit.Encoders.HstoreSpec (spec) where
import Data.HashMap.Strict qualified as HashMap
import Hasql.Connection qualified as Connection
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 Helpers.Scripts qualified as Scripts
import Test.Hspec
import Prelude
spec :: SpecWith (Text, Word16)
spec = do
describe "Hstore Encoders" do
it "encodes empty hstore" \config -> do
Scripts.onPreparableConnection config \connection -> do
result <- Connection.use connection do
-- Enable hstore extension (unprepared), ignore if already exists
catchError
( Session.statement ()
$ Statement.unpreparable
"CREATE EXTENSION IF NOT EXISTS hstore"
Encoders.noParams
Decoders.noResult
)
(const (pure ()))
-- Test encoding empty hstore
Session.statement
([] :: [(Text, Maybe Text)])
$ Statement.preparable
"select $1::hstore = ''::hstore"
(Encoders.param (Encoders.nonNullable Encoders.hstore))
(Decoders.singleRow (Decoders.column (Decoders.nonNullable Decoders.bool)))
result `shouldBe` Right True
it "encodes hstore with single key-value pair" \config -> do
Scripts.onPreparableConnection config \connection -> do
result <- Connection.use connection do
-- Enable hstore extension (unprepared), ignore if already exists
catchError
( Session.statement ()
$ Statement.unpreparable
"CREATE EXTENSION IF NOT EXISTS hstore"
Encoders.noParams
Decoders.noResult
)
(const (pure ()))
-- Test encoding single key-value pair
Session.statement
[("key", Just "value")]
$ Statement.preparable
"select $1::hstore = 'key => value'::hstore"
(Encoders.param (Encoders.nonNullable Encoders.hstore))
(Decoders.singleRow (Decoders.column (Decoders.nonNullable Decoders.bool)))
result `shouldBe` Right True
it "encodes hstore with multiple key-value pairs" \config -> do
Scripts.onPreparableConnection config \connection -> do
result <- Connection.use connection do
-- Enable hstore extension (unprepared), ignore if already exists
catchError
( Session.statement ()
$ Statement.unpreparable
"CREATE EXTENSION IF NOT EXISTS hstore"
Encoders.noParams
Decoders.noResult
)
(const (pure ()))
-- Test encoding multiple key-value pairs
Session.statement
[("a", Just "1"), ("b", Just "2"), ("c", Just "3")]
$ Statement.preparable
"select $1::hstore @> 'a => 1'::hstore AND $1::hstore @> 'b => 2'::hstore AND $1::hstore @> 'c => 3'::hstore"
(Encoders.param (Encoders.nonNullable Encoders.hstore))
(Decoders.singleRow (Decoders.column (Decoders.nonNullable Decoders.bool)))
result `shouldBe` Right True
it "encodes hstore with null values" \config -> do
Scripts.onPreparableConnection config \connection -> do
result <- Connection.use connection do
-- Enable hstore extension (unprepared), ignore if already exists
catchError
( Session.statement ()
$ Statement.unpreparable
"CREATE EXTENSION IF NOT EXISTS hstore"
Encoders.noParams
Decoders.noResult
)
(const (pure ()))
-- Test encoding hstore with null values
Session.statement
[("key1", Just "value1"), ("key2", Nothing), ("key3", Just "value3")]
$ Statement.preparable
"select $1::hstore = 'key1 => value1, key2 => NULL, key3 => value3'::hstore"
(Encoders.param (Encoders.nonNullable Encoders.hstore))
(Decoders.singleRow (Decoders.column (Decoders.nonNullable Decoders.bool)))
result `shouldBe` Right True
it "roundtrips hstore correctly" \config -> do
Scripts.onPreparableConnection config \connection -> do
let testData = HashMap.fromList [("key1", Just "value1"), ("key2", Nothing), ("key3", Just "value3")]
result <- Connection.use connection do
-- Enable hstore extension (unprepared), ignore if already exists
catchError
( Session.statement ()
$ Statement.unpreparable
"CREATE EXTENSION IF NOT EXISTS hstore"
Encoders.noParams
Decoders.noResult
)
(const (pure ()))
-- Test roundtrip
Session.statement
(HashMap.toList testData)
$ Statement.preparable
"select $1"
(Encoders.param (Encoders.nonNullable Encoders.hstore))
(Decoders.singleRow (Decoders.column (Decoders.nonNullable (Decoders.hstore (\n f -> replicateM n f >>= pure . HashMap.fromList)))))
result `shouldBe` Right testData
it "encodes hstore with special characters" \config -> do
Scripts.onPreparableConnection config \connection -> do
result <- Connection.use connection do
-- Enable hstore extension (unprepared), ignore if already exists
catchError
( Session.statement ()
$ Statement.unpreparable
"CREATE EXTENSION IF NOT EXISTS hstore"
Encoders.noParams
Decoders.noResult
)
(const (pure ()))
-- Test encoding hstore with special characters
Session.statement
[("key with spaces", Just "value with quotes")]
$ Statement.preparable
"select $1::hstore = '\"key with spaces\" => \"value with quotes\"'::hstore"
(Encoders.param (Encoders.nonNullable Encoders.hstore))
(Decoders.singleRow (Decoders.column (Decoders.nonNullable Decoders.bool)))
result `shouldBe` Right True