Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add all postgres row-level locking options #402

Merged
merged 1 commit into from
Oct 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
3.5.13.0
========
- @ac251
- [#402](https://github.com/bitemyapp/esqueleto/pull/402)
- Add `forNoKeyUpdate` and `forKeyShare` locking kinds for postgres

3.5.12.0
========
- @csamak
Expand Down
2 changes: 1 addition & 1 deletion esqueleto.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ cabal-version: 1.12

name: esqueleto

version: 3.5.12.0
version: 3.5.13.0
synopsis: Type-safe EDSL for SQL queries on persistent backends.
description: @esqueleto@ is a bare bones, type-safe EDSL for SQL queries that works with unmodified @persistent@ SQL backends. Its language closely resembles SQL, so you don't have to learn new concepts, just new syntax, and it's fairly easy to predict the generated SQL and optimize it for your backend. Most kinds of errors committed when writing SQL are caught as compile-time errors---although it is possible to write type-checked @esqueleto@ queries that fail at runtime.
.
Expand Down
4 changes: 4 additions & 0 deletions src/Database/Esqueleto/Internal/Internal.hs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@
import Data.Kind (Type)
import qualified Data.List as List
import qualified Data.Map.Strict as Map
import qualified Data.Monoid as Monoid

Check warning on line 63 in src/Database/Esqueleto/Internal/Internal.hs

View workflow job for this annotation

GitHub Actions / build (3.10.2.1, 8.6.5)

The qualified import of ‘Data.Monoid’ is redundant

Check warning on line 63 in src/Database/Esqueleto/Internal/Internal.hs

View workflow job for this annotation

GitHub Actions / build (3.10.2.1, 8.10.4)

The qualified import of ‘Data.Monoid’ is redundant

Check warning on line 63 in src/Database/Esqueleto/Internal/Internal.hs

View workflow job for this annotation

GitHub Actions / build (3.10.2.1, 8.10.4)

The qualified import of ‘Data.Monoid’ is redundant

Check warning on line 63 in src/Database/Esqueleto/Internal/Internal.hs

View workflow job for this annotation

GitHub Actions / build (3.10.2.1, 9.0.2)

The qualified import of ‘Data.Monoid’ is redundant

Check warning on line 63 in src/Database/Esqueleto/Internal/Internal.hs

View workflow job for this annotation

GitHub Actions / build (3.10.2.1, 9.0.2)

The qualified import of ‘Data.Monoid’ is redundant

Check warning on line 63 in src/Database/Esqueleto/Internal/Internal.hs

View workflow job for this annotation

GitHub Actions / build (3.10.2.1, 8.8.4)

The qualified import of ‘Data.Monoid’ is redundant

Check warning on line 63 in src/Database/Esqueleto/Internal/Internal.hs

View workflow job for this annotation

GitHub Actions / build (3.10.2.1, 8.8.4)

The qualified import of ‘Data.Monoid’ is redundant

Check warning on line 63 in src/Database/Esqueleto/Internal/Internal.hs

View workflow job for this annotation

GitHub Actions / build (3.10.2.1, 9.2.2)

The qualified import of ‘Data.Monoid’ is redundant

Check warning on line 63 in src/Database/Esqueleto/Internal/Internal.hs

View workflow job for this annotation

GitHub Actions / build (3.10.2.1, 9.2.2)

The qualified import of ‘Data.Monoid’ is redundant

Check warning on line 63 in src/Database/Esqueleto/Internal/Internal.hs

View workflow job for this annotation

GitHub Actions / build (3.10.2.1, 9.4.5)

The qualified import of ‘Data.Monoid’ is redundant

Check warning on line 63 in src/Database/Esqueleto/Internal/Internal.hs

View workflow job for this annotation

GitHub Actions / build (3.10.2.1, 9.4.5)

The qualified import of ‘Data.Monoid’ is redundant

Check warning on line 63 in src/Database/Esqueleto/Internal/Internal.hs

View workflow job for this annotation

GitHub Actions / build (3.10.2.1, 9.6.2)

The qualified import of ‘Data.Monoid’ is redundant

Check warning on line 63 in src/Database/Esqueleto/Internal/Internal.hs

View workflow job for this annotation

GitHub Actions / build (3.10.2.1, 9.6.2)

The qualified import of ‘Data.Monoid’ is redundant

Check warning on line 63 in src/Database/Esqueleto/Internal/Internal.hs

View workflow job for this annotation

GitHub Actions / build (3.10.2.1, 9.8.1)

The qualified import of ‘Data.Monoid’ is redundant

Check warning on line 63 in src/Database/Esqueleto/Internal/Internal.hs

View workflow job for this annotation

GitHub Actions / build (3.10.2.1, 9.8.1)

The qualified import of ‘Data.Monoid’ is redundant
import Data.Proxy (Proxy(..))
import Data.Set (Set)
import qualified Data.Set as Set
Expand All @@ -70,7 +70,7 @@
import Data.Typeable (Typeable)
import Database.Esqueleto.Internal.ExprParser (TableAccess(..), parseOnExpr)
import Database.Esqueleto.Internal.PersistentImport
import Database.Persist (EntityNameDB(..), FieldNameDB(..), SymbolToField(..))

Check warning on line 73 in src/Database/Esqueleto/Internal/Internal.hs

View workflow job for this annotation

GitHub Actions / build (3.10.2.1, 8.10.4)

The import of ‘Database.Persist’ is redundant

Check warning on line 73 in src/Database/Esqueleto/Internal/Internal.hs

View workflow job for this annotation

GitHub Actions / build (3.10.2.1, 8.10.4)

The import of ‘Database.Persist’ is redundant

Check warning on line 73 in src/Database/Esqueleto/Internal/Internal.hs

View workflow job for this annotation

GitHub Actions / build (3.10.2.1, 9.0.2)

The import of ‘Database.Persist’ is redundant

Check warning on line 73 in src/Database/Esqueleto/Internal/Internal.hs

View workflow job for this annotation

GitHub Actions / build (3.10.2.1, 9.0.2)

The import of ‘Database.Persist’ is redundant

Check warning on line 73 in src/Database/Esqueleto/Internal/Internal.hs

View workflow job for this annotation

GitHub Actions / build (3.10.2.1, 8.8.4)

The import of ‘Database.Persist’ is redundant

Check warning on line 73 in src/Database/Esqueleto/Internal/Internal.hs

View workflow job for this annotation

GitHub Actions / build (3.10.2.1, 8.8.4)

The import of ‘Database.Persist’ is redundant

Check warning on line 73 in src/Database/Esqueleto/Internal/Internal.hs

View workflow job for this annotation

GitHub Actions / build (3.10.2.1, 9.2.2)

The import of ‘Database.Persist’ is redundant

Check warning on line 73 in src/Database/Esqueleto/Internal/Internal.hs

View workflow job for this annotation

GitHub Actions / build (3.10.2.1, 9.2.2)

The import of ‘Database.Persist’ is redundant

Check warning on line 73 in src/Database/Esqueleto/Internal/Internal.hs

View workflow job for this annotation

GitHub Actions / build (3.10.2.1, 9.4.5)

The import of ‘Database.Persist’ is redundant

Check warning on line 73 in src/Database/Esqueleto/Internal/Internal.hs

View workflow job for this annotation

GitHub Actions / build (3.10.2.1, 9.4.5)

The import of ‘Database.Persist’ is redundant

Check warning on line 73 in src/Database/Esqueleto/Internal/Internal.hs

View workflow job for this annotation

GitHub Actions / build (3.10.2.1, 9.6.2)

The import of ‘Database.Persist’ is redundant

Check warning on line 73 in src/Database/Esqueleto/Internal/Internal.hs

View workflow job for this annotation

GitHub Actions / build (3.10.2.1, 9.6.2)

The import of ‘Database.Persist’ is redundant

Check warning on line 73 in src/Database/Esqueleto/Internal/Internal.hs

View workflow job for this annotation

GitHub Actions / build (3.10.2.1, 9.8.1)

The import of ‘Database.Persist’ is redundant

Check warning on line 73 in src/Database/Esqueleto/Internal/Internal.hs

View workflow job for this annotation

GitHub Actions / build (3.10.2.1, 9.8.1)

The import of ‘Database.Persist’ is redundant
import qualified Database.Persist
import Database.Persist.Sql.Util
( entityColumnCount
Expand Down Expand Up @@ -1319,7 +1319,7 @@
unique = finalR uniqueConstructor
-- there must be a better way to get the constrain name from a unique, make this not a list search
filterF = (==) (persistUniqueToFieldNames unique) . uniqueFields
uniqueDef = head . filter filterF . getEntityUniques . entityDef $ proxy

Check warning on line 1322 in src/Database/Esqueleto/Internal/Internal.hs

View workflow job for this annotation

GitHub Actions / build (3.10.2.1, 9.8.1)

In the use of ‘head’

Check warning on line 1322 in src/Database/Esqueleto/Internal/Internal.hs

View workflow job for this annotation

GitHub Actions / build (3.10.2.1, 9.8.1)

In the use of ‘head’

-- | Render updates to be use in a SET clause for a given sql backend.
--
Expand Down Expand Up @@ -1485,7 +1485,9 @@
-- Arranged in order of lock strength
data PostgresRowLevelLockStrength =
PostgresForUpdate
| PostgresForNoKeyUpdate
| PostgresForShare
| PostgresForKeyShare
deriving (Ord, Eq)

data LockingOfClause where
Expand Down Expand Up @@ -3254,7 +3256,9 @@
<> makeLockingBehavior (postgresOnLockedBehavior l)
makeLockingStrength :: PostgresRowLevelLockStrength -> (TLB.Builder, [PersistValue])
makeLockingStrength PostgresForUpdate = plain "FOR UPDATE"
makeLockingStrength PostgresForNoKeyUpdate = plain "FOR NO KEY UPDATE"
makeLockingStrength PostgresForShare = plain "FOR SHARE"
makeLockingStrength PostgresForKeyShare = plain "FOR KEY SHARE"

makeLockingBehavior :: OnLockedBehavior -> (TLB.Builder, [PersistValue])
makeLockingBehavior NoWait = plain "NOWAIT"
Expand Down
19 changes: 18 additions & 1 deletion src/Database/Esqueleto/PostgreSQL.hs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@
, wait
, skipLocked
, forUpdateOf
, forNoKeyUpdateOf
, forShareOf
, forKeyShareOf
, filterWhere
, values
-- * Internal
Expand Down Expand Up @@ -238,7 +240,7 @@
queryVals =
addVals updateVals
xs <- rawSql queryText queryVals
pure (head xs)

Check warning on line 243 in src/Database/Esqueleto/PostgreSQL.hs

View workflow job for this annotation

GitHub Actions / build (3.10.2.1, 9.8.1)

In the use of ‘head’

Check warning on line 243 in src/Database/Esqueleto/PostgreSQL.hs

View workflow job for this annotation

GitHub Actions / build (3.10.2.1, 9.8.1)

In the use of ‘head’
#else
uDef = toUniqueDef uniqueKey
handler conn f = fmap head $ uncurry rawSql $
Expand Down Expand Up @@ -280,7 +282,7 @@
-- @since 3.1.3
insertSelectWithConflict
:: forall a m val backend
. (FinalResult a, KnowResult a ~ Unique val, MonadIO m, PersistEntity val, SqlBackendCanWrite backend)

Check warning on line 285 in src/Database/Esqueleto/PostgreSQL.hs

View workflow job for this annotation

GitHub Actions / build (3.10.2.1, 9.4.5)

The use of ‘~’ without TypeOperators

Check warning on line 285 in src/Database/Esqueleto/PostgreSQL.hs

View workflow job for this annotation

GitHub Actions / build (3.10.2.1, 9.4.5)

The use of ‘~’ without TypeOperators

Check warning on line 285 in src/Database/Esqueleto/PostgreSQL.hs

View workflow job for this annotation

GitHub Actions / build (3.10.2.1, 9.6.2)

The use of ‘~’ without TypeOperators

Check warning on line 285 in src/Database/Esqueleto/PostgreSQL.hs

View workflow job for this annotation

GitHub Actions / build (3.10.2.1, 9.6.2)

The use of ‘~’ without TypeOperators

Check warning on line 285 in src/Database/Esqueleto/PostgreSQL.hs

View workflow job for this annotation

GitHub Actions / build (3.10.2.1, 9.8.1)

The use of ‘~’ without TypeOperators

Check warning on line 285 in src/Database/Esqueleto/PostgreSQL.hs

View workflow job for this annotation

GitHub Actions / build (3.10.2.1, 9.8.1)

The use of ‘~’ without TypeOperators
=> a
-- ^ Unique constructor or a unique, this is used just to get the name of
-- the postgres constraint, the value(s) is(are) never used, so if you have
Expand All @@ -300,7 +302,7 @@
-- @since 3.1.3
insertSelectWithConflictCount
:: forall a val m backend
. (FinalResult a, KnowResult a ~ Unique val, MonadIO m, PersistEntity val,

Check warning on line 305 in src/Database/Esqueleto/PostgreSQL.hs

View workflow job for this annotation

GitHub Actions / build (3.10.2.1, 9.4.5)

The use of ‘~’ without TypeOperators

Check warning on line 305 in src/Database/Esqueleto/PostgreSQL.hs

View workflow job for this annotation

GitHub Actions / build (3.10.2.1, 9.4.5)

The use of ‘~’ without TypeOperators

Check warning on line 305 in src/Database/Esqueleto/PostgreSQL.hs

View workflow job for this annotation

GitHub Actions / build (3.10.2.1, 9.6.2)

The use of ‘~’ without TypeOperators

Check warning on line 305 in src/Database/Esqueleto/PostgreSQL.hs

View workflow job for this annotation

GitHub Actions / build (3.10.2.1, 9.6.2)

The use of ‘~’ without TypeOperators

Check warning on line 305 in src/Database/Esqueleto/PostgreSQL.hs

View workflow job for this annotation

GitHub Actions / build (3.10.2.1, 9.8.1)

The use of ‘~’ without TypeOperators

Check warning on line 305 in src/Database/Esqueleto/PostgreSQL.hs

View workflow job for this annotation

GitHub Actions / build (3.10.2.1, 9.8.1)

The use of ‘~’ without TypeOperators
SqlBackendCanWrite backend)
=> a
-> SqlQuery (SqlExpr (Insertion val))
Expand Down Expand Up @@ -469,11 +471,26 @@
forUpdateOf lockableEntities onLockedBehavior =
putLocking $ PostgresLockingClauses [PostgresLockingKind PostgresForUpdate (Just $ LockingOfClause lockableEntities) onLockedBehavior]

-- | `FOR NO KEY UPDATE OF` syntax for postgres locking
-- allows locking of specific tables with a no key update lock in a view or join
--
-- @since 3.5.13.0
forNoKeyUpdateOf :: LockableEntity a => a -> OnLockedBehavior -> SqlQuery ()
forNoKeyUpdateOf lockableEntities onLockedBehavior =
putLocking $ PostgresLockingClauses [PostgresLockingKind PostgresForNoKeyUpdate (Just $ LockingOfClause lockableEntities) onLockedBehavior]

-- | `FOR SHARE OF` syntax for postgres locking
-- allows locking of specific tables with a share lock in a view or join
--
-- @since 3.5.9.0

forShareOf :: LockableEntity a => a -> OnLockedBehavior -> SqlQuery ()
forShareOf lockableEntities onLockedBehavior =
putLocking $ PostgresLockingClauses [PostgresLockingKind PostgresForShare (Just $ LockingOfClause lockableEntities) onLockedBehavior]

-- | `FOR KEY SHARE OF` syntax for postgres locking
-- allows locking of specific tables with a key share lock in a view or join
--
-- @since 3.5.13.0
forKeyShareOf :: LockableEntity a => a -> OnLockedBehavior -> SqlQuery ()
forKeyShareOf lockableEntities onLockedBehavior =
putLocking $ PostgresLockingClauses [PostgresLockingKind PostgresForKeyShare (Just $ LockingOfClause lockableEntities) onLockedBehavior]
4 changes: 4 additions & 0 deletions test/PostgreSQL/Test.hs
Original file line number Diff line number Diff line change
Expand Up @@ -1243,7 +1243,9 @@ testPostgresqlLocking = do
p <- Experimental.from $ table @Person
EP.forUpdateOf p EP.skipLocked
EP.forUpdateOf p EP.skipLocked
EP.forNoKeyUpdateOf p EP.skipLocked
EP.forShareOf p EP.skipLocked
EP.forKeyShareOf p EP.skipLocked
conn <- ask
let res1 = toText conn multipleLockingQuery
resExpected =
Expand All @@ -1253,7 +1255,9 @@ testPostgresqlLocking = do
,"FROM \"Person\""
,"FOR UPDATE OF \"Person\" SKIP LOCKED"
,"FOR UPDATE OF \"Person\" SKIP LOCKED"
,"FOR NO KEY UPDATE OF \"Person\" SKIP LOCKED"
,"FOR SHARE OF \"Person\" SKIP LOCKED"
,"FOR KEY SHARE OF \"Person\" SKIP LOCKED"
]

asserting $ res1 `shouldBe` resExpected
Expand Down
Loading