packages feed

orville-postgresql-1.0.0.0: src/Orville/PostgreSQL/Internal/RowCountExpectation.hs

{- |
Copyright : Flipstone Technology Partners 2023
License   : MIT
Stability : Stable

@since 1.0.0.0
-}
module Orville.PostgreSQL.Internal.RowCountExpectation
  ( expectExactlyOneRow
  , expectAtMostOneRow
  )
where

import Control.Exception (Exception, throwIO)
import Control.Monad.IO.Class (MonadIO (liftIO))

{- |
  INTERNAL: This should really never get thrown in the real world. It would be
  thrown if the returning clause from an insert statement for a single record
  returned 0 records or more than 1 record.

@since 1.0.0.0
-}
newtype RowCountExpectationError
  = RowCountExpectationError String
  deriving (Show)

instance Exception RowCountExpectationError

expectExactlyOneRow :: MonadIO m => String -> [a] -> m a
expectExactlyOneRow caller rows =
  case rows of
    [row] ->
      pure row
    _ ->
      liftIO . throwIO . RowCountExpectationError $
        caller
          <> ": Expected exactly one row to be returned, but got "
          <> show (length rows)

expectAtMostOneRow :: MonadIO m => String -> [a] -> m (Maybe a)
expectAtMostOneRow caller rows =
  case rows of
    [] ->
      pure Nothing
    [row] ->
      pure (Just row)
    _ ->
      liftIO . throwIO . RowCountExpectationError $
        caller
          <> ": Expected exactly one row to be returned, but got "
          <> show (length rows)