graphql/src/Language/GraphQL/Execute.hs

108 lines
3.8 KiB
Haskell
Raw Normal View History

2017-02-10 22:40:08 +01:00
{-# LANGUAGE OverloadedStrings #-}
2020-05-14 09:17:14 +02:00
{-# LANGUAGE NamedFieldPuns #-}
-- | This module provides functions to execute a @GraphQL@ request.
2019-07-14 05:58:05 +02:00
module Language.GraphQL.Execute
( execute
2019-07-25 07:37:36 +02:00
, executeWithName
2019-07-14 05:58:05 +02:00
) where
2019-07-25 07:37:36 +02:00
import qualified Data.Aeson as Aeson
2020-05-14 09:17:14 +02:00
import Data.Foldable (find)
import Data.List.NonEmpty (NonEmpty(..))
2019-07-25 07:37:36 +02:00
import Data.Text (Text)
import qualified Data.Text as Text
2019-12-26 13:00:47 +01:00
import Language.GraphQL.AST.Document
import qualified Language.GraphQL.AST.Core as AST.Core
import qualified Language.GraphQL.Execute.Transform as Transform
import Language.GraphQL.Error
import qualified Language.GraphQL.Schema as Schema
2020-05-14 09:17:14 +02:00
import Language.GraphQL.Type.Definition
import Language.GraphQL.Type.Schema
-- | Query error types.
data QueryError
= OperationNotFound Text
| OperationNameRequired
queryError :: QueryError -> Text
queryError (OperationNotFound operationName) = Text.unwords
["Operation", operationName, "couldn't be found in the document."]
queryError OperationNameRequired = "Missing operation name."
-- | The substitution is applied to the document, and the resolvers are applied
-- to the resulting fields.
--
-- Returns the result of the query against the schema wrapped in a /data/
-- field, or errors wrapped in an /errors/ field.
execute :: Monad m
2020-05-14 09:17:14 +02:00
=> Schema m -- ^ Resolvers.
-> Schema.Subs -- ^ Variable substitution function.
2019-12-26 13:00:47 +01:00
-> Document -- @GraphQL@ document.
2019-07-25 07:37:36 +02:00
-> m Aeson.Value
execute schema subs doc =
maybe transformError (document schema Nothing)
$ Transform.document subs doc
2019-07-25 07:37:36 +02:00
where
transformError = return $ singleError "Schema transformation error."
-- | The substitution is applied to the document, and the resolvers are applied
-- to the resulting fields. The operation name can be used if the document
-- defines multiple root operations.
2019-07-25 07:37:36 +02:00
--
-- Returns the result of the query against the schema wrapped in a /data/
-- field, or errors wrapped in an /errors/ field.
executeWithName :: Monad m
2020-05-14 09:17:14 +02:00
=> Schema m -- ^ Resolvers
-> Text -- ^ Operation name.
-> Schema.Subs -- ^ Variable substitution function.
2019-12-26 13:00:47 +01:00
-> Document -- ^ @GraphQL@ Document.
2019-07-25 07:37:36 +02:00
-> m Aeson.Value
2020-05-14 09:17:14 +02:00
executeWithName schema operationName subs doc =
maybe transformError (document schema $ Just operationName)
$ Transform.document subs doc
where
2019-07-23 06:04:33 +02:00
transformError = return $ singleError "Schema transformation error."
2020-05-14 09:17:14 +02:00
getOperation
:: Maybe Text
-> AST.Core.Document
-> Either QueryError AST.Core.Operation
getOperation Nothing (operation' :| []) = pure operation'
getOperation Nothing _ = Left OperationNameRequired
getOperation (Just operationName) document'
| Just operation' <- find matchingName document' = pure operation'
| otherwise = Left $ OperationNotFound operationName
where
matchingName (AST.Core.Query (Just name') _) = operationName == name'
matchingName (AST.Core.Mutation (Just name') _) = operationName == name'
matchingName _ = False
document :: Monad m
2020-05-14 09:17:14 +02:00
=> Schema m
-> Maybe Text
-> AST.Core.Document
-> m Aeson.Value
2020-05-14 09:17:14 +02:00
document schema operationName document' =
case getOperation operationName document' of
Left error' -> pure $ singleError $ queryError error'
Right operation' -> operation schema operation'
operation :: Monad m
2020-05-14 09:17:14 +02:00
=> Schema m
-> AST.Core.Operation
-> m Aeson.Value
2020-05-14 09:17:14 +02:00
operation = schemaOperation
where
2020-05-14 09:17:14 +02:00
resolve queryFields = runCollectErrs
. flip Schema.resolve queryFields
. fields
lookupError = pure
$ singleError "Root operation type couldn't be found in the schema."
2020-05-14 09:17:14 +02:00
schemaOperation Schema {query} (AST.Core.Query _ fields') =
resolve fields' query
schemaOperation Schema {mutation = Just mutation} (AST.Core.Mutation _ fields') =
resolve fields' mutation
schemaOperation Schema {mutation = Nothing} (AST.Core.Mutation _ _) =
lookupError