{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE NoImplicitPrelude #-} module Execution ( runExecutionTest, ) where import Control.Monad.Except (MonadError (throwError)) import Data.ByteString.Lazy.Char8 (readFile) import Data.Morpheus.App (mkApp, runApp) import Data.Morpheus.App.Internal.Resolving ( ObjectTypeResolver (..), Resolver, ResolverValue, RootResolverValue (..), mkObject, resultOr, ) import Data.Morpheus.App.NamedResolvers ( getArgument, list, ) import Data.Morpheus.Core ( parseSchema, ) import Data.Morpheus.Types.IO ( GQLRequest (..), GQLResponse, ) import Data.Morpheus.Types.Internal.AST ( Msg (..), QUERY, Schema, VALID, ValidValue, ) import Relude hiding (ByteString, readFile) import Test.Morpheus ( FileUrl, file, testApi, ) import Test.Tasty ( TestTree, ) type ExecState m = (StateT Int m) type ResQ m = Resolver QUERY () (ExecState m) getName :: ValidValue -> ResolverValue m getName "zeus" = "Zeus" getName "morpheus" = "Morpheus" getName "poseidon" = "Zeus" getName "cronos" = "Cronos" getName _ = "" restrictExecutions :: Monad m => Int -> ResQ m () restrictExecutions expected = do count <- lift get if expected == count then pure () else throwError ("unexpected execution count. expected " <> msg expected <> " but got " <> msg count <> ".") deityResolver :: Monad m => ValidValue -> ResQ m (ResolverValue (ResQ m)) deityResolver name = do lift (modify (+ 1)) pure $ mkObject "Deity" [("name", pure $ getName name)] resolvers :: Monad m => RootResolverValue () (ExecState m) resolvers = RootResolverValue { queryResolver = pure ( ObjectTypeResolver $ fromList [ ("deity", (getArgument "id" >>= deityResolver) <* restrictExecutions 1), ("deities", (list <$> traverse deityResolver ["zeus", "morpheus"]) <* restrictExecutions 2) ] ), mutationResolver = pure (ObjectTypeResolver mempty), subscriptionResolver = pure (ObjectTypeResolver mempty), channelMap = Nothing } getSchema :: FileUrl -> IO (Schema VALID) getSchema url = readFile (toString url) >>= resultOr (fail . show) pure . parseSchema runExecutionTest :: FileUrl -> FileUrl -> TestTree runExecutionTest url = testApi api where api :: GQLRequest -> IO GQLResponse api req = do schemaDeities <- getSchema (file url "schema.gql") (response, _) <- runStateT (runApp (mkApp schemaDeities resolvers) req) 0 pure response