@@ -1,11 +1,12 @@
1−{-# language BangPatterns #-}
21{-# language BlockArguments #-}
2+{-# language DataKinds #-}
33{-# language DeriveAnyClass #-}
44{-# language DeriveGeneric #-}
55{-# language DerivingStrategies #-}
6+{-# language DisambiguateRecordFields #-}
67{-# language FlexibleContexts #-}
78{-# language FlexibleInstances #-}
8−{-# language MonoLocalBinds #-}
9+{-# language GADTs #-}
910{-# language NamedFieldPuns #-}
1011{-# language OverloadedStrings #-}
1112{-# language RecordWildCards #-}
@@ -13,15 +14,17 @@
1314{-# language StandaloneDeriving #-}
1415{-# language TypeApplications #-}
1516
17+{-# options_ghc -fno-warn-redundant-constraints #-}
18+
1619module Main
1720 ( main
1821 )
1922where
2023
2124-- base
22−import Control.Applicative ( empty, liftA2, liftA3 )
23−import Control.Exception ( bracket, throwIO )
24−import Control.Monad ( (>=>), void )
25+import Control.Applicative ( liftA2, liftA3 )
26+import Control.Monad (void)
27+import Control.Monad.IO.Class ( MonadIO, liftIO )
2528import Data.Bifunctor ( bimap )
2629import Data.Foldable ( for_ )
2730import Data.Int ( Int32, Int64 )
@@ -35,27 +38,25 @@ import GHC.Generics ( Generic )
3538import qualified Data.ByteString.Lazy
3639
3740-- case-insensitive
38−import Data.CaseInsensitive ( mk )
41+import Data.CaseInsensitive (mk)
3942
4043-- containers
41−import Data.Containers.ListUtils ( nubOrdOn )
4244import qualified Data.Map.Strict as Map
4345
4446-- hasql
45−import Hasql.Connection ( Connection, acquire, release )
47+import Hasql.Connection ( Connection, acquire, release )
4648import Hasql.Session ( sql, run )
4749
48−-- hasql-transaction
49−import Hasql.Transaction ( Transaction, condemn, statement )
50−import qualified Hasql.Transaction.Sessions as Hasql
51−
5250-- hedgehog
5351import Hedgehog ( property, (===), forAll, cover, diff, evalM, PropertyT, TestT, test, Gen )
5452import qualified Hedgehog.Gen as Gen
5553import qualified Hedgehog.Range as Range
5654
57−-- mmorph
58−import Control.Monad.Morph ( hoist )
55+-- lifted-base
56+import Control.Exception.Lifted ( bracket, throwIO, bracket_ )
57+
58+-- monad-control
59+import Control.Monad.Trans.Control ( MonadBaseControl )
5960
6061-- rel8
6162import Rel8 ( Result )
@@ -71,16 +72,12 @@ import Test.Tasty
7172import Test.Tasty.Hedgehog ( testProperty )
7273
7374-- text
74−import Data.Text ( Text, pack, unpack )
75+import Data.Text (Text, pack)
7576import qualified Data.Text.Lazy
76−import Data.Text.Encoding ( decodeUtf8 )
7777
7878-- time
7979import Data.Time
8080
81−-- transformers
82−import Control.Monad.Trans.Class ( lift )
83−
8481-- tmp-postgres
8582import qualified Database.Postgres.Temp as TmpPostgres
8683
@@ -116,13 +113,11 @@ tests =
116113 , testCatMaybeTable getTestDatabase
117114 , testCatMaybe getTestDatabase
118115 , testMaybeTable getTestDatabase
119− , testAggregateMaybeTable getTestDatabase
120116 , testNestedTables getTestDatabase
121117 , testMaybeTableApplicative getTestDatabase
122118 , testLogicalFixities getTestDatabase
123119 , testUpdate getTestDatabase
124120 , testDelete getTestDatabase
125− , testUpsert getTestDatabase
126121 , testSelectNestedPairs getTestDatabase
127122 , testSelectArray getTestDatabase
128123 , testNestedMaybeTable getTestDatabase
@@ -138,7 +133,6 @@ tests =
138133 flip run conn do
139134 sql "CREATE EXTENSION citext"
140135 sql "CREATE TABLE test_table ( column1 text not null, column2 bool not null )"
141− sql "CREATE TABLE unique_table ( \"key\" text not null unique, \"value\" text not null )"
142136 sql "CREATE SEQUENCE test_seq"
143137
144138 return db
@@ -146,21 +140,19 @@ tests =
146140 stopTestDatabase = TmpPostgres.stop
147141
148142
149−connect :: TmpPostgres.DB -> IO Connection
150−connect = acquire . TmpPostgres.toConnectionString >=> either (maybe empty (fail . unpack . decodeUtf8)) pure
151−
152−
153143databasePropertyTest
154144 :: TestName
155− -> ((TestT Transaction () -> PropertyT IO ()) -> PropertyT IO ())
145+ -> (((Connection -> TestT IO ()) -> PropertyT IO ()) -> PropertyT IO ())
156146 -> IO TmpPostgres.DB -> TestTree
157147databasePropertyTest testName f getTestDatabase =
158− withResource (connect =<< getTestDatabase) release $ \c ->
148+ withResource connect release $ \c ->
159149 testProperty testName $ property do
160− connection <- lift c
161− f $ test . hoist \m -> do
162− e <- run (Hasql.transaction Hasql.Serializable Hasql.Write (m <* condemn)) connection
163− either throwIO pure e
150+ connection <- liftIO c
151+ f \g -> test $ rollingBack connection $ g connection
152+
153+ where
154+
155+ connect = either (error . show) return =<< acquire . TmpPostgres.toConnectionString =<< getTestDatabase
164156
165157
166158data TestTable f = TestTable
@@ -192,17 +184,18 @@ testSelectTestTable :: IO TmpPostgres.DB -> TestTree
192184testSelectTestTable = databasePropertyTest "Can SELECT TestTable" \transaction -> do
193185 rows <- forAll $ Gen.list (Range.linear 0 10) genTestTable
194186
195− transaction do
196− selected <- lift do
197− statement () $ Rel8.insert Rel8.Insert
198− { into = testTableSchema
199− , rows = Rel8.values $ map Rel8.lit rows
200− , onConflict = Rel8.DoNothing
201− , returning = pure ()
202− }
187+ transaction \connection -> do
188+ void do
189+ liftIO $ Rel8.insert connection
190+ Rel8.Insert
191+ { into = testTableSchema
192+ , rows = map Rel8.lit rows
193+ , onConflict = Rel8.DoNothing
194+ , returning = Rel8.NumberOfRowsAffected
195+ }
203196
204− statement () $ Rel8.select do
205− Rel8.each testTableSchema
197+ selected <- liftIO $ Rel8.select connection do
198+ Rel8.each testTableSchema
206199
207200 sort selected === sort rows
208201
@@ -219,12 +212,11 @@ testWhere_ = databasePropertyTest "WHERE (Rel8.where_)" \transaction -> do
219212
220213 let expected = filter (\t -> testTableColumn2 t == magicBool) rows
221214
222− transaction do
223− selected <- lift do
224− statement () $ Rel8.select do
225− t <- Rel8.values $ Rel8.lit <$> rows
226− Rel8.where_ $ testTableColumn2 t Rel8.==. Rel8.lit magicBool
227− return t
215+ transaction \connection -> do
216+ selected <- liftIO $ Rel8.select connection do
217+ t <- Rel8.values $ Rel8.lit <$> rows
218+ Rel8.where_ $ testTableColumn2 t Rel8.==. Rel8.lit magicBool
219+ return t
228220
229221 sort selected === sort expected
230222
@@ -237,12 +229,11 @@ testFilter :: IO TmpPostgres.DB -> TestTree
237229testFilter = databasePropertyTest "filter" \transaction -> do
238230 rows <- forAll $ Gen.list (Range.linear 1 10) genTestTable
239231
240− transaction do
232+ transaction \connection -> do
241233 let expected = filter testTableColumn2 rows
242234
243− selected <- lift do
244− statement () $ Rel8.select do
245− Rel8.filter testTableColumn2 =<< Rel8.values (Rel8.lit <$> rows)
235+ selected <- liftIO $ Rel8.select connection
236+ $ Rel8.filter testTableColumn2 =<< Rel8.values (Rel8.lit <$> rows)
246237
247238 sort selected === sort expected
248239
@@ -257,10 +248,9 @@ testLimit = databasePropertyTest "LIMIT (Rel8.limit)" \transaction -> do
257248
258249 n <- forAll $ Gen.integral (Range.linear 0 10)
259250
260− transaction do
261− selected <- lift do
262− statement () $ Rel8.select do
263− Rel8.limit n $ Rel8.values (Rel8.lit <$> rows)
251+ transaction \connection -> do
252+ selected <- liftIO $ Rel8.select connection do
253+ Rel8.limit n $ Rel8.values (Rel8.lit <$> rows)
264254
265255 diff (length selected) (<=) (fromIntegral n)
266256
@@ -278,10 +268,9 @@ testUnion = databasePropertyTest "UNION (Rel8.union)" \transaction -> evalM do
278268 left <- forAll $ Gen.list (Range.linear 0 10) genTestTable
279269 right <- forAll $ Gen.list (Range.linear 0 10) genTestTable
280270
281− transaction do
282− selected <- lift do
283− statement () $ Rel8.select do
284− Rel8.values (Rel8.lit <$> nub left) `Rel8.union` Rel8.values (Rel8.lit <$> nub right)
271+ transaction \connection -> do
272+ selected <- liftIO $ Rel8.select connection do
273+ Rel8.values (Rel8.lit <$> nub left) `Rel8.union` Rel8.values (Rel8.lit <$> nub right)
285274
286275 sort selected === sort (nub (left ++ right))
287276
@@ -290,11 +279,9 @@ testDistinct :: IO TmpPostgres.DB -> TestTree
290279testDistinct = databasePropertyTest "DISTINCT (Rel8.distinct)" \transaction -> do
291280 rows <- forAll $ Gen.list (Range.linear 0 10) genTestTable
292281
293− transaction do
294− selected <- lift do
295− statement () $ Rel8.select do
296− Rel8.distinct do
297− Rel8.values (Rel8.lit <$> rows)
282+ transaction \connection -> do
283+ selected <- liftIO $ Rel8.select connection $ Rel8.distinct do
284+ Rel8.values (Rel8.lit <$> rows)
298285
299286 sort selected === nub (sort rows)
300287
@@ -307,10 +294,8 @@ testExists :: IO TmpPostgres.DB -> TestTree
307294testExists = databasePropertyTest "EXISTS (Rel8.exists)" \transaction -> do
308295 rows <- forAll $ Gen.list (Range.linear 0 10) genTestTable
309296
310− transaction do
311− exists <- lift do
312− statement () $ Rel8.select do
313− Rel8.exists $ Rel8.values $ Rel8.lit <$> rows
297+ transaction \connection -> do
298+ exists <- liftIO $ Rel8.select connection $ Rel8.exists $ Rel8.values $ Rel8.lit <$> rows
314299
315300 case rows of
316301 [] -> exists === [False]
@@ -321,10 +306,9 @@ testOptional :: IO TmpPostgres.DB -> TestTree
321306testOptional = databasePropertyTest "Rel8.optional" \transaction -> do
322307 rows <- forAll $ Gen.list (Range.linear 0 10) genTestTable
323308
324− transaction do
325− selected <- lift do
326− statement () $ Rel8.select do
327− Rel8.optional $ Rel8.values (Rel8.lit <$> rows)
309+ transaction \connection -> do
310+ selected <- liftIO $ Rel8.select connection do
311+ Rel8.optional $ Rel8.values (Rel8.lit <$> rows)
328312
329313 case rows of
330314 [] -> selected === [Nothing]
@@ -335,10 +319,9 @@ testAnd :: IO TmpPostgres.DB -> TestTree
335319testAnd = databasePropertyTest "AND (&&.)" \transaction -> do
336320 (x, y) <- forAll $ liftA2 (,) Gen.bool Gen.bool
337321
338− transaction do
339− [result] <- lift do
340− statement () $ Rel8.select do
341− pure $ Rel8.lit x Rel8.&&. Rel8.lit y
322+ transaction \connection -> do
323+ [result] <- liftIO $ Rel8.select connection $ pure $
324+ Rel8.lit x Rel8.&&. Rel8.lit y
342325
343326 result === (x && y)
344327
@@ -347,10 +330,9 @@ testOr :: IO TmpPostgres.DB -> TestTree
347330testOr = databasePropertyTest "OR (||.)" \transaction -> do
348331 (x, y) <- forAll $ liftA2 (,) Gen.bool Gen.bool
349332
350− transaction do
351− [result] <- lift do
352− statement () $ Rel8.select $ pure $
353− Rel8.lit x Rel8.||. Rel8.lit y
333+ transaction \connection -> do
334+ [result] <- liftIO $ Rel8.select connection $ pure $
335+ Rel8.lit x Rel8.||. Rel8.lit y
354336
355337 result === (x || y)
356338
@@ -359,10 +341,9 @@ testLogicalFixities :: IO TmpPostgres.DB -> TestTree
359341testLogicalFixities = databasePropertyTest "Logical operator fixities" \transaction -> do
360342 (u, v, w, x) <- forAll $ (,,,) <$> Gen.bool <*> Gen.bool <*> Gen.bool <*> Gen.bool
361343
362− transaction do
363− [result] <- lift do
364− statement () $ Rel8.select do
365− pure $ Rel8.lit u Rel8.||. Rel8.lit v Rel8.&&. Rel8.lit w Rel8.==. Rel8.lit x
344+ transaction \connection -> do
345+ [result] <- liftIO $ Rel8.select connection $ pure $
346+ Rel8.lit u Rel8.||. Rel8.lit v Rel8.&&. Rel8.lit w Rel8.==. Rel8.lit x
366347
367348 result === (u || v && w == x)
368349
@@ -371,10 +352,9 @@ testNot :: IO TmpPostgres.DB -> TestTree
371352testNot = databasePropertyTest "NOT (not_)" \transaction -> do
372353 x <- forAll Gen.bool
373354
374− transaction do
375− [result] <- lift do
376− statement () $ Rel8.select do
377− pure $ Rel8.not_ $ Rel8.lit x
355+ transaction \connection -> do
356+ [result] <- liftIO $ Rel8.select connection $ pure $
357+ Rel8.not_ $ Rel8.lit x
378358
379359 result === not x
380360
@@ -383,10 +363,9 @@ testBool :: IO TmpPostgres.DB -> TestTree
383363testBool = databasePropertyTest "ifThenElse_" \transaction -> do
384364 (x, y, z) <- forAll $ liftA3 (,,) Gen.bool Gen.bool Gen.bool
385365
386− transaction do
387− [result] <- lift do
388− statement () $ Rel8.select do
389− pure $ Rel8.bool (Rel8.lit z) (Rel8.lit y) (Rel8.lit x)
366+ transaction \connection -> do
367+ [result] <- liftIO $ Rel8.select connection $ pure $
368+ Rel8.bool (Rel8.lit z) (Rel8.lit y) (Rel8.lit x)
390369
391370 result === if x then y else z
392371
@@ -398,10 +377,9 @@ testAp = databasePropertyTest "Cartesian product (<*>)" \transaction -> do
398377 (Gen.list (Range.linear 1 10) genTestTable)
399378 (Gen.list (Range.linear 1 10) genTestTable)
400379
401− transaction do
402− result <- lift do
403− statement () $ Rel8.select do
404− liftA2 (,) (Rel8.values (Rel8.lit <$> rows1)) (Rel8.values (Rel8.lit <$> rows2))
380+ transaction \connection -> do
381+ result <- liftIO $ Rel8.select connection $ do
382+ liftA2 (,) (Rel8.values (Rel8.lit <$> rows1)) (Rel8.values (Rel8.lit <$> rows2))
405383
406384 sort result === sort (liftA2 (,) rows1 rows2)
407385
@@ -430,22 +408,21 @@ testDBType getTestDatabase = testGroup "DBType instances"
430408 where
431409 dbTypeTest :: (Eq a, Show a, Rel8.DBType a) => TestName -> Gen a -> TestTree
432410 dbTypeTest name generator = testGroup name
433− [ databasePropertyTest name (t generator) getTestDatabase
434− , databasePropertyTest ("Maybe " <> name) (t (Gen.maybe generator)) getTestDatabase
411+ [ databasePropertyTest name (t (==) generator) getTestDatabase
412+ , databasePropertyTest ("Maybe " <> name) (t (==) (Gen.maybe generator)) getTestDatabase
435413 ]
436414
437− t :: forall a b. (Eq a, Show a, Rel8.Sql Rel8.DBType a)
438− => Gen a
439− -> (TestT Transaction () -> PropertyT IO b)
415+ t :: forall a b. (Show a, Rel8.Sql Rel8.DBType a)
416+ => (a -> a -> Bool)
417+ -> Gen a
418+ -> ((Connection -> TestT IO ()) -> PropertyT IO b)
440419 -> PropertyT IO b
441− t generator transaction = do
420+ t eq generator transaction = do
442421 x <- forAll generator
443422
444− transaction do
445− [res] <- lift do
446− statement () $ Rel8.select do
447− pure (Rel8.litExpr x)
448− diff res (==) x
423+ transaction \connection -> do
424+ [res] <- liftIO $ Rel8.select connection $ pure (Rel8.litExpr x)
425+ diff res eq x
449426
450427 genDay :: Gen Day
451428 genDay = do
@@ -487,38 +464,39 @@ testDBEq getTestDatabase = testGroup "DBEq instances"
487464
488465 t :: forall a. (Eq a, Show a, Rel8.Sql Rel8.DBEq a)
489466 => Gen a
490− -> (TestT Transaction () -> PropertyT IO ())
467+ -> ((Connection -> TestT IO ()) -> PropertyT IO ())
491468 -> PropertyT IO ()
492469 t generator transaction = do
493470 (x, y) <- forAll (liftA2 (,) generator generator)
494471
495− transaction do
496− [res] <- lift do
497− statement () $ Rel8.select do
498− pure $ Rel8.litExpr x Rel8.==. Rel8.litExpr y
472+ transaction \connection -> do
473+ [res] <- liftIO $ Rel8.select connection $ pure $ Rel8.litExpr x Rel8.==. Rel8.litExpr y
499474 res === (x == y)
500475
476+ cover 1 "Equal" $ x == y
477+ cover 1 "Not Equal" $ x /= y
478+
501479
502480testTableEquality :: IO TmpPostgres.DB -> TestTree
503481testTableEquality = databasePropertyTest "TestTable equality" \transaction -> do
504482 (x, y) <- forAll $ liftA2 (,) genTestTable genTestTable
505483
506− transaction do
507− [eq] <- lift do
508− statement () $ Rel8.select do
509− pure $ Rel8.lit x Rel8.==: Rel8.lit y
484+ transaction \connection -> do
485+ [eq] <- liftIO $ Rel8.select connection do
486+ pure $ Rel8.lit x Rel8.==: Rel8.lit y
510487
511488 eq === (x == y)
512489
490+ cover 1 "Equal" $ x == y
491+ cover 1 "Not Equal" $ x /= y
492+
513493
514494testFromString :: IO TmpPostgres.DB -> TestTree
515495testFromString = databasePropertyTest "FromString" \transaction -> do
516496 str <- forAll $ Gen.list (Range.linear 0 10) Gen.unicode
517497
518− transaction do
519− [result] <- lift do
520− statement () $ Rel8.select do
521− pure $ fromString str
498+ transaction \connection -> do
499+ [result] <- liftIO $ Rel8.select connection $ pure $ fromString str
522500 result === pack str
523501
524502
@@ -526,11 +504,10 @@ testCatMaybeTable :: IO TmpPostgres.DB -> TestTree
526504testCatMaybeTable = databasePropertyTest "catMaybeTable" \transaction -> do
527505 rows <- forAll $ Gen.list (Range.linear 0 10) genTestTable
528506
529− transaction do
530− selected <- lift do
531− statement () $ Rel8.select do
532− testTable <- Rel8.values $ Rel8.lit <$> rows
533− Rel8.catMaybeTable $ Rel8.bool Rel8.nothingTable (pure testTable) (testTableColumn2 testTable)
507+ transaction \connection -> do
508+ selected <- liftIO $ Rel8.select connection do
509+ testTable <- Rel8.values $ Rel8.lit <$> rows
510+ Rel8.catMaybeTable $ Rel8.bool Rel8.nothingTable (pure testTable) (testTableColumn2 testTable)
534511
535512 sort selected === sort (filter testTableColumn2 rows)
536513
@@ -539,10 +516,9 @@ testCatMaybe :: IO TmpPostgres.DB -> TestTree
539516testCatMaybe = databasePropertyTest "catMaybe" \transaction -> evalM do
540517 rows <- forAll $ Gen.list (Range.linear 0 10) $ Gen.maybe Gen.bool
541518
542− transaction do
543− selected <- lift do
544− statement () $ Rel8.select do
545− Rel8.catNull =<< Rel8.values (map Rel8.lit rows)
519+ transaction \connection -> do
520+ selected <- evalM $ liftIO $ Rel8.select connection do
521+ Rel8.catNull =<< Rel8.values (map Rel8.lit rows)
546522
547523 sort selected === sort (catMaybes rows)
548524
@@ -551,38 +527,15 @@ testMaybeTable :: IO TmpPostgres.DB -> TestTree
551527testMaybeTable = databasePropertyTest "maybeTable" \transaction -> evalM do
552528 (rows, def) <- forAll $ liftA2 (,) (Gen.list (Range.linear 0 10) genTestTable) genTestTable
553529
554− transaction do
555− selected <- lift do
556− statement () $ Rel8.select do
557− Rel8.maybeTable (Rel8.lit def) id <$> Rel8.optional (Rel8.values (Rel8.lit <$> rows))
530+ transaction \connection -> do
531+ selected <- liftIO $ Rel8.select connection $
532+ Rel8.maybeTable (Rel8.lit def) id <$> Rel8.optional (Rel8.values (Rel8.lit <$> rows))
558533
559534 case rows of
560535 [] -> selected === [def]
561536 _ -> sort selected === sort rows
562537
563538
564−testAggregateMaybeTable :: IO TmpPostgres.DB -> TestTree
565−testAggregateMaybeTable = databasePropertyTest "aggregateMaybeTable" \transaction -> evalM do
566− rows <- forAll $ Gen.list (Range.linear 0 10) (Gen.maybe (Gen.int64 (Range.linear 0 10)))
567−
568− let
569− aggregate = go 0 False False
570− where
571− go !n nothing _ (Just a : as) = go (n + a) nothing True as
572− go n _ just (Nothing : as) = go n True just as
573− go _ False False [] = []
574− go _ True False [] = [Nothing]
575− go n False True [] = [Just n]
576− go n True True [] = [Nothing, Just n]
577−
578− transaction do
579− selected <- lift do
580− statement () $ Rel8.select do
581− Rel8.aggregate $ Rel8.aggregateMaybeTable Rel8.sum <$> Rel8.values (Rel8.lit <$> rows)
582−
583− sort selected === aggregate rows
584−
585−
586539data TwoTestTables f =
587540 TwoTestTables
588541 { testTable1 :: TestTable f
@@ -603,10 +556,9 @@ testNestedTables = databasePropertyTest "Nested TestTables" \transaction -> eval
603556 Gen.list (Range.linear 0 10) $
604557 liftA2 TwoTestTables genTestTable genTestTable
605558
606− transaction do
607− selected <- lift do
608− statement () $ Rel8.select do
609− Rel8.values (Rel8.lit <$> rows)
559+ transaction \connection -> do
560+ selected <- liftIO $ Rel8.select connection do
561+ Rel8.values (Rel8.lit <$> rows)
610562
611563 sort selected === sort rows
612564
@@ -616,12 +568,11 @@ testMaybeTableApplicative = databasePropertyTest "MaybeTable (<*>)" \transaction
616568 rows1 <- genRows
617569 rows2 <- genRows
618570
619− transaction do
620− selected <- lift do
621− statement () $ Rel8.select do
622− as <- Rel8.optional (Rel8.values (Rel8.lit <$> rows1))
623− bs <- Rel8.optional (Rel8.values (Rel8.lit <$> rows2))
624− pure $ liftA2 (,) as bs
571+ transaction \connection -> do
572+ selected <- liftIO $ Rel8.select connection do
573+ as <- Rel8.optional (Rel8.values (Rel8.lit <$> rows1))
574+ bs <- Rel8.optional (Rel8.values (Rel8.lit <$> rows2))
575+ pure $ liftA2 (,) as bs
625576
626577 case (rows1, rows2) of
627578 ([], []) -> selected === [Nothing]
@@ -633,6 +584,14 @@ testMaybeTableApplicative = databasePropertyTest "MaybeTable (<*>)" \transaction
633584 genRows = forAll do
634585 Gen.list (Range.linear 0 10) $ liftA2 TestTable (Gen.text (Range.linear 0 10) Gen.unicode) (pure True)
635586
587+rollingBack
588+ :: (MonadBaseControl IO m, MonadIO m)
589+ => Connection -> m a -> m a
590+rollingBack connection =
591+ bracket_
592+ (liftIO (run (sql "BEGIN") connection))
593+ (liftIO (run (sql "ROLLBACK") connection))
594+
636595
637596genTestTable :: Gen (TestTable Result)
638597genTestTable = do
@@ -645,19 +604,19 @@ testUpdate :: IO TmpPostgres.DB -> TestTree
645604testUpdate = databasePropertyTest "Can UPDATE TestTable" \transaction -> do
646605 rows <- forAll $ Gen.map (Range.linear 0 5) $ liftA2 (,) genTestTable genTestTable
647606
648− transaction do
649− selected <- lift do
650− statement () $ Rel8.insert Rel8.Insert
607+ transaction \connection -> do
608+ void $ liftIO $ Rel8.insert connection
609+ Rel8.Insert
651610 { into = testTableSchema
652− , rows = Rel8.values $ map Rel8.lit $ Map.keys rows
611+ , rows = map Rel8.lit $ Map.keys rows
653612 , onConflict = Rel8.DoNothing
654− , returning = pure ()
613+ , returning = Rel8.NumberOfRowsAffected
655614 }
656615
657− statement () $ Rel8.update Rel8.Update
616+ void $ liftIO $ Rel8.update connection
617+ Rel8.Update
658618 { target = testTableSchema
659− , from = pure ()
660− , set = \_ r ->
619+ , set = \r ->
661620 let updates = map (bimap Rel8.lit Rel8.lit) $ Map.toList rows
662621 in
663622 foldl
@@ -671,12 +630,12 @@ testUpdate = databasePropertyTest "Can UPDATE TestTable" \transaction -> do
671630 )
672631 r
673632 updates
674− , updateWhere = \_ _ -> Rel8.lit True
675− , returning = pure ()
633+ , updateWhere = \_ -> Rel8.lit True
634+ , returning = Rel8.NumberOfRowsAffected
676635 }
677636
678− statement () $ Rel8.select do
679− Rel8.each testTableSchema
637+ selected <- liftIO $ Rel8.select connection do
638+ Rel8.each testTableSchema
680639
681640 sort selected === sort (Map.elems rows)
682641
@@ -689,96 +648,29 @@ testDelete :: IO TmpPostgres.DB -> TestTree
689648testDelete = databasePropertyTest "Can DELETE TestTable" \transaction -> do
690649 rows <- forAll $ Gen.list (Range.linear 0 5) genTestTable
691650
692− transaction do
693− (deleted, selected) <- lift do
694− statement () $ Rel8.insert Rel8.Insert
651+ transaction \connection -> do
652+ void $ liftIO $ Rel8.insert connection
653+ Rel8.Insert
695654 { into = testTableSchema
696− , rows = Rel8.values $ map Rel8.lit rows
655+ , rows = map Rel8.lit rows
697656 , onConflict = Rel8.DoNothing
698− , returning = pure ()
657+ , returning = Rel8.NumberOfRowsAffected
699658 }
700659
701− deleted <- statement () $ Rel8.delete Rel8.Delete
660+ deleted <-
661+ liftIO $ Rel8.delete connection
662+ Rel8.Delete
702663 { from = testTableSchema
703− , using = pure ()
704− , deleteWhere = const testTableColumn2
664+ , deleteWhere = testTableColumn2
705665 , returning = Rel8.Projection id
706666 }
707667
708− selected <- statement () $ Rel8.select do
709− Rel8.each testTableSchema
710−
711− pure (deleted, selected)
668+ selected <- liftIO $ Rel8.select connection do
669+ Rel8.each testTableSchema
712670
713671 sort (deleted <> selected) === sort rows
714672
715673
716−data UniqueTable f = UniqueTable
717− { uniqueTableKey :: Rel8.Column f Text
718− , uniqueTableValue :: Rel8.Column f Text
719− }
720− deriving stock Generic
721− deriving anyclass Rel8.Rel8able
722−
723−
724−deriving stock instance Eq (UniqueTable Result)
725−deriving stock instance Ord (UniqueTable Result)
726−deriving stock instance Show (UniqueTable Result)
727−
728−
729−uniqueTableSchema :: Rel8.TableSchema (UniqueTable Rel8.Name)
730−uniqueTableSchema =
731− Rel8.TableSchema
732− { name = "unique_table"
733− , schema = Nothing
734− , columns = UniqueTable
735− { uniqueTableKey = "key"
736− , uniqueTableValue = "value"
737− }
738− }
739−
740−
741−genUniqueTable :: Gen (UniqueTable Result)
742−genUniqueTable = do
743− uniqueTableKey <- Gen.text (Range.linear 0 5) Gen.alphaNum
744− uniqueTableValue <- Gen.text (Range.linear 0 5) Gen.alphaNum
745− pure UniqueTable {..}
746−
747−
748−testUpsert :: IO TmpPostgres.DB -> TestTree
749−testUpsert = databasePropertyTest "Can UPSERT UniqueTable" \transaction -> do
750− as <- unique $ forAll $ Gen.list (Range.linear 0 20) genUniqueTable
751− bs <- unique $ forAll $ Gen.list (Range.linear 0 20) genUniqueTable
752−
753− transaction do
754− selected <- lift do
755− statement () $ Rel8.insert Rel8.Insert
756− { into = uniqueTableSchema
757− , rows = Rel8.values $ Rel8.lit <$> as
758− , onConflict = Rel8.DoNothing
759− , returning = pure ()
760− }
761−
762− statement () $ Rel8.insert Rel8.Insert
763− { into = uniqueTableSchema
764− , rows = Rel8.values $ Rel8.lit <$> bs
765− , onConflict = Rel8.DoUpdate Rel8.Upsert
766− { index = uniqueTableKey
767− , set = \UniqueTable {uniqueTableValue} old -> old {uniqueTableValue}
768− , updateWhere = \_ _ -> Rel8.true
769− }
770− , returning = pure ()
771− }
772−
773− statement () $ Rel8.select do
774− Rel8.each uniqueTableSchema
775−
776− fromUniqueTables selected === fromUniqueTables bs <> fromUniqueTables as
777− where
778− unique = fmap (nubOrdOn uniqueTableKey)
779− fromUniqueTables = Map.fromList . map \(UniqueTable key value) -> (key, value)
780−
781−
782674newtype HKNestedPair f = HKNestedPair { pairOne :: (TestTable f, TestTable f) }
783675 deriving stock Generic
784676 deriving anyclass Rel8.Rel8able
@@ -792,10 +684,9 @@ testSelectNestedPairs :: IO TmpPostgres.DB -> TestTree
792684testSelectNestedPairs = databasePropertyTest "Can SELECT nested pairs" \transaction -> do
793685 rows <- forAll $ Gen.list (Range.linear 0 10) $ HKNestedPair <$> liftA2 (,) genTestTable genTestTable
794686
795− transaction do
796− selected <- lift do
797− statement () $ Rel8.select do
798− Rel8.values $ map Rel8.lit rows
687+ transaction \connection -> do
688+ selected <- liftIO $ Rel8.select connection do
689+ Rel8.values $ map Rel8.lit rows
799690
800691 sort selected === sort rows
801692
@@ -804,22 +695,16 @@ testSelectArray :: IO TmpPostgres.DB -> TestTree
804695testSelectArray = databasePropertyTest "Can SELECT Arrays (with aggregation)" \transaction -> do
805696 rows <- forAll $ Gen.list (Range.linear 1 10) Gen.bool
806697
807− transaction do
808− selected <- lift do
809− statement () $ Rel8.select do
810− Rel8.many $ Rel8.values (map Rel8.lit rows)
698+ transaction \connection -> do
699+ selected <- liftIO $ Rel8.select connection do
700+ Rel8.many $ Rel8.values (map Rel8.lit rows)
811701
812702 selected === [foldMap pure rows]
813703
814− selected' <- lift do
815− statement () $ Rel8.select do
816− a <- Rel8.catListTable =<< do
817− Rel8.many $ Rel8.values (map Rel8.lit rows)
818− b <- Rel8.catListTable =<< do
819− Rel8.many $ Rel8.values (map Rel8.lit rows)
820− pure (a, b)
704+ selected' <- liftIO $ Rel8.select connection $ Rel8.catListTable =<< do
705+ Rel8.many $ Rel8.values (map Rel8.lit rows)
821706
822− selected' === liftA2 (,) rows rows
707+ selected' === rows
823708
824709
825710data NestedMaybeTable f = NestedMaybeTable
@@ -839,11 +724,10 @@ testNestedMaybeTable :: IO TmpPostgres.DB -> TestTree
839724testNestedMaybeTable = databasePropertyTest "Can nest MaybeTable within other tables" \transaction -> do
840725 let example = NestedMaybeTable { nmt1 = True, nmt2 = Just (TestTable "Hi" True) }
841726
842− transaction do
843− selected <- lift do
844− statement () $ Rel8.select do
845− x <- Rel8.values [Rel8.lit example]
846− pure $ Rel8.maybeTable (Rel8.lit False) (\_ -> Rel8.lit True) (nmt2 x)
727+ transaction \connection -> do
728+ selected <- liftIO $ Rel8.select connection do
729+ x <- Rel8.values [Rel8.lit example]
730+ pure $ Rel8.maybeTable (Rel8.lit False) (\_ -> Rel8.lit True) (nmt2 x)
847731
848732 selected === [True]
849733
@@ -851,12 +735,11 @@ testNestedMaybeTable = databasePropertyTest "Can nest MaybeTable within other ta
851735testEvaluate :: IO TmpPostgres.DB -> TestTree
852736testEvaluate = databasePropertyTest "evaluate has the evaluation order we expect" \transaction -> do
853737
854− transaction do
855− selected <- lift do
856− statement () $ Rel8.select do
857− x <- Rel8.values (Rel8.lit <$> ['a', 'b', 'c'])
858− y <- Rel8.evaluate (Rel8.nextval "test_seq")
859− pure (x, (y, y))
738+ transaction \connection -> do
739+ selected <- liftIO $ Rel8.select connection do
740+ x <- Rel8.values (Rel8.lit <$> ['a', 'b', 'c'])
741+ y <- Rel8.evaluate (Rel8.nextval "test_seq")
742+ pure (x, (y, y))
860743
861744 normalize selected ===
862745 [ ('a', (0, 0))
@@ -864,22 +747,21 @@ testEvaluate = databasePropertyTest "evaluate has the evaluation order we expect
864747 , ('c', (2, 2))
865748 ]
866749
867− selected' <- lift do
868− statement () $ Rel8.select do
869− x <- Rel8.values (Rel8.lit <$> ['a', 'b', 'c'])
870− y <- Rel8.values (Rel8.lit <$> ['d', 'e', 'f'])
871− z <- Rel8.evaluate (Rel8.nextval "test_seq")
872− pure ((x, y), (z, z))
750+ selected' <- liftIO $ Rel8.select connection do
751+ x <- Rel8.values (Rel8.lit <$> ['a', 'b', 'c'])
752+ y <- Rel8.values (Rel8.lit <$> ['d', 'e', 'f'])
753+ z <- Rel8.evaluate (Rel8.nextval "test_seq")
754+ pure ((x, y), (z, z))
873755
874756 normalize selected' ===
875757 [ (('a', 'd'), (0, 0))
876− , (('a', 'e'), (1, 1))
877− , (('a', 'f'), (2, 2))
878− , (('b', 'd'), (3, 3))
758+ , (('b', 'd'), (1, 1))
759+ , (('c', 'd'), (2, 2))
760+ , (('a', 'e'), (3, 3))
879761 , (('b', 'e'), (4, 4))
880− , (('b', 'f'), (5, 5))
881− , (('c', 'd'), (6, 6))
882− , (('c', 'e'), (7, 7))
762+ , (('c', 'e'), (5, 5))
763+ , (('a', 'f'), (6, 6))
764+ , (('b', 'f'), (7, 7))
883765 , (('c', 'f'), (8, 8))
884766 ]
885767
@@ -887,3 +769,13 @@ testEvaluate = databasePropertyTest "evaluate has the evaluation order we expect
887769 normalize :: [(x, (Int64, Int64))] -> [(x, (Int64, Int64))]
888770 normalize [] = []
889771 normalize xs@((_, (i, _)) : _) = map (fmap (\(a, b) -> (a - i, b - i))) xs
772+
773+{-
774+ selected <- liftIO $ Rel8.select connection do
775+ x <- Rel8.values (Rel8.lit <$> ['a', 'b', 'c'])
776+ x <- Rel8.values (Rel8.lit <$> ['d', 'e', 'f'])
777+ y <- Rel8.evaluate (Rel8.nextval "test_seq")
778+ pure (x, y, y)
779+
780+ selected === [('a', 1, 1), ('b', 2, 2), ('c', 3, 3)]
781+-}