btc-lsp-0.1.0.0: src/BtcLsp/Storage/Util.hs
module BtcLsp.Storage.Util
( lockByTable,
lockByRow,
lockByUnique,
)
where
import BtcLsp.Class.Storage
import BtcLsp.Data.Kind
import BtcLsp.Import.External
import qualified BtcLsp.Import.Psql as Psql
import qualified Database.Esqueleto.Legacy as Esqueleto
import qualified Universum
-- | This ugly fake type is here just to
-- make Haskell type system compatible
-- with weird Postgres semantics
-- for pg_advisory_xact_lock
data VoidSQL
= VoidSQL
instance Psql.RawSql VoidSQL where
rawSqlCols _ _ = (1, [])
rawSqlColCountReason _ = ""
rawSqlProcessRow [Psql.PersistNull] = Right VoidSQL
rawSqlProcessRow _ = Left "Unexpected VoidSQL expr"
lockByTable :: (MonadIO m) => Table -> Psql.SqlPersistT m ()
lockByTable x =
void
( Psql.rawSql
"SELECT pg_advisory_xact_lock(?)"
[Psql.PersistInt64 . from $ fromEnum x] ::
(MonadIO m) => Psql.SqlPersistT m [VoidSQL]
)
lockByRow ::
( MonadIO m,
HasTable a,
Psql.ToBackendKey Psql.SqlBackend a
) =>
Psql.Key a ->
Psql.SqlPersistT m a
lockByRow rowId = do
void
( Psql.rawSql
"SELECT pg_advisory_xact_lock(?,?)"
[ Psql.PersistInt64 . from . fromEnum $ getTable rowId,
Psql.PersistInt64 $ Psql.fromSqlKey rowId
] ::
(MonadIO m) => Psql.SqlPersistT m [VoidSQL]
)
maybeM
(error $ "Impossible missing row " <> Universum.show rowId)
pure
. (entityVal <<$>>)
. (listToMaybe <$>)
$ Psql.select $
Psql.from $ \row -> do
Psql.locking Psql.ForUpdate
Psql.where_
( row Psql.^. Psql.persistIdField
Psql.==. Psql.val rowId
)
pure row
lockByUnique ::
( MonadIO m,
HasTable a,
Psql.ToBackendKey Psql.SqlBackend a
) =>
Psql.Unique a ->
Psql.SqlPersistT m (Maybe (Entity a))
lockByUnique =
maybeM
(pure Nothing)
(\(Entity x _) -> Just . Entity x <$> lockByRow x)
. Esqueleto.getBy