summaryrefslogtreecommitdiff
path: root/src/Language/GraphQL/Execute.hs
diff options
context:
space:
mode:
authorEugen Wissner <belka@caraus.de>2020-05-21 10:20:59 +0200
committerEugen Wissner <belka@caraus.de>2020-05-21 10:20:59 +0200
commitc3ecfece0358d79dd1da6efbe6ab83e63bf50f88 (patch)
tree1ff3de1ddd4bf2e04da57cd6d1c889520c263427 /src/Language/GraphQL/Execute.hs
parenta5c44f30facdaabd94ed25953a3bd88005efa868 (diff)
downloadgraphql-c3ecfece0358d79dd1da6efbe6ab83e63bf50f88.tar.gz
Coerce variable values
Diffstat (limited to 'src/Language/GraphQL/Execute.hs')
-rw-r--r--src/Language/GraphQL/Execute.hs126
1 files changed, 96 insertions, 30 deletions
diff --git a/src/Language/GraphQL/Execute.hs b/src/Language/GraphQL/Execute.hs
index e1bacbc..e21d5de 100644
--- a/src/Language/GraphQL/Execute.hs
+++ b/src/Language/GraphQL/Execute.hs
@@ -9,42 +9,42 @@ module Language.GraphQL.Execute
import qualified Data.Aeson as Aeson
import Data.Foldable (find)
+import qualified Data.HashMap.Strict as HashMap
import Data.List.NonEmpty (NonEmpty(..))
import Data.Text (Text)
import qualified Data.Text as Text
import Language.GraphQL.AST.Document
import qualified Language.GraphQL.AST.Core as AST.Core
+import Language.GraphQL.Execute.Coerce
import qualified Language.GraphQL.Execute.Transform as Transform
import Language.GraphQL.Error
import qualified Language.GraphQL.Schema as Schema
-import Language.GraphQL.Type.Definition
+import qualified Language.GraphQL.Type.Definition as Definition
import Language.GraphQL.Type.Schema
-- | Query error types.
data QueryError
= OperationNotFound Text
| OperationNameRequired
+ | CoercionError
queryError :: QueryError -> Text
queryError (OperationNotFound operationName) = Text.unwords
["Operation", operationName, "couldn't be found in the document."]
queryError OperationNameRequired = "Missing operation name."
+queryError CoercionError = "Coercion error."
-- | 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
+execute :: (Monad m, VariableValue a)
=> Schema m -- ^ Resolvers.
- -> Schema.Subs -- ^ Variable substitution function.
+ -> HashMap.HashMap Name a -- ^ Variable substitution function.
-> Document -- @GraphQL@ document.
-> m Aeson.Value
-execute schema subs doc =
- maybe transformError (document schema Nothing)
- $ Transform.document subs doc
- where
- transformError = return $ singleError "Schema transformation error."
+execute schema = document schema Nothing
-- | 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
@@ -52,41 +52,105 @@ execute schema subs doc =
--
-- Returns the result of the query against the schema wrapped in a /data/
-- field, or errors wrapped in an /errors/ field.
-executeWithName :: Monad m
+executeWithName :: (Monad m, VariableValue a)
=> Schema m -- ^ Resolvers
-> Text -- ^ Operation name.
- -> Schema.Subs -- ^ Variable substitution function.
+ -> HashMap.HashMap Name a -- ^ Variable substitution function.
-> Document -- ^ @GraphQL@ Document.
-> m Aeson.Value
-executeWithName schema operationName subs doc =
- maybe transformError (document schema $ Just operationName)
- $ Transform.document subs doc
- where
- transformError = return $ singleError "Schema transformation error."
+executeWithName schema operationName = document schema (Just operationName)
getOperation
:: Maybe Text
- -> AST.Core.Document
- -> Either QueryError AST.Core.Operation
-getOperation Nothing (operation' :| []) = pure operation'
+ -> Transform.Document
+ -> Either QueryError Transform.OperationDefinition
+getOperation Nothing (Transform.Document (operation' :| []) _) = pure operation'
getOperation Nothing _ = Left OperationNameRequired
-getOperation (Just operationName) document'
- | Just operation' <- find matchingName document' = pure operation'
+getOperation (Just operationName) (Transform.Document operations _)
+ | Just operation' <- find matchingName operations = 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
+ matchingName (Transform.OperationDefinition _ name _ _ _) =
+ name == Just operationName
+
+lookupInputType
+ :: Type
+ -> HashMap.HashMap Name (Definition.TypeDefinition m)
+ -> Maybe Definition.InputType
+lookupInputType (TypeNamed name) types =
+ case HashMap.lookup name types of
+ Just (Definition.ScalarTypeDefinition scalarType) ->
+ Just $ Definition.ScalarInputType scalarType
+ Just (Definition.EnumTypeDefinition enumType) ->
+ Just $ Definition.EnumInputType enumType
+ Just (Definition.InputObjectTypeDefinition objectType) ->
+ Just $ Definition.ObjectInputType objectType
+ _ -> Nothing
+lookupInputType (TypeList list) types
+ = Definition.ListInputType
+ <$> lookupInputType list types
+lookupInputType (TypeNonNull (NonNullTypeNamed nonNull)) types =
+ case HashMap.lookup nonNull types of
+ Just (Definition.ScalarTypeDefinition scalarType) ->
+ Just $ Definition.NonNullScalarInputType scalarType
+ Just (Definition.EnumTypeDefinition enumType) ->
+ Just $ Definition.NonNullEnumInputType enumType
+ Just (Definition.InputObjectTypeDefinition objectType) ->
+ Just $ Definition.NonNullObjectInputType objectType
+ _ -> Nothing
+lookupInputType (TypeNonNull (NonNullTypeList nonNull)) types
+ = Definition.NonNullListInputType
+ <$> lookupInputType nonNull types
+
+coerceVariableValues :: (Monad m, VariableValue a)
+ => Schema m
+ -> Transform.OperationDefinition
+ -> HashMap.HashMap Name a
+ -> Either QueryError Schema.Subs
+coerceVariableValues schema (Transform.OperationDefinition _ _ variables _ _) values =
+ let referencedTypes = collectReferencedTypes schema
+ in maybe (Left CoercionError) Right
+ $ foldr (coerceValue referencedTypes) (Just HashMap.empty) variables
+ where
+ coerceValue referencedTypes variableDefinition coercedValues = do
+ let VariableDefinition variableName variableTypeName _defaultValue =
+ variableDefinition
+ variableType <- lookupInputType variableTypeName referencedTypes
+ value <- HashMap.lookup variableName values
+ coercedValue <- coerceVariableValue variableType value
+ HashMap.insert variableName coercedValue <$> coercedValues
-document :: Monad m
+executeRequest :: (Monad m, VariableValue a)
=> Schema m
-> Maybe Text
- -> AST.Core.Document
+ -> HashMap.HashMap Name a
+ -> Transform.Document
+ -> Either QueryError (Transform.OperationDefinition, Schema.Subs)
+executeRequest schema operationName subs document' = do
+ operation' <- getOperation operationName document'
+ coercedValues <- coerceVariableValues schema operation' subs
+ pure (operation', coercedValues)
+
+document :: (Monad m, VariableValue a)
+ => Schema m
+ -> Maybe Text
+ -> HashMap.HashMap Name a
+ -> Document
-> m Aeson.Value
-document schema operationName document' =
- case getOperation operationName document' of
- Left error' -> pure $ singleError $ queryError error'
- Right operation' -> operation schema operation'
+document schema operationName subs document' =
+ case Transform.document document' of
+ Just transformed -> executeRequest' transformed
+ Nothing -> pure $ singleError
+ "The document doesn't contain any executable operations."
+ where
+ transformOperation fragmentTable operation' subs' =
+ case Transform.operation fragmentTable subs' operation' of
+ Just operationResult -> operation schema operationResult
+ Nothing -> pure $ singleError "Schema transformation error."
+ executeRequest' transformed@(Transform.Document _ fragmentTable) =
+ case executeRequest schema operationName subs transformed of
+ Right (operation', subs') -> transformOperation fragmentTable operation' subs'
+ Left error' -> pure $ singleError $ queryError error'
operation :: Monad m
=> Schema m
@@ -96,7 +160,8 @@ operation = schemaOperation
where
resolve queryFields = runCollectErrs
. flip Schema.resolve queryFields
- . fields
+ . fmap getResolver
+ . Definition.fields
lookupError = pure
$ singleError "Root operation type couldn't be found in the schema."
schemaOperation Schema {query} (AST.Core.Query _ fields') =
@@ -105,3 +170,4 @@ operation = schemaOperation
resolve fields' mutation
schemaOperation Schema {mutation = Nothing} (AST.Core.Mutation _ _) =
lookupError
+ getResolver (Definition.Field _ _ _ resolver) = resolver