module Test.Expr.OrderBy ( orderByTests ) where import qualified Control.Monad.IO.Class as MIO import qualified Data.List.NonEmpty as NE 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 Test.Expr.TestSchema (FooBar (..), assertEqualFooBarRows, barColumn, dropAndRecreateTestTable, fooBarTable, fooColumn, insertFooBarSource, mkFooBar) import qualified Test.Property as Property orderByTests :: Orville.ConnectionPool -> Property.Group orderByTests pool = Property.group "Expr - OrderBy" [ prop_ascendingExpr pool , prop_descendingExpr pool , prop_appendOrderByExpr pool , prop_orderByColumnsExpr pool , prop_ascendingOrderWithExpr pool , prop_descendingOrderWithExpr pool , prop_distinctOnExpr pool ] prop_ascendingExpr :: Property.NamedDBProperty prop_ascendingExpr = orderByTest "ascendingExpr sorts a text column" $ OrderByTest { orderByValuesToInsert = NE.fromList [mkFooBar 1 "dog", mkFooBar 2 "dingo", mkFooBar 3 "dog"] , orderByExpectedQueryResults = [mkFooBar 2 "dingo", mkFooBar 1 "dog", mkFooBar 3 "dog"] , orderByDistinctOn = Nothing , orderByClause = Just . Expr.orderByClause $ Expr.orderByColumnName barColumn Expr.ascendingOrder } prop_descendingExpr :: Property.NamedDBProperty prop_descendingExpr = orderByTest "descendingExpr sorts a text column" $ OrderByTest { orderByValuesToInsert = NE.fromList [mkFooBar 1 "dog", mkFooBar 2 "dingo", mkFooBar 3 "dog"] , orderByExpectedQueryResults = [mkFooBar 1 "dog", mkFooBar 3 "dog", mkFooBar 2 "dingo"] , orderByDistinctOn = Nothing , orderByClause = Just . Expr.orderByClause $ Expr.orderByColumnName barColumn Expr.descendingOrder } prop_appendOrderByExpr :: Property.NamedDBProperty prop_appendOrderByExpr = orderByTest "appendOrderByExpr causes ordering on both columns" $ OrderByTest { orderByValuesToInsert = NE.fromList [mkFooBar 1 "dog", mkFooBar 2 "dingo", mkFooBar 3 "dog"] , orderByExpectedQueryResults = [mkFooBar 2 "dingo", mkFooBar 3 "dog", mkFooBar 1 "dog"] , orderByDistinctOn = Nothing , orderByClause = Just . Expr.orderByClause $ Expr.appendOrderByExpr (Expr.orderByColumnName barColumn Expr.ascendingOrder) (Expr.orderByColumnName fooColumn Expr.descendingOrder) } prop_orderByColumnsExpr :: Property.NamedDBProperty prop_orderByColumnsExpr = orderByTest "orderByColumnsExpr orders by columns" $ OrderByTest { orderByValuesToInsert = NE.fromList [mkFooBar 1 "dog", mkFooBar 2 "dingo", mkFooBar 3 "dog"] , orderByExpectedQueryResults = [mkFooBar 2 "dingo", mkFooBar 3 "dog", mkFooBar 1 "dog"] , orderByDistinctOn = Nothing , orderByClause = Just . Expr.orderByClause $ Expr.orderByColumnsExpr $ (barColumn, Expr.ascendingOrder) NE.:| [(fooColumn, Expr.descendingOrder)] } prop_ascendingOrderWithExpr :: Property.NamedDBProperty prop_ascendingOrderWithExpr = orderByTest "ascendingOrderWith sorts columns with nulls first/last" $ OrderByTest { orderByValuesToInsert = NE.fromList [FooBar Nothing Nothing, FooBar (Just 1) Nothing, mkFooBar 2 "dog", FooBar Nothing (Just "dog")] , orderByExpectedQueryResults = [FooBar Nothing (Just "dog"), FooBar Nothing Nothing, FooBar (Just 1) Nothing, mkFooBar 2 "dog"] , orderByDistinctOn = Nothing , orderByClause = Just . Expr.orderByClause $ Expr.appendOrderByExpr (Expr.orderByColumnName fooColumn $ Expr.ascendingOrderWith Expr.NullsFirst) (Expr.orderByColumnName barColumn $ Expr.ascendingOrderWith Expr.NullsLast) } prop_descendingOrderWithExpr :: Property.NamedDBProperty prop_descendingOrderWithExpr = orderByTest "descendingOrderWith sorts columns with nulls first/last" $ OrderByTest { orderByValuesToInsert = NE.fromList [FooBar Nothing Nothing, FooBar (Just 1) Nothing, mkFooBar 2 "dog", FooBar Nothing (Just "dog")] , orderByExpectedQueryResults = [FooBar Nothing (Just "dog"), FooBar Nothing Nothing, mkFooBar 2 "dog", FooBar (Just 1) Nothing] , orderByDistinctOn = Nothing , orderByClause = Just . Expr.orderByClause $ Expr.appendOrderByExpr (Expr.orderByColumnName fooColumn $ Expr.descendingOrderWith Expr.NullsFirst) (Expr.orderByColumnName barColumn $ Expr.descendingOrderWith Expr.NullsLast) } prop_distinctOnExpr :: Property.NamedDBProperty prop_distinctOnExpr = orderByTest "descendingExpr sorts a text column as expected with distinctOn" $ OrderByTest { orderByValuesToInsert = NE.fromList [mkFooBar 1 "dog", mkFooBar 2 "dingo", mkFooBar 3 "dog"] , orderByExpectedQueryResults = [mkFooBar 2 "dingo", mkFooBar 1 "dog"] , orderByDistinctOn = Just . pure . RawSql.unsafeFromRawSql $ RawSql.toRawSql barColumn , orderByClause = Just . Expr.orderByClause $ Expr.appendOrderByExpr (Expr.orderByColumnName barColumn Expr.ascendingOrder) (Expr.orderByColumnName fooColumn Expr.ascendingOrder) } data OrderByTest = OrderByTest { orderByValuesToInsert :: NE.NonEmpty FooBar , orderByClause :: Maybe Expr.OrderByClause , orderByDistinctOn :: Maybe (NE.NonEmpty Expr.DistinctOnExpr) , orderByExpectedQueryResults :: [FooBar] } orderByTest :: String -> OrderByTest -> Property.NamedDBProperty orderByTest testName test = Property.singletonNamedDBProperty testName $ \pool -> do rows <- MIO.liftIO $ do Conn.withPoolConnection pool $ \connection -> do dropAndRecreateTestTable connection RawSql.executeVoid connection $ Expr.insertExpr fooBarTable Nothing (insertFooBarSource $ orderByValuesToInsert test) Nothing Nothing result <- RawSql.execute connection $ Expr.queryExpr (Expr.selectClause . Expr.selectDistinctOnExpr $ orderByDistinctOn test) (Expr.selectColumns [fooColumn, barColumn]) ( Just $ Expr.tableExpr (Expr.singleTableReferenceList fooBarTable) Nothing Nothing (orderByClause test) Nothing Nothing Nothing Nothing Nothing ) Execution.readRows result assertEqualFooBarRows rows (orderByExpectedQueryResults test)