module Test.Expr.GroupBy
( groupByTests
)
where
import qualified Control.Monad.IO.Class as MIO
import qualified Data.ByteString.Char8 as B8
import qualified Data.Int as Int
import Data.List.NonEmpty (NonEmpty ((:|)))
import qualified Data.Text as T
import qualified Orville.PostgreSQL as Orville
import qualified Orville.PostgreSQL.Execution as Execution
import qualified Orville.PostgreSQL.Expr as Expr
import qualified Orville.PostgreSQL.Raw.Connection as Conn
import qualified Orville.PostgreSQL.Raw.RawSql as RawSql
import qualified Orville.PostgreSQL.Raw.SqlValue as SqlValue
import Test.Expr.TestSchema (assertEqualSqlRows)
import qualified Test.Property as Property
data FooBar = FooBar
{ foo :: Int.Int32
, bar :: String
}
groupByTests :: Orville.ConnectionPool -> Property.Group
groupByTests pool =
Property.group
"Expr - GroupBy"
[ prop_groupByColumnsExpr pool
, prop_appendGroupByExpr pool
]
prop_groupByColumnsExpr :: Property.NamedDBProperty
prop_groupByColumnsExpr =
groupByTest "groupByColumnsExpr groups by columns" $
GroupByTest
{ groupByValuesToInsert = [FooBar 1 "dog", FooBar 2 "dingo", FooBar 3 "dog"]
, groupByExpectedQueryResults = [FooBar 3 "dog", FooBar 2 "dingo", FooBar 1 "dog"]
, groupByClause =
Just . Expr.groupByClause $
Expr.groupByColumnsExpr $
barColumn :| [fooColumn]
}
prop_appendGroupByExpr :: Property.NamedDBProperty
prop_appendGroupByExpr =
groupByTest "appendGroupByExpr causes grouping on both clauses" $
GroupByTest
{ groupByValuesToInsert = [FooBar 1 "dog", FooBar 2 "dingo", FooBar 1 "dog", FooBar 3 "dingo", FooBar 1 "dog", FooBar 2 "dingo"]
, groupByExpectedQueryResults = [FooBar 2 "dingo", FooBar 1 "dog", FooBar 3 "dingo"]
, groupByClause =
Just . Expr.groupByClause $
Expr.appendGroupByExpr
(Expr.groupByColumnsExpr . pure $ barColumn)
(Expr.groupByColumnsExpr . pure $ fooColumn)
}
data GroupByTest = GroupByTest
{ groupByValuesToInsert :: [FooBar]
, groupByClause :: Maybe Expr.GroupByClause
, groupByExpectedQueryResults :: [FooBar]
}
mkGroupByTestInsertSource :: GroupByTest -> Expr.InsertSource
mkGroupByTestInsertSource test =
let
mkRow foobar =
[ SqlValue.fromInt32 (foo foobar)
, SqlValue.fromText (T.pack $ bar foobar)
]
in
Expr.insertSqlValues (map mkRow $ groupByValuesToInsert test)
mkGroupByTestExpectedRows :: GroupByTest -> [[(Maybe B8.ByteString, SqlValue.SqlValue)]]
mkGroupByTestExpectedRows test =
let
mkRow foobar =
[ (Just (B8.pack "foo"), SqlValue.fromInt32 (foo foobar))
, (Just (B8.pack "bar"), SqlValue.fromText (T.pack $ bar foobar))
]
in
fmap mkRow (groupByExpectedQueryResults test)
groupByTest :: String -> GroupByTest -> Property.NamedDBProperty
groupByTest testName test =
Property.singletonNamedDBProperty testName $ \pool -> do
rows <- MIO.liftIO . Conn.withPoolConnection pool $ \connection -> do
dropAndRecreateTestTable connection
RawSql.executeVoid connection $
Expr.insertExpr testTable Nothing (mkGroupByTestInsertSource test) Nothing
result <-
RawSql.execute connection $
Expr.queryExpr
(Expr.selectClause $ Expr.selectExpr Nothing)
(Expr.selectColumns [fooColumn, barColumn])
(Just $ Expr.tableExpr (Expr.referencesTable testTable) Nothing (groupByClause test) Nothing Nothing Nothing)
Execution.readRows result
rows `assertEqualSqlRows` mkGroupByTestExpectedRows test
testTable :: Expr.Qualified Expr.TableName
testTable =
Expr.qualifyTable Nothing (Expr.tableName "expr_test")
fooColumn :: Expr.ColumnName
fooColumn =
Expr.columnName "foo"
barColumn :: Expr.ColumnName
barColumn =
Expr.columnName "bar"
dropAndRecreateTestTable :: Orville.Connection -> IO ()
dropAndRecreateTestTable connection = do
RawSql.executeVoid connection (RawSql.fromString "DROP TABLE IF EXISTS " <> RawSql.toRawSql testTable)
RawSql.executeVoid connection (RawSql.fromString "CREATE TABLE " <> RawSql.toRawSql testTable <> RawSql.fromString "(foo INTEGER, bar TEXT)")