Skip to content

Commit

Permalink
Use aroundWith instead of brackets for for update test
Browse files Browse the repository at this point in the history
  • Loading branch information
josephsumabat committed Oct 14, 2022
1 parent c488d8e commit c6c1858
Showing 1 changed file with 148 additions and 148 deletions.
296 changes: 148 additions & 148 deletions test/PostgreSQL/Test.hs
Original file line number Diff line number Diff line change
Expand Up @@ -1234,8 +1234,8 @@ testCommonTableExpressions = do
testPostgresqlLocking :: SpecDb
testPostgresqlLocking =
describe "For update skip locked locking" $ sequential $ do
let mkInitialStateForLockingTest connection =
flip runSqlPool connection $ do
let mkInitialStateForLockingTest connection =
flip runSqlPool connection $ do
p1k <- insert p1
p2k <- insert p2
p3k <- insert p3
Expand All @@ -1244,155 +1244,155 @@ testPostgresqlLocking =
, BlogPost "B" p2k
, BlogPost "C" p3k ]
pure ([p1k, p2k, p3k], entityKey <$> blogPosts)
cleanupLockingTest connection (personKeys, blogPostKeys) =
cleanupLockingTest connection (personKeys, blogPostKeys) =
flip runSqlPool connection $ do
void $ forM_ blogPostKeys P.delete
void $ forM_ personKeys P.delete

it "skips locked rows for a locking select" $ \connection -> do
bracket (mkInitialStateForLockingTest connection) (cleanupLockingTest connection) $ \(personKeys, blogPostKeys) -> do
waitMainThread <- newEmptyMVar

let sideThread :: IO Expectation
sideThread = do
flip runSqlPool connection $ do

_ <- takeMVar waitMainThread
nonLockedRowsNonSpecified <-
select $ do
p <- Experimental.from $ table @Person
locking (ForUpdateSkipLocked)
return p

nonLockedRowsSpecifiedTable <-
select $ do
from $ \(p `LeftOuterJoin` b) -> do
on (p ^. PersonId ==. b ^. BlogPostAuthorId)
EP.forUpdateOfSkipLocked [LockableEntity p]
return p

nonLockedRowsSpecifyAllTables <-
select $ do
from $ \(p `InnerJoin` b) -> do
on (p ^. PersonId ==. b ^. BlogPostAuthorId)
EP.forUpdateOfSkipLocked [LockableEntity p,LockableEntity b]
return p

pure $ do
nonLockedRowsNonSpecified `shouldBe` []
nonLockedRowsSpecifiedTable `shouldBe` []
nonLockedRowsSpecifyAllTables `shouldBe` []

withAsync sideThread $ \sideThreadAsync -> do
void $ flip runSqlPool connection $ do
void $ select $ do
person <- Experimental.from $ table @Person
locking (ForUpdate)
pure $ person ^. PersonId

_ <- putMVar waitMainThread ()
sideThreadAsserts <- wait sideThreadAsync
nonLockedRowsAfterUpdate <- select $ do
from $ \(p `LeftOuterJoin` b) -> do
on (p ^. PersonId ==. b ^. BlogPostAuthorId)
EP.forUpdateOfSkipLocked [LockableEntity p]
return p

asserting $ sideThreadAsserts
asserting $ length nonLockedRowsAfterUpdate `shouldBe` 3

it "skips locked rows for a subselect update" $ \connection -> do
bracket (mkInitialStateForLockingTest connection) (cleanupLockingTest connection) $ \(personKeys, blogPostKeys) -> do
waitMainThread <- newEmptyMVar

let sideThread :: IO Expectation
sideThread =
flip runSqlPool connection $ do
liftIO $ takeMVar waitMainThread

nonLockedRowsSpecifiedTable <-
select $ do
from $ \(p `LeftOuterJoin` b) -> do
on (p ^. PersonId ==. b ^. BlogPostAuthorId)
EP.forUpdateOfSkipLocked [LockableEntity p]
return p

pure $ length nonLockedRowsSpecifiedTable `shouldBe` 2

withAsync sideThread $ \sideThreadAsync -> do
void $ flip runSqlPool connection $ do
update $ \p -> do
set p [ PersonName =. val "ChangedName" ]
where_ $ p ^. PersonId
`in_` (subList_select $ do
person <- Experimental.from $ table @Person
limit 1
locking (ForUpdate)
pure $ person ^. PersonId)

