beam-postgres-0.5.4.4: test/Database/Beam/Postgres/Test/Select.hs
{-# LANGUAGE LambdaCase #-}
module Database.Beam.Postgres.Test.Select (tests) where
import Data.Aeson
import Data.ByteString (ByteString)
import Data.Int
import Data.List (sort)
import qualified Data.Text as T
import qualified Data.Vector as V
import Test.Tasty
import Test.Tasty.HUnit
import Data.UUID (UUID, nil)
import qualified Data.UUID.V5 as V5
import Database.Beam
import Database.Beam.Backend.SQL.SQL92
import Database.Beam.Migrate
import Database.Beam.Postgres
import Database.Beam.Postgres.Extensions.UuidOssp
import Database.Beam.Postgres.Test
tests :: IO ByteString -> TestTree
tests getConn = testGroup "Selection Tests"
[ testGroup "JSON"
[ testPgArrayToJSON getConn
]
, testGroup "ARRAY functions"
[ testArrayReplace getConn
, testArrayShuffle getConn
, testArraySample getConn
, testArrayToStringBasic getConn
, testArrayToStringWithNull getConn
, testArrayAppend getConn
, testArrayPrepend getConn
, testArrayRemove getConn
]
, testGroup "UUID"
[ testUuidFunction getConn "uuid_nil" $ \ext -> pgUuidNil ext
, testUuidFunction getConn "uuid_ns_dns" $ \ext -> pgUuidNsDns ext
, testUuidFunction getConn "uuid_ns_url" $ \ext -> pgUuidNsUrl ext
, testUuidFunction getConn "uuid_ns_oid" $ \ext -> pgUuidNsOid ext
, testUuidFunction getConn "uuid_ns_x500" $ \ext -> pgUuidNsX500 ext
, testUuidFunction getConn "uuid_generate_v1" $ \ext ->
pgUuidGenerateV1 ext
, testUuidFunction getConn "uuid_generate_v1mc" $ \ext ->
pgUuidGenerateV1Mc ext
, testUuidFunction getConn "uuid_generate_v3" $ \ext ->
pgUuidGenerateV3 ext (val_ nil) "nil"
, testUuidFunction getConn "uuid_generate_v4" $ \ext ->
pgUuidGenerateV4 ext
, testUuidFunction getConn "uuid_generate_v5" $ \ext ->
pgUuidGenerateV5 ext (val_ nil) "nil"
, testUuuidInValues getConn
]
, testInRowValues getConn
, testInSelect getConn
, testReturningMany getConn
, testPgUnnest getConn
]
testPgArrayToJSON :: IO ByteString -> TestTree
testPgArrayToJSON getConn = testFunction getConn "array_to_json" $ \conn -> do
let values :: [Int32] = [1, 2, 3]
actual :: [PgJSON Value] <-
runBeamPostgres conn $ runSelectReturningList $ select $
return $ pgArrayToJson $ val_ $ V.fromList values
assertEqual "JSON list" [PgJSON $ toJSON values] actual
testArrayReplace :: IO ByteString -> TestTree
testArrayReplace getConn = testFunction getConn "array_replace" $ \conn -> do
let arr = V.fromList [1::Int32,2,5,4]
res <- runBeamPostgres conn $ runSelectReturningList $ select $ do
pure $ arrayReplace_ (val_ arr) (val_ (5::Int32)) (val_ (3::Int32))
assertEqual "array_replace" [V.fromList [1,2,3,4 :: Int32]] res
testArrayShuffle :: IO ByteString -> TestTree
testArrayShuffle getConn = testFunction getConn "array_shuffle" $ \conn -> do
let arr = V.fromList [1::Int32,2,3,4,5]
res <- runBeamPostgres conn $ runSelectReturningList $ select $ do
pure $ arrayShuffle_ (val_ arr)
-- shuffled result has same length and elements, order may change
case res of
[shuf] -> do
assertEqual "length" (V.length arr) (V.length shuf)
assertBool "is permutation"
(sort (V.toList arr) == sort (V.toList shuf))
_ -> assertFailure "unexpected result"
testArraySample :: IO ByteString -> TestTree
testArraySample getConn = testFunction getConn "array_sample" $ \conn -> do
let arr = V.fromList [1::Int32,2,3,4,5,6]
res <- runBeamPostgres conn $ runSelectReturningList $ select $ do
pure $ arraySample_ (val_ arr) (val_ (3::Int32))
case res of
[samp] -> do
assertEqual "length 3" 3 (V.length samp)
assertBool "subset" (V.all (`V.elem` arr) samp)
_ -> assertFailure "unexpected result"
testArrayToStringBasic :: IO ByteString -> TestTree
testArrayToStringBasic getConn = testFunction getConn "array_to_string_basic" $ \conn -> do
let arr = V.fromList [1::Int32,2,3]
res <- runBeamPostgres conn $ runSelectReturningList $ select $ do
pure $ arrayToString_ (val_ arr) (val_ ",")
assertEqual "join" ["1,2,3" :: T.Text] res
testArrayToStringWithNull :: IO ByteString -> TestTree
testArrayToStringWithNull getConn = testFunction getConn "array_to_string_with_null" $ \conn -> do
let arr :: V.Vector (Maybe T.Text)
arr = V.fromList [Just "a", Nothing, Just "b"]
res <- runBeamPostgres conn $ runSelectReturningList $ select $ do
pure $ arrayToStringWithNull_ (val_ arr) (val_ "-") (val_ "*")
assertEqual "join with null" ["a-*-b" :: T.Text] res
testArrayAppend :: IO ByteString -> TestTree
testArrayAppend getConn = testFunction getConn "array_append" $ \conn -> do
let arr = V.fromList [1::Int32,2]
res <- runBeamPostgres conn $ runSelectReturningList $ select $ do
pure $ arrayAppend_ (val_ arr) (val_ (3::Int32))
assertEqual "append" [V.fromList [1,2,3 :: Int32]] res
testArrayPrepend :: IO ByteString -> TestTree
testArrayPrepend getConn = testFunction getConn "array_prepend" $ \conn -> do
let arr = V.fromList [2::Int32,3]
res <- runBeamPostgres conn $ runSelectReturningList $ select $ do
pure $ arrayPrepend_ (val_ (1::Int32)) (val_ arr)
assertEqual "prepend" [V.fromList [1,2,3 :: Int32]] res
testArrayRemove :: IO ByteString -> TestTree
testArrayRemove getConn = testFunction getConn "array_remove" $ \conn -> do
let arr = V.fromList [1::Int32,2,3,2]
res <- runBeamPostgres conn $ runSelectReturningList $ select $ do
pure $ arrayRemove_ (val_ arr) (val_ (2::Int32))
assertEqual "remove" [V.fromList [1,3 :: Int32]] res
data UuidSchema f = UuidSchema
{ _uuidOssp :: f (PgExtensionEntity UuidOssp)
} deriving (Generic, Database Postgres)
testUuidFunction
:: IO ByteString
-> String
-> (forall s. UuidOssp -> QExpr Postgres s UUID)
-> TestTree
testUuidFunction getConn name mkUuid = testFunction getConn name $ \conn ->
runBeamPostgres conn $ do
db <- executeMigration runNoReturn $ UuidSchema <$>
pgCreateExtension @UuidOssp
[_] <- runSelectReturningList $ select $
return $ mkUuid $ getPgExtension $ _uuidOssp $ unCheckDatabase db
return ()
-- | Regression test for <https://github.com/haskell-beam/beam/issues/555 #555>
testUuuidInValues :: IO ByteString -> TestTree
testUuuidInValues getConn = testCase "UUID in values_ works" $
withTestPostgres "uuid_values" getConn $ \conn -> do
result <- runBeamPostgres conn $ do
db <- executeMigration runNoReturn $ UuidSchema <$>
pgCreateExtension @UuidOssp
let ext = getPgExtension $ _uuidOssp $ unCheckDatabase db
runSelectReturningList $ select $ do
v <- values_ [val_ nil]
return $ pgUuidGenerateV5 ext v ""
assertEqual "result" [V5.generateNamed nil []] result
data Pair f = Pair
{ _left :: C f Bool
, _right :: C f Bool
} deriving (Generic, Beamable)
testInRowValues :: IO ByteString -> TestTree
testInRowValues getConn = testCase "IN with row values works" $
withTestPostgres "db_in_row_values" getConn $ \conn -> do
result <- runBeamPostgres conn $ runSelectReturningList $ select $ do
let pair :: forall ctx s. Pair (QGenExpr ctx Postgres s)
pair = val_ $ Pair False False
return $ pair `in_` [pair, pair]
assertEqual "result" [True] result
testInSelect :: IO ByteString -> TestTree
testInSelect getConn = testCase "IN (SELECT ...) works" $
withTestPostgres "db_in_row_values" getConn $ \conn -> do
result <- runBeamPostgres conn $ runSelectReturningList $ select $ do
let x = as_ @Int32 (val_ 1)
return $ x `inQuery_` ( pgUnnestArray $ array_ $ (as_ @Int32 . val_) <$> [0..100])
assertEqual "result" [True] result
testReturningMany :: IO ByteString -> TestTree
testReturningMany getConn = testCase "runReturningMany (batching via cursor) works" $
withTestPostgres "run_returning_many_cursor" getConn $ \conn -> do
result <- runBeamPostgres conn $ runSelectReturningMany
(select $ pgUnnestArray $ array_ $ (as_ @Int32 . val_) <$> [0..rowCount - 1])
(\fetch ->
let count n = fetch >>= \case
Nothing -> pure n
Just _ -> count (n + 1)
in count 0)
assertEqual "result" rowCount result
where
rowCount = 500
runSelectReturningMany ::
(FromBackendRow Postgres x) =>
SqlSelect Postgres x -> (Pg (Maybe x) -> Pg a) -> Pg a
runSelectReturningMany (SqlSelect s) =
runReturningMany (selectCmd s)
testFunction :: IO ByteString -> String -> (Connection -> Assertion) -> TestTree
testFunction getConn name mkAssertion = testCase name $
withTestPostgres name getConn mkAssertion
-- | Regression test for <https://github.com/haskell-beam/beam/issues/541 #541>
testPgUnnest :: IO ByteString -> TestTree
testPgUnnest getConn = testCase "pgUnnest works" $
withTestPostgres "pg_unnest" getConn $ \conn -> do
let values = [Bool True, Number 1]
result <- runBeamPostgres conn $ runSelectReturningList $ select $
pgUnnest $ pgJsonArrayElements $ val_ $
PgJSONB $ Array $ V.fromList values
assertEqual "result" (PgJSONB <$> values) $ pgJsonElement <$> result