morpheus-graphql-server-0.27.1: src/Data/Morpheus/Server/Deriving/Kinded/NamedResolverFun.hs
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE NoImplicitPrelude #-}
module Data.Morpheus.Server.Deriving.Kinded.NamedResolverFun
( deriveNamedResolverFun,
KindedNamedFunValue (..),
)
where
import Control.Monad.Except (MonadError (..))
import Data.Aeson (ToJSON (..))
import Data.Morpheus.App.Internal.Resolving
( MonadResolver (..),
NamedResolverRef (..),
NamedResolverResult (..),
ObjectTypeResolver (..),
ResolverValue (..),
getArguments,
mkList,
mkNull,
)
import Data.Morpheus.Server.Deriving.Internal.Decode.Utils (useDecodeArguments)
import Data.Morpheus.Server.Deriving.Internal.Schema.Directive (UseDeriving, toFieldRes)
import Data.Morpheus.Server.Deriving.Utils.GRep
( ConsRep (..),
FieldRep (..),
GRep,
RepContext (..),
TypeRep (..),
deriveValue,
)
import Data.Morpheus.Server.Deriving.Utils.Kinded
( CatType (..),
outputType,
)
import Data.Morpheus.Server.Deriving.Utils.Proxy
( ContextValue (..),
)
import Data.Morpheus.Server.Deriving.Utils.Use
( UseDeriving (..),
UseGQLType (..),
UseNamedResolver (..),
)
import Data.Morpheus.Server.Types.Kind
( CUSTOM,
DerivingKind,
SCALAR,
TYPE,
WRAPPER,
)
import Data.Morpheus.Server.Types.NamedResolvers
( NamedRef,
NamedResolverT (..),
)
import Data.Morpheus.Types.GQLScalar
( EncodeScalar (..),
)
import Data.Morpheus.Types.Internal.AST
( GQLError,
OUT,
TypeName,
ValidValue,
Value (List),
internal,
replaceValue,
)
import qualified GHC.Exts as HM
import GHC.Generics
( Generic (..),
)
import Relude hiding (empty)
deriveNamedResolverFun ::
( Generic a,
gql [Maybe a],
gql a,
MonadError GQLError m,
GRep gql (res m) (m (ResolverValue m)) (Rep a)
) =>
UseNamedResolver namedRes res gql val ->
[Maybe a] ->
m [NamedResolverResult m]
deriveNamedResolverFun ctx x = traverse encodeNode x
where
encodeNode (Just v) = convertNamedNode (namedDrv ctx) (Identity x) (deriveValue (getOptions ctx) v)
encodeNode Nothing = pure NamedNullResolver
class KindedNamedFunValue res gql val (k :: DerivingKind) (m :: Type -> Type) (a :: Type) where
kindedNamedFunValue :: UseNamedResolver namedRes res gql val -> ContextValue k a -> m (ResolverValue m)
instance (EncodeScalar a, Monad m) => KindedNamedFunValue res gql val SCALAR m a where
kindedNamedFunValue _ = pure . ResScalar . encodeScalar . unContextValue
instance (MonadError GQLError m) => KindedNamedFunValue res gql val TYPE m a where
kindedNamedFunValue _ (ContextValue _) = throwError (internal "types are resolved by Refs")
instance (Applicative m, res m a) => KindedNamedFunValue res gql val WRAPPER m [a] where
kindedNamedFunValue ctx = fmap ResList . traverse (useNamedFieldResolver ctx) . unContextValue
instance (gql a, res m a, Applicative m) => KindedNamedFunValue res gql val WRAPPER m (Maybe a) where
kindedNamedFunValue ctx (ContextValue (Just x)) = useNamedFieldResolver ctx x
kindedNamedFunValue _ (ContextValue Nothing) = pure mkNull
instance (Monad m, gql a, ToJSON (NamedRef a)) => KindedNamedFunValue res gql val CUSTOM m (NamedResolverT m a) where
kindedNamedFunValue ctx = encodeRef . unContextValue
where
name :: TypeName
name = useTypename (dirGQL (namedDrv ctx)) (OutputType :: CatType OUT a)
encodeRef :: Monad m => NamedResolverT m a -> m (ResolverValue m)
encodeRef (NamedResolverT ref) = do
value <- replaceValue . toJSON <$> ref
case value of
(List ls) -> pure $ mkList $ map (packRef name) ls
_ -> pure $ packRef name value
packRef :: Applicative m => TypeName -> ValidValue -> ResolverValue m
packRef name v = ResRef $ pure $ NamedResolverRef name [v]
instance (Monad m, val a, MonadResolver m, res m b) => KindedNamedFunValue res gql val CUSTOM m (a -> b) where
kindedNamedFunValue ctx (ContextValue f) =
getArguments
>>= liftState . useDecodeArguments (namedDrv ctx)
>>= useNamedFieldResolver ctx . f
getOptions :: UseNamedResolver namedRes res gql val -> RepContext gql (res m) Identity (m (ResolverValue m))
getOptions UseNamedResolver {..} =
RepContext
{ optApply = useNamedFieldResolver . runIdentity,
optTypeData = useTypeData (dirGQL namedDrv) . outputType
}
convertNamedNode ::
(gql a, MonadError GQLError m) =>
UseDeriving gql val ->
f a ->
TypeRep (m (ResolverValue m)) ->
m (NamedResolverResult m)
convertNamedNode
drv
proxy
TypeRep
{ tyIsUnion,
tyCons = ConsRep {consFields, consName}
}
| null consFields = pure $ NamedEnumResolver consName
| tyIsUnion = deriveUnion consFields
| otherwise =
pure $
NamedObjectResolver
ObjectTypeResolver
{ objectFields = HM.fromList (toFieldRes drv proxy <$> consFields)
}
deriveUnion :: (MonadError GQLError m) => [FieldRep (m (ResolverValue m))] -> m (NamedResolverResult m)
deriveUnion [FieldRep {..}] = NamedUnionResolver <$> (fieldValue >>= getRef)
deriveUnion _ = throwError "only union references are supported!"
getRef :: MonadError GQLError m => ResolverValue m -> m NamedResolverRef
getRef (ResRef x) = x
getRef _ = throwError "only resolver references are supported!"