{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}
module Data.Morpheus.Execution.Server.Encode
( EncodeCon
, GResolver(..)
, Encode(..)
, encodeQuery
, encodeSubscription
, encodeMutation
, ObjectResolvers(..)
) where
import Data.Map (Map)
import qualified Data.Map as M (toList)
import Data.Maybe (fromMaybe)
import Data.Proxy (Proxy (..))
import Data.Semigroup ((<>))
import Data.Set (Set)
import qualified Data.Set as S (toList)
import Data.Text (pack)
import GHC.Generics
import Data.Morpheus.Error.Internal (internalUnknownTypeMessage)
import Data.Morpheus.Execution.Server.Decode (DecodeObject, decodeArguments)
import Data.Morpheus.Execution.Server.Generics.EnumRep (EnumRep (..))
import Data.Morpheus.Kind (ENUM, GQL_KIND, OBJECT, ResContext (..), SCALAR,
UNION, VContext (..))
import Data.Morpheus.Types.Custom (MapKind, Pair (..), mapKindFromList)
import Data.Morpheus.Types.GQLScalar (GQLScalar (..))
import Data.Morpheus.Types.GQLType (GQLType (CUSTOM, KIND, __typeName))
import Data.Morpheus.Types.Internal.AST.Operation (Operation (..), ValidOperation)
import Data.Morpheus.Types.Internal.AST.Selection (Selection (..), SelectionRec (..), ValidSelection)
import Data.Morpheus.Types.Internal.Base (Key)
import Data.Morpheus.Types.Internal.Data (MUTATION, OperationType, QUERY, SUBSCRIPTION)
import Data.Morpheus.Types.Internal.Resolver (MapGraphQLT (..), PureOperation (..), Resolver (..),
Resolving (..), ResolvingStrategy (..), resolveObject,
withObject)
import Data.Morpheus.Types.Internal.Validation (Validation)
import Data.Morpheus.Types.Internal.Value (GQLValue (..), Value (..))
class Encode resolver o m e where
encode :: PureOperation o => resolver -> (Key, ValidSelection) -> ResolvingStrategy o m e Value
instance {-# OVERLAPPABLE #-} (EncodeKind (KIND a) a o m e , PureOperation o) => Encode a o m e where
encode resolver = encodeKind (VContext resolver :: VContext (KIND a) a)
instance (Monad m , Encode a o m e) => Encode (Maybe a) o m e where
encode = maybe (const $ pure gqlNull) encode
instance Encode (Pair k v) o m e => Encode (k, v) o m e where
encode (key, value) = encode (Pair key value)
instance Encode [a] o m e => Encode (Set a) o m e where
encode = encode . S.toList
instance (Eq k, Monad m, Encode (MapKind k v (Resolver o m e)) o m e) => Encode (Map k v) o m e where
encode value = encode ((mapKindFromList $ M.toList value) :: MapKind k v (Resolver o m e))
instance (Monad m, Encode a o m e) => Encode [a] o m e where
encode list query = gqlList <$> traverse (`encode` query) list
instance (DecodeObject a, Resolving fO m e ,Monad m,PureOperation fO, MapGraphQLT fO o, Encode b fO m e ) => Encode (a -> Resolver fO m e b) o m e where
encode resolver selection@(_, Selection { selectionArguments }) = mapGraphQLT $ resolving encode (getArgs args resolver) selection
where
args :: Validation a
args = decodeArguments selectionArguments
class EncodeKind (kind :: GQL_KIND) a o m e where
encodeKind :: PureOperation o => VContext kind a -> (Key, ValidSelection) -> ResolvingStrategy o m e Value
instance (GQLScalar a, Monad m) => EncodeKind SCALAR a o m e where
encodeKind = pure . pure . gqlScalar . serialize . unVContext
instance (Generic a, EnumRep (Rep a), Monad m) => EncodeKind ENUM a o m e where
encodeKind = pure . pure . gqlString . encodeRep . from . unVContext
instance (Monad m, EncodeCon o m e a, Monad m, GResolver OBJECT (Rep a) o m e) => EncodeKind OBJECT a o m e where
encodeKind (VContext value) = withObject encodeK
where
encodeK selection = resolveObject selection (__typenameResolver : objectResolvers (Proxy :: Proxy (CUSTOM a)) value)
__typenameResolver = ("__typename", const $ pure $ gqlString $ __typeName (Proxy @a))
instance (Monad m, GQL_RES a, GResolver UNION (Rep a) o m e) => EncodeKind UNION a o m e where
encodeKind (VContext value) (key, sel@Selection {selectionRec = UnionSelection selections}) =
resolver (key, sel {selectionRec = SelectionSet lookupSelection})
where
lookupSelection = fromMaybe [] $ lookup typeName selections
(typeName, resolver) = unionResolver value
encodeKind _ _ = Fail $ internalUnknownTypeMessage "union Resolver only should recieve UnionSelection"
type GQL_RES a = (Generic a, GQLType a)
type EncodeOperator o m e a = a -> ValidOperation -> ResolvingStrategy o m e Value
type EncodeCon o m e a = (GQL_RES a, ObjectResolvers (CUSTOM a) a o m e)
type FieldRes o m e = (Key, (Key, ValidSelection) -> ResolvingStrategy o m e Value)
type family GRes (kind :: GQL_KIND) value :: *
type instance GRes OBJECT v = [(Key, (Key, ValidSelection) -> v)]
type instance GRes UNION v = (Key, (Key, ValidSelection) -> v)
class ObjectResolvers (custom :: Bool) a (o :: OperationType) (m :: * -> *) e where
objectResolvers :: PureOperation o => Proxy custom -> a -> [(Key, (Key, ValidSelection) -> ResolvingStrategy o m e Value)]
instance (Generic a, GResolver OBJECT (Rep a) o m e ) => ObjectResolvers 'False a o m e where
objectResolvers _ = getResolvers (ResContext :: ResContext OBJECT o m e value) . from
unionResolver :: (Generic a, PureOperation o, GResolver UNION (Rep a) o m e) => a -> (Key, (Key, ValidSelection) -> ResolvingStrategy o m e Value)
unionResolver = getResolvers (ResContext :: ResContext UNION o m e value) . from
class GResolver (kind :: GQL_KIND) f o m e where
getResolvers :: PureOperation o => ResContext kind o m e value -> f a -> GRes kind (ResolvingStrategy o m e Value)
instance GResolver kind f o m e => GResolver kind (M1 D c f) o m e where
getResolvers context (M1 src) = getResolvers context src
instance GResolver kind f o m e => GResolver kind (M1 C c f) o m e where
getResolvers context (M1 src) = getResolvers context src
instance GResolver OBJECT U1 o m e where
getResolvers _ _ = []
instance (Selector s, GQLType a, Encode a o m e) => GResolver OBJECT (M1 S s (K1 s2 a)) o m e where
getResolvers _ m@(M1 (K1 src)) = [(pack (selName m), encode src)]
instance (GResolver OBJECT f o m e, GResolver OBJECT g o m e) => GResolver OBJECT (f :*: g) o m e where
getResolvers context (a :*: b) = getResolvers context a ++ getResolvers context b
instance (Selector s, GQLType a, Encode a o m e ) => GResolver UNION (M1 S s (K1 s2 a)) o m e where
getResolvers _ (M1 (K1 src)) = (__typeName (Proxy @a), encode src)
instance (GResolver UNION a o m e, GResolver UNION b o m e) => GResolver UNION (a :+: b) o m e where
getResolvers context (L1 x) = getResolvers context x
getResolvers context (R1 x) = getResolvers context x
encodeQuery ::
forall m event query (schema :: (* -> *) -> *). (Monad m, EncodeCon QUERY m event (schema (Resolver QUERY m event)), EncodeCon QUERY m event query, Resolving QUERY m event)
=> schema (Resolver QUERY m event)
-> EncodeOperator QUERY m event query
encodeQuery schema = encodeOperationWith (objectResolvers (Proxy :: Proxy (CUSTOM (schema (Resolver QUERY m event)))) schema)
encodeMutation ::
forall m event mut. (Monad m, EncodeCon MUTATION m event mut, Resolving MUTATION m event)
=> EncodeOperator MUTATION m event mut
encodeMutation = encodeOperationWith []
encodeSubscription ::
forall m event mut. (Monad m, EncodeCon SUBSCRIPTION m event mut, Resolving SUBSCRIPTION m event)
=> EncodeOperator SUBSCRIPTION m event mut
encodeSubscription = encodeOperationWith []
encodeOperationWith ::
forall o m e a . (Monad m, EncodeCon o m e a, Resolving o m e, PureOperation o)
=> [FieldRes o m e]
-> EncodeOperator o m e a
encodeOperationWith externalRes rootResolver Operation {operationSelection} = resolveObject operationSelection resolvers
where
resolvers = externalRes <> objectResolvers (Proxy :: Proxy (CUSTOM a)) rootResolver