diff options
Diffstat (limited to 'src/Language/GraphQL/Error.hs')
| -rw-r--r-- | src/Language/GraphQL/Error.hs | 80 |
1 files changed, 50 insertions, 30 deletions
diff --git a/src/Language/GraphQL/Error.hs b/src/Language/GraphQL/Error.hs index 59719b0..4c37f6a 100644 --- a/src/Language/GraphQL/Error.hs +++ b/src/Language/GraphQL/Error.hs @@ -1,3 +1,4 @@ +{-# LANGUAGE DuplicateRecordFields #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RecordWildCards #-} @@ -5,7 +6,9 @@ module Language.GraphQL.Error ( parseError , CollectErrsT + , Error(..) , Resolution(..) + , Response(..) , addErr , addErrMsg , runCollectErrs @@ -13,12 +16,16 @@ module Language.GraphQL.Error ) where import Control.Monad.Trans.State (StateT, modify, runStateT) -import qualified Data.Aeson as Aeson import Data.HashMap.Strict (HashMap) +import Data.Sequence (Seq(..), (|>)) +import qualified Data.Sequence as Seq import Data.Text (Text) +import qualified Data.Text as Text import Data.Void (Void) import Language.GraphQL.AST.Document (Name) +import Language.GraphQL.Execute.Coerce import Language.GraphQL.Type.Schema +import Prelude hiding (null) import Text.Megaparsec ( ParseErrorBundle(..) , PosState(..) @@ -31,59 +38,72 @@ import Text.Megaparsec -- | Executor context. data Resolution m = Resolution - { errors :: [Aeson.Value] + { errors :: Seq Error , types :: HashMap Name (Type m) } -- | Wraps a parse error into a list of errors. -parseError :: Applicative f => ParseErrorBundle Text Void -> f Aeson.Value +parseError :: (Applicative f, Serialize a) + => ParseErrorBundle Text Void + -> f (Response a) parseError ParseErrorBundle{..} = - pure $ Aeson.object [("errors", Aeson.toJSON $ fst $ foldl go ([], bundlePosState) bundleErrors)] + pure $ Response null $ fst + $ foldl go (Seq.empty, bundlePosState) bundleErrors where - errorObject s SourcePos{..} = Aeson.object - [ ("message", Aeson.toJSON $ init $ parseErrorTextPretty s) - , ("line", Aeson.toJSON $ unPos sourceLine) - , ("column", Aeson.toJSON $ unPos sourceColumn) - ] + errorObject s SourcePos{..} = Error + (Text.pack $ init $ parseErrorTextPretty s) + (unPos' sourceLine) + (unPos' sourceColumn) + unPos' = fromIntegral . unPos go (result, state) x = let (_, newState) = reachOffset (errorOffset x) state sourcePosition = pstateSourcePos newState - in (errorObject x sourcePosition : result, newState) + in (result |> errorObject x sourcePosition, newState) -- | A wrapper to pass error messages around. type CollectErrsT m = StateT (Resolution m) m -- | Adds an error to the list of errors. -addErr :: Monad m => Aeson.Value -> CollectErrsT m () +addErr :: Monad m => Error -> CollectErrsT m () addErr v = modify appender where - appender resolution@Resolution{..} = resolution{ errors = v : errors } + appender :: Monad m => Resolution m -> Resolution m + appender resolution@Resolution{..} = resolution{ errors = errors |> v } -makeErrorMessage :: Text -> Aeson.Value -makeErrorMessage s = Aeson.object [("message", Aeson.toJSON s)] +makeErrorMessage :: Text -> Error +makeErrorMessage s = Error s 0 0 -- | Constructs a response object containing only the error with the given --- message. -singleError :: Text -> Aeson.Value -singleError message = Aeson.object - [ ("errors", Aeson.toJSON [makeErrorMessage message]) - ] +-- message. +singleError :: Serialize a => Text -> Response a +singleError message = Response null $ Seq.singleton $ makeErrorMessage message -- | Convenience function for just wrapping an error message. addErrMsg :: Monad m => Text -> CollectErrsT m () addErrMsg = addErr . makeErrorMessage +-- | @GraphQL@ error. +data Error = Error + { message :: Text + , line :: Word + , column :: Word + } deriving (Eq, Show) + +-- | The server\'s response describes the result of executing the requested +-- operation if successful, and describes any errors encountered during the +-- request. +data Response a = Response + { data' :: a + , errors :: Seq Error + } deriving (Eq, Show) + -- | Runs the given query computation, but collects the errors into an error --- list, which is then sent back with the data. -runCollectErrs :: Monad m +-- list, which is then sent back with the data. +runCollectErrs :: (Monad m, Serialize a) => HashMap Name (Type m) - -> CollectErrsT m Aeson.Value - -> m Aeson.Value + -> CollectErrsT m a + -> m (Response a) runCollectErrs types' res = do - (dat, Resolution{..}) <- runStateT res $ Resolution{ errors = [], types = types' } - if null errors - then return $ Aeson.object [("data", dat)] - else return $ Aeson.object - [ ("data", dat) - , ("errors", Aeson.toJSON $ reverse errors) - ] + (dat, Resolution{..}) <- runStateT res + $ Resolution{ errors = Seq.empty, types = types' } + pure $ Response dat errors |
