morpheus-graphql-app-0.28.2: src/Data/Morpheus/App/Internal/Resolving/Resolver.hs
{-# LANGUAGE CPP #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE NoImplicitPrelude #-}
module Data.Morpheus.App.Internal.Resolving.Resolver
( Resolver,
LiftOperation,
ResponseEvent (..),
ResponseStream,
WithOperation,
SubscriptionField (..),
)
where
import Control.Monad.Except (MonadError (..))
import Control.Monad.Trans.Reader (mapReaderT)
import Data.Morpheus.App.Internal.Resolving.Event
( EventHandler (..),
ResponseEvent (..),
)
import Data.Morpheus.App.Internal.Resolving.MonadResolver
( MonadIOResolver,
MonadResolver (..),
SubscriptionField (..),
)
import Data.Morpheus.App.Internal.Resolving.ResolverState
( ResolverContext (..),
ResolverState,
ResolverStateT (..),
clearStateResolverEvents,
resolverFailureMessage,
runResolverState,
runResolverStateT,
runResolverStateValueM,
toResolverStateT,
)
import Data.Morpheus.Internal.Ext
( GQLResult,
PushEvents (..),
Result (..),
ResultT (..),
cleanEvents,
mapEvent,
)
import Data.Morpheus.Types.IO
( GQLResponse,
renderResponse,
)
import Data.Morpheus.Types.Internal.AST
( GQLError,
MUTATION,
OperationType (..),
QUERY,
SUBSCRIPTION,
Selection (..),
VALID,
ValidValue,
Value (..),
msg,
)
import Relude hiding
( Show,
empty,
show,
)
import Prelude (Show (..))
type WithOperation (o :: OperationType) = LiftOperation o
type ResponseStream event (m :: Type -> Type) = ResultT (ResponseEvent event m) m
-- GraphQL resolver
---------------------------------------------------------------
data Resolver (o :: OperationType) event (m :: Type -> Type) value where
ResolverQ :: {runResolverQ :: ResolverStateT () m value} -> Resolver QUERY event m value
ResolverM :: {runResolverM :: ResolverStateT event m value} -> Resolver MUTATION event m value
ResolverS :: {runResolverS :: ResolverStateT () m (SubEventRes event m value)} -> Resolver SUBSCRIPTION event m value
instance (LiftOperation o, Monad m, MonadIO m) => MonadIOResolver (Resolver o e m)
instance (LiftOperation o, Monad m) => MonadResolver (Resolver o e m) where
type MonadOperation (Resolver o e m) = o
type MonadEvent (Resolver o e m) = e
type MonadQuery (Resolver o e m) = (Resolver QUERY e m)
type MonadMutation (Resolver o e m) = (Resolver MUTATION e m)
type MonadSubscription (Resolver o e m) = (Resolver SUBSCRIPTION e m)
type MonadParam (Resolver o e m) = m
getArguments = asks (selectionArguments . currentSelection)
liftState = packResolver . toResolverStateT
subscribe ch res = SubscriptionField ch (ResolverS (runSubscription <$> runResolverQ res))
where
runSubscription f = join (ReaderT (runResolverS . f))
publish = pushEvents
runResolver _ (ResolverQ resT) sel = cleanEvents $ runResolverStateT resT sel
runResolver _ (ResolverM resT) sel = mapEvent Publish $ runResolverStateT resT sel
runResolver toChannel (ResolverS resT) ctx = ResultT $ do
readResValue <- runResolverStateValueM resT ctx
pure $ case readResValue >>= subscriptionEvents ctx toChannel . toEventResolver ctx of
Failure x -> Failure x
Success {warnings, result} -> Success {warnings, result = ([result], Null)}
type SubEventRes event m value = ReaderT event (ResolverStateT () m) value
instance Show (Resolver o e m value) where
show ResolverQ {} = "Resolver QUERY e m a"
show ResolverM {} = "Resolver MUTATION e m a"
show ResolverS {} = "Resolver SUBSCRIPTION e m a"
deriving instance (Functor m) => Functor (Resolver o e m)
-- Applicative
instance (LiftOperation o, Monad m) => Applicative (Resolver o e m) where
pure = packResolver . pure
ResolverQ r1 <*> ResolverQ r2 = ResolverQ $ r1 <*> r2
ResolverM r1 <*> ResolverM r2 = ResolverM $ r1 <*> r2
ResolverS r1 <*> ResolverS r2 = ResolverS $ (<*>) <$> r1 <*> r2
-- Monad
instance (Monad m, LiftOperation o) => Monad (Resolver o e m) where
return = pure
(ResolverQ x) >>= m2 = ResolverQ (x >>= runResolverQ . m2)
(ResolverM x) >>= m2 = ResolverM (x >>= runResolverM . m2)
(ResolverS res) >>= m2 = ResolverS (liftSubResolver m2 <$> res)
liftSubResolver ::
(Monad m) =>
(t -> Resolver SUBSCRIPTION r m a) ->
ReaderT r (ResolverStateT () m) t ->
ReaderT r (ResolverStateT () m) a
liftSubResolver m2 readResA = ReaderT $ \e -> do
a <- runReaderT readResA e
readResB <- runResolverS (m2 a)
runReaderT readResB e
-- MonadIO
instance (MonadIO m, LiftOperation o) => MonadIO (Resolver o e m) where
liftIO = lift . liftIO
-- Monad Transformers
instance (LiftOperation o) => MonadTrans (Resolver o e) where
lift = packResolver . lift
-- Failure
instance (LiftOperation o, Monad m) => MonadError GQLError (Resolver o e m) where
throwError = packResolver . throwError
catchError (ResolverQ r) f = ResolverQ $ catchError r (runResolverQ . f)
catchError (ResolverM r) f = ResolverM $ catchError r (runResolverM . f)
catchError (ResolverS r) f = ResolverS $ catchError r (runResolverS . f)
instance (Monad m, LiftOperation o) => MonadFail (Resolver o e m) where
fail = throwError . msg
-- PushEvents
instance (Monad m) => PushEvents e (Resolver MUTATION e m) where
pushEvents = packResolver . pushEvents
instance (Monad m, Semigroup a, LiftOperation o) => Semigroup (Resolver o e m a) where
x <> y = fmap (<>) x <*> y
instance (LiftOperation o, Monad m) => MonadReader ResolverContext (Resolver o e m) where
ask = packResolver ask
local f (ResolverQ res) = ResolverQ (local f res)
local f (ResolverM res) = ResolverM (local f res)
local f (ResolverS resM) = ResolverS $ mapReaderT (local f) <$> resM
class LiftOperation (o :: OperationType) where
packResolver :: (Monad m) => ResolverStateT e m a -> Resolver o e m a
instance LiftOperation QUERY where
packResolver = ResolverQ . clearStateResolverEvents
instance LiftOperation MUTATION where
packResolver = ResolverM
instance LiftOperation SUBSCRIPTION where
packResolver = ResolverS . pure . lift . clearStateResolverEvents
toEventResolver :: (Monad m) => ResolverContext -> SubEventRes event m ValidValue -> (event -> m GQLResponse)
toEventResolver sel (ReaderT subRes) event = renderResponse <$> runResolverStateValueM (subRes event) sel
subscriptionEvents ::
ResolverContext ->
Maybe (Selection VALID -> ResolverState (Channel e)) ->
(e -> m GQLResponse) ->
GQLResult (ResponseEvent e m)
subscriptionEvents ctx@ResolverContext {currentSelection} (Just channelGenerator) res =
runResolverState handle ctx
where
handle = do
channel <- channelGenerator currentSelection
pure $ Subscribe channel res
subscriptionEvents ctx Nothing _ = throwError $ resolverFailureMessage ctx "channel Resolver is not defined"