liftIO $ putMVar waitMainThread ()
sideThreadAsserts <- wait sideThreadAsync
nonLockedRowsAfterUpdate <- select $ do
from $ \(p `LeftOuterJoin` b) -> do
on (p ^. PersonId ==. b ^. BlogPostAuthorId)
EP.forUpdateOfSkipLocked [LockableEntity p]
return p

asserting sideThreadAsserts
asserting $ length nonLockedRowsAfterUpdate `shouldBe` 3

it "skips locked rows for a subselect join update" $ \connection -> do
bracket (mkInitialStateForLockingTest connection) (cleanupLockingTest connection) $ \(personKeys, blogPostKeys) -> do
waitMainThread <- newEmptyMVar

let sideThread :: IO Expectation
sideThread =
flip runSqlPool connection $ do
liftIO $ takeMVar waitMainThread
lockedRows <-
select $ do
from $ \(p `LeftOuterJoin` b) -> do
on (p ^. PersonId ==. b ^. BlogPostAuthorId)
where_ (b ^. BlogPostTitle ==. val "A")
EP.forUpdateOfSkipLocked [LockableEntity p]
return p

nonLockedRows <-
select $ do
from $ \(p `LeftOuterJoin` b) -> do
on (p ^. PersonId ==. b ^. BlogPostAuthorId)
EP.forUpdateOfSkipLocked [LockableEntity p]
return p

pure $ do
lockedRows `shouldBe` []
length nonLockedRows `shouldBe` 2

withAsync sideThread $ \sideThreadAsync -> do
void $ flip runSqlPool connection $ do
update $ \p -> do
set p [ PersonName =. val "ChangedName" ]
where_ $ p ^. PersonId
`in_` (subList_select $ do
(people :& blogPosts) <-
Experimental.from $ table @Person
`Experimental.leftJoin` table @BlogPost
`Experimental.on` (\(people :& blogPosts) ->
just (people ^. PersonId) ==. blogPosts ?. BlogPostAuthorId)
where_ (blogPosts ?. BlogPostTitle ==. just (val "A"))
pure $ people ^. PersonId
)

liftIO $ putMVar waitMainThread ()
sideThreadAsserts <- wait sideThreadAsync
nonLockedRowsAfterUpdate <- select $ do
from $ \(p `LeftOuterJoin` b) -> do
on (p ^. PersonId ==. b ^. BlogPostAuthorId)
EP.forUpdateOfSkipLocked [LockableEntity p]
return p

asserting sideThreadAsserts
asserting $ length nonLockedRowsAfterUpdate `shouldBe` 3
aroundWith (\testAction connection -> do
bracket (mkInitialStateForLockingTest connection) (cleanupLockingTest connection) $ \(personKeys, blogPostKeys) ->
testAction (connection, personKeys, blogPostKeys)
) $ do
it "skips locked rows for a locking select" $ \(connection, personKeys, blogPostKeys) -> do
waitMainThread <- newEmptyMVar

let sideThread :: IO Expectation
sideThread = do
flip runSqlPool connection $ do

_ <- takeMVar waitMainThread
nonLockedRowsNonSpecified <-
select $ do
p <- Experimental.from $ table @Person
locking (ForUpdateSkipLocked)
return p

nonLockedRowsSpecifiedTable <-
select $ do
from $ \(p `LeftOuterJoin` b) -> do
on (p ^. PersonId ==. b ^. BlogPostAuthorId)
EP.forUpdateOfSkipLocked [LockableEntity p]
return p

nonLockedRowsSpecifyAllTables <-
select $ do
from $ \(p `InnerJoin` b) -> do
on (p ^. PersonId ==. b ^. BlogPostAuthorId)
EP.forUpdateOfSkipLocked [LockableEntity p,LockableEntity b]
return p

pure $ do
nonLockedRowsNonSpecified `shouldBe` []
nonLockedRowsSpecifiedTable `shouldBe` []
nonLockedRowsSpecifyAllTables `shouldBe` []

