graphql-engine/server/src-lib/Hasura/SQL/Error.hs

98 lines
3.2 KiB
Haskell
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

-- | Functions and datatypes for interpreting Postgres errors.
module Hasura.SQL.Error
( PGErrorType(..)
, _PGDataException
, _PGIntegrityConstraintViolation
, _PGSyntaxErrorOrAccessRuleViolation
, pgErrorType
, PGErrorCode(..)
, _PGErrorGeneric
, _PGErrorSpecific
, PGDataException(..)
, PGIntegrityConstraintViolation(..)
, PGSyntaxErrorOrAccessRuleViolation(..)
) where
import Hasura.Prelude
import Control.Lens.TH (makePrisms)
import qualified Data.Text as T
import qualified Database.PG.Query.Connection as Q
-- | The top-level error code type. Errors in Postgres are divided into different /classes/, which
-- are further subdivided into individual error codes. Even if a particular status code is not known
-- to the application, its possible to determine its class and handle it appropriately.
data PGErrorType
= PGDataException !(Maybe (PGErrorCode PGDataException))
| PGIntegrityConstraintViolation !(Maybe (PGErrorCode PGIntegrityConstraintViolation))
| PGSyntaxErrorOrAccessRuleViolation !(Maybe (PGErrorCode PGSyntaxErrorOrAccessRuleViolation))
deriving (Show, Eq)
data PGErrorCode a
= PGErrorGeneric
-- ^ represents errors that have the non-specific @000@ status code
| PGErrorSpecific !a
-- ^ represents errors with a known, more specific status code
deriving (Show, Eq, Functor)
data PGDataException
= PGInvalidDatetimeFormat
| PGInvalidParameterValue
| PGInvalidEscapeSequence
| PGInvalidTextRepresentation
deriving (Show, Eq)
data PGIntegrityConstraintViolation
= PGRestrictViolation
| PGNotNullViolation
| PGForeignKeyViolation
| PGUniqueViolation
| PGCheckViolation
| PGExclusionViolation
deriving (Show, Eq)
data PGSyntaxErrorOrAccessRuleViolation
= PGUndefinedObject
| PGInvalidColumnReference
deriving (Show, Eq)
$(makePrisms ''PGErrorType)
$(makePrisms ''PGErrorCode)
pgErrorType :: Q.PGStmtErrDetail -> Maybe PGErrorType
pgErrorType errorDetails = parseTypes =<< Q.edStatusCode errorDetails
where
parseTypes fullCodeText = choice
[ withClass "22" PGDataException
[ code "007" PGInvalidDatetimeFormat
, code "023" PGInvalidParameterValue
, code "025" PGInvalidEscapeSequence
, code "P02" PGInvalidTextRepresentation
]
, withClass "23" PGIntegrityConstraintViolation
[ code "001" PGRestrictViolation
, code "502" PGNotNullViolation
, code "503" PGForeignKeyViolation
, code "505" PGUniqueViolation
, code "514" PGCheckViolation
, code "P01" PGExclusionViolation
]
, withClass "42" PGSyntaxErrorOrAccessRuleViolation
[ code "704" PGUndefinedObject
, code "P10" PGInvalidColumnReference
]
]
where
(classText, codeText) = T.splitAt 2 fullCodeText
withClass :: T.Text -> (Maybe a -> b) -> [Maybe a] -> Maybe b
withClass expectedClassText mkClass codes =
guard (classText == expectedClassText) $> mkClass (choice codes)
code :: T.Text -> a -> Maybe (PGErrorCode a)
code expectedCodeText codeValue =
guard (codeText == expectedCodeText) $> PGErrorSpecific codeValue