content: {-|
  Module: Squeal.PostgreSQL.Session.Exception
  Description: exceptions
  Copyright: (c) Eitan Chatav, 2019
  Maintainer: eitan@morphism.tech
  Stability: experimental
  
  exceptions
  -}
  
  {-# LANGUAGE
      OverloadedStrings
    , PatternSynonyms
  #-}
  
  module Squeal.PostgreSQL.Session.Exception
    ( SquealException (..)
    , pattern UniqueViolation
    , pattern CheckViolation
    , pattern SerializationFailure
    , pattern DeadlockDetected
    , SQLState (..)
    , LibPQ.ExecStatus (..)
    , catchSqueal
    , handleSqueal
    , trySqueal
    , throwSqueal
    ) where
  
  import Control.Monad.Catch
  import Data.ByteString (ByteString)
  import Data.Text (Text)
  
  import qualified Database.PostgreSQL.LibPQ as LibPQ
  
  -- $setup
  -- >>> import Squeal.PostgreSQL
  
  -- | the state of LibPQ
  data SQLState = SQLState
    { sqlExecStatus :: LibPQ.ExecStatus
    , sqlStateCode :: ByteString
      -- ^ https://www.postgresql.org/docs/current/static/errcodes-appendix.html
    , sqlErrorMessage :: ByteString
    } deriving (Eq, Show)
  
  -- | `Exception`s that can be thrown by Squeal.
  data SquealException
    = SQLException SQLState
    -- ^ SQL exception state
    | ConnectionException Text
    -- ^ `Database.PostgreSQL.LibPQ` function connection exception
    | DecodingException Text Text
    -- ^ decoding exception function and error message
    | ColumnsException Text LibPQ.Column
    -- ^ unexpected number of columns
    | RowsException Text LibPQ.Row LibPQ.Row
    -- ^ too few rows, expected at least and actual number of rows
    deriving (Eq, Show)
  instance Exception SquealException
  
  -- | A pattern for unique violation exceptions.
  pattern UniqueViolation :: ByteString -> SquealException
  pattern UniqueViolation msg =
    SQLException (SQLState LibPQ.FatalError "23505" msg)
  -- | A pattern for check constraint violation exceptions.
  pattern CheckViolation :: ByteString -> SquealException
  pattern CheckViolation msg =
    SQLException (SQLState LibPQ.FatalError "23514" msg)
  -- | A pattern for serialization failure exceptions.
  pattern SerializationFailure :: ByteString -> SquealException
  pattern SerializationFailure msg =
    SQLException (SQLState LibPQ.FatalError "40001" msg)
  -- | A pattern for deadlock detection exceptions.
  pattern DeadlockDetected :: ByteString -> SquealException
  pattern DeadlockDetected msg =
    SQLException (SQLState LibPQ.FatalError "40P01" msg)
  
  -- | Catch `SquealException`s.
  catchSqueal
    :: MonadCatch m
    => m a
    -> (SquealException -> m a) -- ^ handler
    -> m a
  catchSqueal = catch
  
  -- | Handle `SquealException`s.
  handleSqueal
    :: MonadCatch m
    => (SquealException -> m a) -- ^ handler
    -> m a -> m a
  handleSqueal = handle
  
  -- | `Either` return a `SquealException` or a result.
  trySqueal :: MonadCatch m => m a -> m (Either SquealException a)
  trySqueal = try
  
  -- | Throw `SquealException`s.
  throwSqueal :: MonadThrow m => SquealException -> m a
  throwSqueal = throwM
  