@@ -2,23 +2,60 @@ module GraphQL.Execution (execute) where
22
33import Prelude
44
5−import Control.Monad.Error.Class (class MonadError)
5+import Control.Monad.Error.Class (class MonadError, throwError)
66import Data.Argonaut.Core (Json, jsonEmptyObject)
77import Data.Argonaut.Encode ((:=), (~>))
8−import Data.List (List(..))
9−import Data.Maybe (Maybe(..))
10−import Effect.Exception (Error)
8+import Data.List (List(..), find)
9+import Data.Maybe (Maybe(..), fromMaybe, maybe)
10+import Effect.Exception (Error, error)
1111import GraphQL.Execution.Result (serializeResult)
12−import GraphQL.Language.AST (DefinitionNode(..), DocumentNode(..), OperationTypeNode(..))
12+import GraphQL.Language.AST (DefinitionNode(..), DocumentNode(..), NameNode(..), OperationTypeNode(..))
1313import GraphQL.Type (Schema(..), VariableMap, output)
1414
15+
1516simpleError :: forall m. Applicative m => String -> m Json
1617simpleError e = pure $ "error" := e ~> jsonEmptyObject
1718
18−execute :: forall m a. MonadError Error m => DocumentNode -> Schema m a -> VariableMap -> m a -> m Json
19−execute (DocumentNode { definitions: Cons query Nil }) (Schema s) variables root =
20− case query of
19+
20+execute :: forall m a.
21+ MonadError Error m =>
22+ DocumentNode ->
23+ Schema m a ->
24+ VariableMap ->
25+ Maybe String ->
26+ m a ->
27+ m Json
28+execute (DocumentNode { definitions }) (Schema s) variables operation root = do
29+ -- Find the operation with the operation name given supplied. If no operation name is supplied,
30+ -- return the only operation of the document. If multiple operations are supplied without an
31+ -- operation name, or the named operation cannot be found in the document, throw an error.
32+ definitionNode <- case operation of
33+ Just operationName ->
34+ fromMaybe
35+ (throwError $ error $ "Could not find definitions with name " <> operationName <> ".")
36+ (pure <$> find (hasOperationName operationName) definitions)
37+
38+ Nothing -> case definitions of
39+ Nil -> throwError $ error "No definitions found in document."
40+ Cons query Nil -> pure query
41+ _ -> throwError $ error "Operation name is required for queries with multiple operations."
42+
43+ executionResult <- case definitionNode of
2144 OperationDefinitionNode { operation: Query, selectionSet } ->
22− serializeResult <$> output s.query (Just selectionSet) variables root
23− _ -> simpleError "Somehow received non OperationDefinitionNode for operation execution..."
24−execute _ _ _ _ = simpleError "Can only execute documents with single query"
45+ output s.query (Just selectionSet) variables root
46+
47+ OperationDefinitionNode { operation: Mutation, selectionSet } ->
48+ maybe
49+ (throwError $ error "Api does not support mutations.")
50+ (\mutation -> output mutation (Just selectionSet) variables root)
51+ s.mutation
52+
53+ _ -> throwError $ error "Unrecognised operation."
54+
55+ pure $ serializeResult executionResult
56+
57+ where
58+ hasOperationName operationName (OperationDefinitionNode { name: Just (NameNode nameNode) }) =
59+ nameNode.value == operationName
60+
61+ hasOperationName _ _ = false