diff options
Diffstat (limited to 'src/Language/GraphQL/Execute/Execution.hs')
| -rw-r--r-- | src/Language/GraphQL/Execute/Execution.hs | 253 |
1 files changed, 0 insertions, 253 deletions
diff --git a/src/Language/GraphQL/Execute/Execution.hs b/src/Language/GraphQL/Execute/Execution.hs deleted file mode 100644 index 9ad4439..0000000 --- a/src/Language/GraphQL/Execute/Execution.hs +++ /dev/null @@ -1,253 +0,0 @@ -{-# LANGUAGE ExplicitForAll #-} -{-# LANGUAGE LambdaCase #-} -{-# LANGUAGE OverloadedStrings #-} -{-# LANGUAGE ViewPatterns #-} - -module Language.GraphQL.Execute.Execution - ( coerceArgumentValues - , collectFields - , executeSelectionSet - ) where - -import Control.Monad.Catch (Exception(..), MonadCatch(..)) -import Control.Monad.Trans.Class (lift) -import Control.Monad.Trans.Reader (runReaderT) -import Control.Monad.Trans.State (gets) -import Data.List.NonEmpty (NonEmpty(..)) -import qualified Data.List.NonEmpty as NonEmpty -import Data.HashMap.Strict (HashMap) -import qualified Data.HashMap.Strict as HashMap -import Data.Maybe (fromMaybe) -import Data.Sequence (Seq(..)) -import qualified Data.Text as Text -import qualified Language.GraphQL.AST as Full -import Language.GraphQL.Error -import Language.GraphQL.Execute.Coerce -import Language.GraphQL.Execute.Internal -import Language.GraphQL.Execute.OrderedMap (OrderedMap) -import qualified Language.GraphQL.Execute.OrderedMap as OrderedMap -import qualified Language.GraphQL.Execute.Transform as Transform -import qualified Language.GraphQL.Type as Type -import qualified Language.GraphQL.Type.In as In -import qualified Language.GraphQL.Type.Out as Out -import qualified Language.GraphQL.Type.Internal as Internal -import Prelude hiding (null) - -resolveFieldValue :: MonadCatch m - => Type.Value - -> Type.Subs - -> Type.Resolve m - -> Full.Location - -> CollectErrsT m Type.Value -resolveFieldValue result args resolver location' = - catch (lift $ runReaderT resolver context) handleFieldError - where - handleFieldError :: MonadCatch m - => ResolverException - -> CollectErrsT m Type.Value - handleFieldError e - = addError Type.Null - $ Error (Text.pack $ displayException e) [location'] [] - context = Type.Context - { Type.arguments = Type.Arguments args - , Type.values = result - } - -collectFields :: Monad m - => Out.ObjectType m - -> Seq (Transform.Selection m) - -> OrderedMap (NonEmpty (Transform.Field m)) -collectFields objectType = foldl forEach OrderedMap.empty - where - forEach groupedFields (Transform.SelectionField field) = - let responseKey = aliasOrName field - in OrderedMap.insert responseKey (field :| []) groupedFields - forEach groupedFields (Transform.SelectionFragment selectionFragment) - | Transform.Fragment fragmentType fragmentSelectionSet <- selectionFragment - , Internal.doesFragmentTypeApply fragmentType objectType = - let fragmentGroupedFieldSet = collectFields objectType fragmentSelectionSet - in groupedFields <> fragmentGroupedFieldSet - | otherwise = groupedFields - -aliasOrName :: forall m. Transform.Field m -> Full.Name -aliasOrName (Transform.Field alias name _ _ _) = fromMaybe name alias - -resolveAbstractType :: Monad m - => Internal.AbstractType m - -> Type.Subs - -> CollectErrsT m (Maybe (Out.ObjectType m)) -resolveAbstractType abstractType values' - | Just (Type.String typeName) <- HashMap.lookup "__typename" values' = do - types' <- gets types - case HashMap.lookup typeName types' of - Just (Internal.ObjectType objectType) -> - if Internal.instanceOf objectType abstractType - then pure $ Just objectType - else pure Nothing - _ -> pure Nothing - | otherwise = pure Nothing - -executeField :: (MonadCatch m, Serialize a) - => Out.Resolver m - -> Type.Value - -> NonEmpty (Transform.Field m) - -> CollectErrsT m a -executeField fieldResolver prev fields - | Out.ValueResolver fieldDefinition resolver <- fieldResolver = - executeField' fieldDefinition resolver - | Out.EventStreamResolver fieldDefinition resolver _ <- fieldResolver = - executeField' fieldDefinition resolver - where - executeField' fieldDefinition resolver = do - let Out.Field _ fieldType argumentDefinitions = fieldDefinition - let Transform.Field _ _ arguments' _ location' = NonEmpty.head fields - case coerceArgumentValues argumentDefinitions arguments' of - Left [] -> - let errorMessage = "Not all required arguments are specified." - in addError null $ Error errorMessage [location'] [] - Left errorLocations -> addError null - $ Error "Argument coercing failed." errorLocations [] - Right argumentValues -> do - answer <- resolveFieldValue prev argumentValues resolver location' - completeValue fieldType fields answer - -completeValue :: (MonadCatch m, Serialize a) - => Out.Type m - -> NonEmpty (Transform.Field m) - -> Type.Value - -> CollectErrsT m a -completeValue (Out.isNonNullType -> False) _ Type.Null = pure null -completeValue outputType@(Out.ListBaseType listType) fields (Type.List list) - = traverse (completeValue listType fields) list - >>= coerceResult outputType (firstFieldLocation fields) . List -completeValue outputType@(Out.ScalarBaseType _) fields (Type.Int int) = - coerceResult outputType (firstFieldLocation fields) $ Int int -completeValue outputType@(Out.ScalarBaseType _) fields (Type.Boolean boolean) = - coerceResult outputType (firstFieldLocation fields) $ Boolean boolean -completeValue outputType@(Out.ScalarBaseType _) fields (Type.Float float) = - coerceResult outputType (firstFieldLocation fields) $ Float float -completeValue outputType@(Out.ScalarBaseType _) fields (Type.String string) = - coerceResult outputType (firstFieldLocation fields) $ String string -completeValue outputType@(Out.EnumBaseType enumType) fields (Type.Enum enum) = - let Type.EnumType _ _ enumMembers = enumType - location = firstFieldLocation fields - in if HashMap.member enum enumMembers - then coerceResult outputType location $ Enum enum - else addError null $ Error "Enum value completion failed." [location] [] -completeValue (Out.ObjectBaseType objectType) fields result - = executeSelectionSet result objectType (firstFieldLocation fields) - $ mergeSelectionSets fields -completeValue (Out.InterfaceBaseType interfaceType) fields result - | Type.Object objectMap <- result = do - let abstractType = Internal.AbstractInterfaceType interfaceType - let location = firstFieldLocation fields - concreteType <- resolveAbstractType abstractType objectMap - case concreteType of - Just objectType -> executeSelectionSet result objectType location - $ mergeSelectionSets fields - Nothing -> addError null - $ Error "Interface value completion failed." [location] [] -completeValue (Out.UnionBaseType unionType) fields result - | Type.Object objectMap <- result = do - let abstractType = Internal.AbstractUnionType unionType - let location = firstFieldLocation fields - concreteType <- resolveAbstractType abstractType objectMap - case concreteType of - Just objectType -> executeSelectionSet result objectType - location $ mergeSelectionSets fields - Nothing -> addError null - $ Error "Union value completion failed." [location] [] -completeValue _ (Transform.Field _ _ _ _ location :| _) _ = - addError null $ Error "Value completion failed." [location] [] - -mergeSelectionSets :: MonadCatch m - => NonEmpty (Transform.Field m) - -> Seq (Transform.Selection m) -mergeSelectionSets = foldr forEach mempty - where - forEach (Transform.Field _ _ _ fieldSelectionSet _) selectionSet = - selectionSet <> fieldSelectionSet - -firstFieldLocation :: MonadCatch m => NonEmpty (Transform.Field m) -> Full.Location -firstFieldLocation (Transform.Field _ _ _ _ fieldLocation :| _) = fieldLocation - -coerceResult :: (MonadCatch m, Serialize a) - => Out.Type m - -> Full.Location - -> Output a - -> CollectErrsT m a -coerceResult outputType parentLocation result - | Just serialized <- serialize outputType result = pure serialized - | otherwise = addError null - $ Error "Result coercion failed." [parentLocation] [] - --- | Takes an 'Out.ObjectType' and a list of 'Transform.Selection's and applies --- each field to each 'Transform.Selection'. Resolves into a value containing --- the resolved 'Transform.Selection', or a null value and error information. -executeSelectionSet :: (MonadCatch m, Serialize a) - => Type.Value - -> Out.ObjectType m - -> Full.Location - -> Seq (Transform.Selection m) - -> CollectErrsT m a -executeSelectionSet result objectType@(Out.ObjectType _ _ _ resolvers) objectLocation selectionSet = do - let fields = collectFields objectType selectionSet - resolvedValues <- OrderedMap.traverseMaybe forEach fields - coerceResult (Out.NonNullObjectType objectType) objectLocation - $ Object resolvedValues - where - forEach fields@(field :| _) = - let Transform.Field _ name _ _ _ = field - in traverse (tryResolver fields) $ lookupResolver name - lookupResolver = flip HashMap.lookup resolvers - tryResolver fields resolver = - executeField resolver result fields >>= lift . pure - -coerceArgumentValues - :: HashMap Full.Name In.Argument - -> HashMap Full.Name (Full.Node Transform.Input) - -> Either [Full.Location] Type.Subs -coerceArgumentValues argumentDefinitions argumentNodes = - HashMap.foldrWithKey forEach (pure mempty) argumentDefinitions - where - forEach argumentName (In.Argument _ variableType defaultValue) = \case - Right resultMap - | Just matchedValues - <- matchFieldValues' argumentName variableType defaultValue $ Just resultMap - -> Right matchedValues - | otherwise -> Left $ generateError argumentName [] - Left errorLocations - | Just _ - <- matchFieldValues' argumentName variableType defaultValue $ pure mempty - -> Left errorLocations - | otherwise -> Left $ generateError argumentName errorLocations - generateError argumentName errorLocations = - case HashMap.lookup argumentName argumentNodes of - Just (Full.Node _ errorLocation) -> [errorLocation] - Nothing -> errorLocations - matchFieldValues' = matchFieldValues coerceArgumentValue (Full.node <$> argumentNodes) - coerceArgumentValue inputType (Transform.Int integer) = - coerceInputLiteral inputType (Type.Int integer) - coerceArgumentValue inputType (Transform.Boolean boolean) = - coerceInputLiteral inputType (Type.Boolean boolean) - coerceArgumentValue inputType (Transform.String string) = - coerceInputLiteral inputType (Type.String string) - coerceArgumentValue inputType (Transform.Float float) = - coerceInputLiteral inputType (Type.Float float) - coerceArgumentValue inputType (Transform.Enum enum) = - coerceInputLiteral inputType (Type.Enum enum) - coerceArgumentValue inputType Transform.Null - | In.isNonNullType inputType = Nothing - | otherwise = coerceInputLiteral inputType Type.Null - coerceArgumentValue (In.ListBaseType inputType) (Transform.List list) = - let coerceItem = coerceInputLiteral inputType - in Type.List <$> traverse coerceItem list - coerceArgumentValue (In.InputObjectBaseType inputType) (Transform.Object object) - | In.InputObjectType _ _ inputFields <- inputType = - let go = forEachField object - resultMap = HashMap.foldrWithKey go (pure mempty) inputFields - in Type.Object <$> resultMap - coerceArgumentValue _ (Transform.Variable variable) = pure variable - coerceArgumentValue _ _ = Nothing - forEachField object variableName (In.InputField _ variableType defaultValue) = - matchFieldValues coerceArgumentValue object variableName variableType defaultValue |
