summaryrefslogtreecommitdiff
path: root/src/Language/GraphQL/Execute/Execution.hs
diff options
context:
space:
mode:
Diffstat (limited to 'src/Language/GraphQL/Execute/Execution.hs')
-rw-r--r--src/Language/GraphQL/Execute/Execution.hs93
1 files changed, 69 insertions, 24 deletions
diff --git a/src/Language/GraphQL/Execute/Execution.hs b/src/Language/GraphQL/Execute/Execution.hs
index 140df81..8a3f400 100644
--- a/src/Language/GraphQL/Execute/Execution.hs
+++ b/src/Language/GraphQL/Execute/Execution.hs
@@ -19,17 +19,23 @@ import Data.Sequence (Seq(..))
import Data.Text (Text)
import qualified Data.Text as Text
import qualified Data.Sequence as Seq
-import Language.GraphQL.AST.Document (Name)
+import Language.GraphQL.AST.Core
import Language.GraphQL.Error
+import Language.GraphQL.Execute.Coerce
import Language.GraphQL.Execute.Transform
import Language.GraphQL.Trans
-import Language.GraphQL.Type.Definition
+import qualified Language.GraphQL.Type.Definition as Definition
+import qualified Language.GraphQL.Type.In as In
import qualified Language.GraphQL.Type.Out as Out
import Language.GraphQL.Type.Schema
-resolveFieldValue :: Monad m => Value -> Field m -> ActionT m a -> m (Either Text a)
-resolveFieldValue result (Field _ _ args _) =
- flip runReaderT (Context {arguments=args, values=result})
+resolveFieldValue :: Monad m
+ => Definition.Value
+ -> Definition.Subs
+ -> ActionT m a
+ -> m (Either Text a)
+resolveFieldValue result args =
+ flip runReaderT (Context {arguments = Arguments args, values = result})
. runExceptT
. runActionT
@@ -54,10 +60,10 @@ aliasOrName (Field alias name _ _) = fromMaybe name alias
resolveAbstractType :: Monad m
=> AbstractType m
- -> HashMap Name Value
+ -> HashMap Name Definition.Value
-> CollectErrsT m (Maybe (Out.ObjectType m))
resolveAbstractType abstractType values'
- | Just (String typeName) <- HashMap.lookup "__typename" values' = do
+ | Just (Definition.String typeName) <- HashMap.lookup "__typename" values' = do
types' <- gets types
case HashMap.lookup typeName types' of
Just (ObjectType objectType) ->
@@ -97,40 +103,44 @@ instanceOf objectType (AbstractUnionType unionType) =
in acc || this == that
executeField :: Monad m
- => Value
+ => Definition.Value
-> Out.Resolver m
-> Field m
-> CollectErrsT m Aeson.Value
executeField prev (Out.Resolver fieldDefinition resolver) field = do
- let Out.Field _ fieldType _ = fieldDefinition
- answer <- lift $ resolveFieldValue prev field resolver
- case answer of
- Right result -> completeValue fieldType field result
- Left errorMessage -> errmsg errorMessage
+ let Out.Field _ fieldType argumentDefinitions = fieldDefinition
+ let Field _ _ arguments' _ = field
+ case coerceArgumentValues argumentDefinitions arguments' of
+ Nothing -> errmsg "Argument coercing failed."
+ Just argumentValues -> do
+ answer <- lift $ resolveFieldValue prev argumentValues resolver
+ case answer of
+ Right result -> completeValue fieldType field result
+ Left errorMessage -> errmsg errorMessage
completeValue :: Monad m
=> Out.Type m
-> Field m
- -> Value
+ -> Definition.Value
-> CollectErrsT m Aeson.Value
-completeValue _ _ Null = pure Aeson.Null
-completeValue _ _ (Int integer) = pure $ Aeson.toJSON integer
-completeValue _ _ (Boolean boolean') = pure $ Aeson.Bool boolean'
-completeValue _ _ (Float float') = pure $ Aeson.toJSON float'
-completeValue _ _ (Enum enum) = pure $ Aeson.String enum
-completeValue _ _ (String string') = pure $ Aeson.String string'
+completeValue _ _ Definition.Null = pure Aeson.Null
+completeValue _ _ (Definition.Int integer) = pure $ Aeson.toJSON integer
+completeValue _ _ (Definition.Boolean boolean') = pure $ Aeson.Bool boolean'
+completeValue _ _ (Definition.Float float') = pure $ Aeson.toJSON float'
+completeValue _ _ (Definition.Enum enum) = pure $ Aeson.String enum
+completeValue _ _ (Definition.String string') = pure $ Aeson.String string'
completeValue (Out.ObjectBaseType objectType) (Field _ _ _ seqSelection) result =
executeSelectionSet result objectType seqSelection
-completeValue (Out.ListBaseType listType) selectionField (List list) =
+completeValue (Out.ListBaseType listType) selectionField (Definition.List list) =
Aeson.toJSON <$> traverse (completeValue listType selectionField) list
completeValue (Out.InterfaceBaseType interfaceType) (Field _ _ _ seqSelection) result
- | Object objectMap <- result = do
+ | Definition.Object objectMap <- result = do
abstractType <- resolveAbstractType (AbstractInterfaceType interfaceType) objectMap
case abstractType of
Just objectType -> executeSelectionSet result objectType seqSelection
Nothing -> errmsg "Value completion failed."
completeValue (Out.UnionBaseType unionType) (Field _ _ _ seqSelection) result
- | Object objectMap <- result = do
+ | Definition.Object objectMap <- result = do
abstractType <- resolveAbstractType (AbstractUnionType unionType) objectMap
case abstractType of
Just objectType -> executeSelectionSet result objectType seqSelection
@@ -144,7 +154,7 @@ errmsg errorMessage = addErrMsg errorMessage >> pure Aeson.Null
-- to each 'Selection'. Resolves into a value containing the resolved
-- 'Selection', or a null value and error information.
executeSelectionSet :: Monad m
- => Value
+ => Definition.Value
-> Out.ObjectType m
-> Seq (Selection m)
-> CollectErrsT m Aeson.Value
@@ -161,3 +171,38 @@ executeSelectionSet result objectType@(Out.ObjectType _ _ _ resolvers) selection
| Just typeField <- lookupResolver name =
executeField result typeField fld
| otherwise = errmsg $ Text.unwords ["field", name, "not resolved."]
+
+coerceArgumentValues
+ :: HashMap Name In.Argument
+ -> HashMap Name Input
+ -> Maybe Definition.Subs
+coerceArgumentValues argumentDefinitions argumentValues =
+ HashMap.foldrWithKey forEach (pure mempty) argumentDefinitions
+ where
+ forEach variableName (In.Argument _ variableType defaultValue) =
+ matchFieldValues coerceArgumentValue argumentValues variableName variableType defaultValue
+ coerceArgumentValue inputType (Int integer) =
+ coerceInputLiteral inputType (Definition.Int integer)
+ coerceArgumentValue inputType (Boolean boolean) =
+ coerceInputLiteral inputType (Definition.Boolean boolean)
+ coerceArgumentValue inputType (String string) =
+ coerceInputLiteral inputType (Definition.String string)
+ coerceArgumentValue inputType (Float float) =
+ coerceInputLiteral inputType (Definition.Float float)
+ coerceArgumentValue inputType (Enum enum) =
+ coerceInputLiteral inputType (Definition.Enum enum)
+ coerceArgumentValue inputType Null
+ | In.isNonNullType inputType = Nothing
+ | otherwise = coerceInputLiteral inputType Definition.Null
+ coerceArgumentValue (In.ListBaseType inputType) (List list) =
+ let coerceItem = coerceInputLiteral inputType
+ in Definition.List <$> traverse coerceItem list
+ coerceArgumentValue (In.InputObjectBaseType inputType) (Object object)
+ | In.InputObjectType _ _ inputFields <- inputType =
+ let go = forEachField object
+ resultMap = HashMap.foldrWithKey go (pure mempty) inputFields
+ in Definition.Object <$> resultMap
+ coerceArgumentValue _ (Variable variable) = pure variable
+ coerceArgumentValue _ _ = Nothing
+ forEachField object variableName (In.InputField _ variableType defaultValue) =
+ matchFieldValues coerceArgumentValue object variableName variableType defaultValue