packages feed

btc-lsp-0.1.0.0: src/BtcLsp/Storage/Model/User.hs

{-# LANGUAGE TypeApplications #-}

module BtcLsp.Storage.Model.User
  ( createVerifySql,
  )
where

import BtcLsp.Data.Orphan ()
import BtcLsp.Import hiding (Storage (..))
import qualified BtcLsp.Import.Psql as Psql
import qualified BtcLsp.Storage.Util as Util

--
-- NOTE : We will not create withVerifiedNonce
-- for now to reduce complexity overall.
-- Plus this combinator enables all kinds of
-- possibilities for deadlocks.
--
createVerifySql ::
  ( MonadIO m
  ) =>
  NodePubKey ->
  Nonce ->
  ReaderT Psql.SqlBackend m (Either Failure (Entity User))
createVerifySql pub nonce = do
  ct <- getCurrentTime
  let zeroRow =
        User
          { userNodePubKey = pub,
            userLatestNonce = from @Word64 0,
            userInsertedAt = ct,
            userUpdatedAt = ct
          }
  rowId <-
    entityKey
      <$> Psql.upsertBy
        (UniqueUser pub)
        zeroRow
        [ UserUpdatedAt Psql.=. Psql.val ct
        ]
  existingRow <- Util.lockByRow rowId
  if (existingRow == zeroRow)
    || (userLatestNonce existingRow < nonce)
    then
      Right
        <$> Psql.upsertBy
          (UniqueUser pub)
          zeroRow
            { userLatestNonce = nonce
            }
          [ UserLatestNonce Psql.=. Psql.val nonce,
            UserUpdatedAt Psql.=. Psql.val ct
          ]
    else
      pure
        . Left
        $ FailureInp FailureNonce