morpheus-graphql-0.18.0: src/Data/Morpheus/Server/Deriving/Named/EncodeValue.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 TypeApplications #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE NoImplicitPrelude #-}
module Data.Morpheus.Server.Deriving.Named.EncodeValue
( EncodeFieldKind,
Encode,
getTypeName,
encodeResolverValue,
)
where
import Control.Monad.Except (MonadError (..))
import Data.Aeson (ToJSON (..))
import Data.Morpheus.App.Internal.Resolving
( LiftOperation,
NamedResolverRef (..),
NamedResolverResult (..),
ObjectTypeResolver (..),
Resolver,
ResolverValue (..),
getArguments,
liftResolverState,
mkList,
mkNull,
)
import Data.Morpheus.Kind
( CUSTOM,
DerivingKind,
SCALAR,
TYPE,
WRAPPER,
)
import Data.Morpheus.NamedResolvers
( NamedResolverT (..),
ResolveNamed (..),
)
import Data.Morpheus.Server.Deriving.Decode
( DecodeConstraint,
decodeArguments,
)
import Data.Morpheus.Server.Deriving.Encode
( ContextValue (..),
)
import Data.Morpheus.Server.Deriving.Utils
( ConsRep (..),
DataType (..),
FieldRep (..),
TypeConstraint (..),
TypeRep (..),
toFieldRes,
toValue,
)
import Data.Morpheus.Server.Types.GQLType
( GQLType (__type),
KIND,
TypeData (gqlTypeName),
)
import Data.Morpheus.Types.GQLScalar
( EncodeScalar (..),
)
import Data.Morpheus.Types.Internal.AST
( GQLError,
OUT,
TypeCategory (OUT),
TypeName,
internal,
replaceValue,
)
import qualified GHC.Exts as HM
import GHC.Generics
( Generic (..),
)
import Relude
encodeResolverValue :: (MonadError GQLError m, FieldConstraint m a) => a -> m (NamedResolverResult m)
encodeResolverValue = convertNamedNode . getFieldValues
type FieldConstraint m a =
( GQLType a,
Generic a,
TypeRep (Encode m) (m (ResolverValue m)) (Rep a)
)
class Encode (m :: * -> *) res where
encodeField :: res -> m (ResolverValue m)
instance (EncodeFieldKind (KIND a) m a) => Encode m a where
encodeField resolver = encodeFieldKind (ContextValue resolver :: ContextValue (KIND a) a)
class EncodeFieldKind (k :: DerivingKind) (m :: * -> *) (a :: *) where
encodeFieldKind :: ContextValue k a -> m (ResolverValue m)
instance (EncodeScalar a, Monad m) => EncodeFieldKind SCALAR m a where
encodeFieldKind = pure . ResScalar . encodeScalar . unContextValue
instance (FieldConstraint m a, MonadError GQLError m) => EncodeFieldKind TYPE m a where
encodeFieldKind (ContextValue _) = throwError (internal "types are resolved by Refs")
instance (GQLType a, Applicative m, EncodeFieldKind (KIND a) m a) => EncodeFieldKind WRAPPER m [a] where
encodeFieldKind = fmap ResList . traverse encodeField . unContextValue
instance (GQLType a, EncodeFieldKind (KIND a) m a, Applicative m) => EncodeFieldKind WRAPPER m (Maybe a) where
encodeFieldKind (ContextValue (Just x)) = encodeField x
encodeFieldKind (ContextValue Nothing) = pure mkNull
instance
( Monad m,
GQLType a,
EncodeFieldKind (KIND a) m a,
ToJSON (Dep a)
) =>
EncodeFieldKind CUSTOM m (NamedResolverT m a)
where
encodeFieldKind = encodeRef . unContextValue
where
name :: TypeName
name = getTypeName (Proxy @a)
encodeRef :: Monad m => NamedResolverT m a -> m (ResolverValue m)
encodeRef (Ref x) = pure $ ResRef (NamedResolverRef name . replaceValue . toJSON <$> x)
encodeRef (Value value) = value >>= encodeField
encodeRef (Refs refs) = mkList . map (ResRef . pure . NamedResolverRef name . replaceValue . toJSON) <$> refs
instance
( DecodeConstraint a,
Generic a,
Monad m,
Encode (Resolver o e m) b,
LiftOperation o
) =>
EncodeFieldKind CUSTOM (Resolver o e m) (a -> b)
where
encodeFieldKind (ContextValue f) =
getArguments
>>= liftResolverState . decodeArguments
>>= encodeField . f
getFieldValues :: FieldConstraint m a => a -> DataType (m (ResolverValue m))
getFieldValues =
toValue
( TypeConstraint (encodeField . runIdentity) ::
TypeConstraint (Encode m) (m (ResolverValue m)) Identity
)
(Proxy @OUT)
convertNamedNode ::
MonadError GQLError m =>
DataType (m (ResolverValue m)) ->
m (NamedResolverResult m)
convertNamedNode
DataType
{ tyIsUnion,
tyCons = ConsRep {consFields, consName}
}
| null consFields = pure $ NamedEnumResolver consName
| tyIsUnion = deriveUnion consFields
| otherwise =
pure $
NamedObjectResolver
ObjectTypeResolver
{ objectFields = HM.fromList (toFieldRes <$> 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!"
getTypeName :: GQLType a => f a -> TypeName
getTypeName proxy = gqlTypeName $ __type proxy OUT