{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE TypeFamilies #-}
import Control.Monad.Catch (handleAll)
import qualified Data.ByteString.Char8 as BS
import Data.List (sort)
import qualified Database.Beam as B
import qualified Database.Beam.Migrate as B
import qualified Database.Beam.Postgres as B
import qualified Database.PostgreSQL.Simple as Pg
import qualified Hedgehog.Gen as HH
import qualified Hedgehog.Range as HH
import System.Environment (lookupEnv)
import Test.Tasty
import Test.Tasty.HUnit
import Typson.Beam
import Typson.Test.Beam.DbSchema (Db(..), EntityT(..), createTableMigration, db)
import Typson.Test.Generators
import Typson.Test.Types
main :: IO ()
main = defaultMain beamTestTree
beamTestTree :: TestTree
beamTestTree = withRunDb $ \runDb ->
testGroup "Beam Tests"
[ testCase "JSON Queries" $ do
graphs <- HH.sample (HH.list (HH.singleton 100) bazGen)
runDb (insertData graphs)
r1 <- runDb . B.runSelectReturningList . B.select $
jsonPath basicPath1 bazJ <$> getAllGraphs
let a1 = JNullable . B.PgJSONB . basicPath1Getter <$> graphs
assertEqual "Basic Path 1" (sort r1) (sort a1)
r2 <- runDb . B.runSelectReturningList . B.select $
jsonPath basicPath2 bazJ <$> getAllGraphs
let a2 = JNullable . B.PgJSONB . basicPath2Getter <$> graphs
assertEqual "Basic Path 2" (sort r2) (sort a2)
r3 <- runDb . B.runSelectReturningList . B.select $
jsonPath basicPath3 bazJ <$> getAllGraphs
let a3 = JNullable . B.PgJSONB . basicPath3Getter <$> graphs
assertEqual "Basic Path 3" (sort r3) (sort a3)
r4 <- runDb . B.runSelectReturningList . B.select $
jsonPath optionalPath1 bazJ <$> getAllGraphs
let a4 = JNullable . B.PgJSONB . optionalPath1Getter <$> graphs
assertEqual "Optional Path 1" (sort r4) (sort a4)
r5 <- runDb . B.runSelectReturningList . B.select $
jsonPath optionalPath2 bazJ <$> getAllGraphs
let a5 = JNullable . B.PgJSONB . optionalPath2Getter <$> graphs
assertEqual "Optional Path 2" (sort r5) (sort a5)
r6 <- runDb . B.runSelectReturningList . B.select $
jsonPath optionalPath3 bazJ <$> getAllGraphs
let a6 = JNullable . B.PgJSONB . optionalPath3Getter <$> graphs
assertEqual "Optional Path 3" (sort r6) (sort a6)
r7 <- runDb . B.runSelectReturningList . B.select $
jsonPath listIdxPath1 bazJ <$> getAllGraphs
let a7 = JNullable . B.PgJSONB . listIdxPath1Getter <$> graphs
assertEqual "List Idx Path 1" (sort r7) (sort a7)
r8 <- runDb . B.runSelectReturningList . B.select $
jsonPath listIdxPath2 bazJ <$> getAllGraphs
let a8 = JNullable . B.PgJSONB . listIdxPath2Getter <$> graphs
assertEqual "List Idx Path 2" (sort r8) (sort a8)
r9 <- runDb . B.runSelectReturningList . B.select $
jsonPath listIdxPath3 bazJ <$> getAllGraphs
let a9 = JNullable . B.PgJSONB . listIdxPath3Getter <$> graphs
assertEqual "List Idx Path 3" (sort r9) (sort a9)
r10 <- runDb . B.runSelectReturningList . B.select $
jsonPath unionPath1 bazJ <$> getAllGraphs
let a10 = JNullable . B.PgJSONB . unionPath1Getter <$> graphs
assertEqual "Union Query 1" (sort r10) (sort a10)
r11 <- runDb . B.runSelectReturningList . B.select $
jsonPath unionPath2 bazJ <$> getAllGraphs
let a11 = JNullable . B.PgJSONB . unionPath2Getter <$> graphs
assertEqual "Union Query 2" (sort r11) (sort a11)
r12 <- runDb . B.runSelectReturningList . B.select $
jsonPath textMapPath1 bazJ <$> getAllGraphs
let a12 = JNullable . B.PgJSONB . textMapPath1Getter <$> graphs
assertEqual "Text Map Query 1" (sort r12) (sort a12)
r13 <- runDb . B.runSelectReturningList . B.select $
jsonPath textMapPath2 bazJ <$> getAllGraphs
let a13 = JNullable . B.PgJSONB . textMapPath2Getter <$> graphs
assertEqual "Text Map Query 2" (sort r13) (sort a13)
]
getAllGraphs :: B.Q B.Postgres Db s (B.QGenExpr B.QValueContext B.Postgres s (JNullable B.PgJSONB Baz))
getAllGraphs = _entityGraph <$> B.all_ (_dbEntity db)
type DbRunner = forall b. B.Pg b -> IO b
withRunDb :: (DbRunner -> TestTree) -> TestTree
withRunDb mkTree = withDb $ \ioConn -> mkTree $ \action -> do
conn <- ioConn
B.runBeamPostgres conn action
withDb :: (IO B.Connection -> TestTree) -> TestTree
withDb = withResource connectToDb B.close
connectToDb :: IO B.Connection
connectToDb = do
Just connString <- lookupEnv "CONN_STRING"
conn <- B.connectPostgreSQL (BS.pack connString)
-- reset the table
_ <- handleAll (const $ pure 0) $ Pg.execute_ conn "DROP TABLE \"beam-entity\""
_ <- B.runBeamPostgres conn $
B.executeMigration B.runNoReturn createTableMigration
pure conn
insertData :: [Baz] -> B.Pg ()
insertData graphs =
let mkEntity g = EntityT { _entityId = B.default_
, _entityGraph = B.val_ (JNullable $ B.PgJSONB g)
}
in B.runInsert
. B.insert (_dbEntity db)
$ B.insertExpressions
$ map mkEntity graphs