graphql-engine/server/src-lib/Hasura/Backends/Postgres/SQL/Error.hs
Evie Ciobanu 9337edf096 Evie/postgres/module docs
PR-URL: https://github.com/hasura/graphql-engine-mono/pull/3563
GitOrigin-RevId: e35aafbd210d526ed53db7088e1a47f89f0b9c44
2022-02-08 09:25:35 +00:00

104 lines
3.3 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.

-- | Postgres SQL Error
--
-- Functions and datatypes for interpreting Postgres errors.
module Hasura.Backends.Postgres.SQL.Error
( PGErrorType (..),
_PGDataException,
_PGIntegrityConstraintViolation,
_PGSyntaxErrorOrAccessRuleViolation,
pgErrorType,
PGErrorCode (..),
_PGErrorGeneric,
_PGErrorSpecific,
PGDataException (..),
PGIntegrityConstraintViolation (..),
PGSyntaxErrorOrAccessRuleViolation (..),
)
where
import Control.Lens.TH (makePrisms)
import Data.Text qualified as T
import Database.PG.Query.Connection qualified as Q
import Hasura.Prelude
-- | 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
= -- | represents errors that have the non-specific @000@ status code
PGErrorGeneric
| -- | represents errors with a known, more specific status code
PGErrorSpecific !a
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 :: Text -> (Maybe a -> b) -> [Maybe a] -> Maybe b
withClass expectedClassText mkClass codes =
guard (classText == expectedClassText) $> mkClass (choice codes)
code :: Text -> a -> Maybe (PGErrorCode a)
code expectedCodeText codeValue =
guard (codeText == expectedCodeText) $> PGErrorSpecific codeValue