withAsync sideThread $ \sideThreadAsync -> do
void $ flip runSqlPool connection $ do
void $ select $ do
person <- Experimental.from $ table @Person
locking (ForUpdate)
pure $ person ^. PersonId

_ <- putMVar waitMainThread ()
sideThreadAsserts <- wait sideThreadAsync
nonLockedRowsAfterUpdate <- select $ do
from $ \(p `LeftOuterJoin` b) -> do
on (p ^. PersonId ==. b ^. BlogPostAuthorId)
EP.forUpdateOfSkipLocked [LockableEntity p]
return p

asserting $ sideThreadAsserts
asserting $ length nonLockedRowsAfterUpdate `shouldBe` 3

it "skips locked rows for a subselect update" $ \(connection, personKeys, blogPostKeys)-> do
waitMainThread <- newEmptyMVar

let sideThread :: IO Expectation
sideThread =
flip runSqlPool connection $ do
liftIO $ takeMVar waitMainThread

nonLockedRowsSpecifiedTable <-
select $ do
from $ \(p `LeftOuterJoin` b) -> do
on (p ^. PersonId ==. b ^. BlogPostAuthorId)
EP.forUpdateOfSkipLocked [LockableEntity p]
return p

pure $ length nonLockedRowsSpecifiedTable `shouldBe` 2

withAsync sideThread $ \sideThreadAsync -> do
void $ flip runSqlPool connection $ do
update $ \p -> do
set p [ PersonName =. val "ChangedName" ]
where_ $ p ^. PersonId
`in_` (subList_select $ do
person <- Experimental.from $ table @Person
limit 1
locking (ForUpdate)
pure $ person ^. PersonId)

liftIO $ putMVar waitMainThread ()
sideThreadAsserts <- wait sideThreadAsync
nonLockedRowsAfterUpdate <- select $ do
from $ \(p `LeftOuterJoin` b) -> do
on (p ^. PersonId ==. b ^. BlogPostAuthorId)
EP.forUpdateOfSkipLocked [LockableEntity p]
return p

asserting sideThreadAsserts
asserting $ length nonLockedRowsAfterUpdate `shouldBe` 3

it "skips locked rows for a subselect join update" $ \(connection, personKeys, blogPostKeys) -> do
waitMainThread <- newEmptyMVar

let sideThread :: IO Expectation
sideThread =
flip runSqlPool connection $ do
liftIO $ takeMVar waitMainThread
lockedRows <-
select $ do
from $ \(p `LeftOuterJoin` b) -> do
on (p ^. PersonId ==. b ^. BlogPostAuthorId)
where_ (b ^. BlogPostTitle ==. val "A")
EP.forUpdateOfSkipLocked [LockableEntity p]
return p

nonLockedRows <-
select $ do
from $ \(p `LeftOuterJoin` b) -> do
on (p ^. PersonId ==. b ^. BlogPostAuthorId)
EP.forUpdateOfSkipLocked [LockableEntity p]
return p

pure $ do
lockedRows `shouldBe` []
length nonLockedRows `shouldBe` 2

withAsync sideThread $ \sideThreadAsync -> do
void $ flip runSqlPool connection $ do
update $ \p -> do
set p [ PersonName =. val "ChangedName" ]
where_ $ p ^. PersonId
`in_` (subList_select $ do
(people :& blogPosts) <-
Experimental.from $ table @Person
`Experimental.leftJoin` table @BlogPost
`Experimental.on` (\(people :& blogPosts) ->
just (people ^. PersonId) ==. blogPosts ?. BlogPostAuthorId)
where_ (blogPosts ?. BlogPostTitle ==. just (val "A"))
pure $ people ^. PersonId
)

liftIO $ putMVar waitMainThread ()
sideThreadAsserts <- wait sideThreadAsync
nonLockedRowsAfterUpdate <- select $ do
from $ \(p `LeftOuterJoin` b) -> do
on (p ^. PersonId ==. b ^. BlogPostAuthorId)
EP.forUpdateOfSkipLocked [LockableEntity p]
return p

asserting sideThreadAsserts
asserting $ length nonLockedRowsAfterUpdate `shouldBe` 3

-- Since lateral queries arent supported in Sqlite or older versions of mysql
-- the test is in the Postgres module
Expand Down

0 comments on commit c6c1858

Please sign in to comment.