beam-postgres-0.6.2.0: test/Database/Beam/Postgres/Test/TempTable.hs
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE StandaloneDeriving #-}
module Database.Beam.Postgres.Test.TempTable (tests) where
import Data.ByteString (ByteString)
import Data.Int (Int32)
import Data.Kind (Type)
import GHC.Exts (Any)
import Database.Beam
import Database.Beam.Postgres
import Database.PostgreSQL.Simple (execute_)
import Test.Tasty
import Test.Tasty.HUnit
import Database.Beam.Postgres.Test
tests :: IO ByteString -> TestTree
tests getConn = testGroup "Temporary table tests"
[ testStageFilteredRows getConn
, testDropAndCreate getConn
]
-- | A permanent table of items.
data ItemT f = Item
{ itemId :: C f Int32
, itemValue :: C f Int32
} deriving (Generic, Beamable)
deriving instance Show (ItemT Identity)
deriving instance Eq (ItemT Identity)
instance Table ItemT where
data PrimaryKey ItemT f = ItemKey (C f Int32)
deriving (Generic, Beamable)
primaryKey = ItemKey . itemId
data ItemDb entity = ItemDb
{ dbItems :: entity (TableEntity ItemT)
} deriving (Generic, Database Postgres)
itemDb :: DatabaseSettings be ItemDb
itemDb = defaultDbSettings
-- | Stage a filtered subset of a permanent table in a temp table using
-- INSERT INTO temp SELECT ... FROM permanent WHERE ..., then read it back.
testStageFilteredRows :: IO ByteString -> TestTree
testStageFilteredRows getConn = testCase "sanity test" $
withTestPostgres "temp_table_stage" getConn $ \conn -> do
execute_ conn "CREATE TABLE items (id INT PRIMARY KEY, value INT NOT NULL)"
result <- runBeamPostgres conn $ do
runInsert $ insert (dbItems itemDb) $ insertValues
[ Item 1 5, Item 2 10, Item 3 15, Item 4 20, Item 5 25 ]
scratch <- runCreateTempTable @_ @Any @ItemT
defaultTempTableOptions "high_value_items"
runInsert $ insert scratch $ insertFrom $
filter_ (\r -> itemValue r >. val_ 15) $
all_ (dbItems itemDb)
runSelectReturningList $ select $
orderBy_ (asc_ . itemId) $ all_ scratch
assertEqual "high-value items staged" [Item 4 20, Item 5 25] result
testDropAndCreate :: IO ByteString -> TestTree
testDropAndCreate getConn = testCase "drop-and-create" $
withTestPostgres "temp_table_drop_and_create" getConn $ \conn -> do
execute_ conn "CREATE TABLE items (id INT PRIMARY KEY, value INT NOT NULL)"
result <- runBeamPostgres conn $ do
runInsert $ insert (dbItems itemDb) $ insertValues
[ Item 1 5, Item 2 10, Item 3 15, Item 4 20, Item 5 25 ]
-- First pass: stage low-value items.
scratch <- runCreateTempTable @_ @Any @ItemT
defaultTempTableOptions "scratch"
runInsert $ insert scratch $ insertFrom $
filter_ (\r -> itemValue r <=. val_ 15) $
all_ (dbItems itemDb)
-- Second pass: drop and recreate, then stage high-value items only.
scratch' <- runCreateTempTable @_ @Any @ItemT
(defaultTempTableOptions { tempTableCreateMode = DropAndCreate })
"scratch"
runInsert $ insert scratch' $ insertFrom $
filter_ (\r -> itemValue r >. val_ 15) $
all_ (dbItems itemDb)
runSelectReturningList $ select $
orderBy_ (asc_ . itemId) $ all_ scratch'
assertEqual "only high-value items after reset" [Item 4 20, Item 5 25] result