{-# LANGUAGE DataKinds #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE TemplateHaskell #-}
module Data.Morpheus.Execution.Document.GQLType
( deriveGQLType
)
where
import Data.Text ( pack
, unpack
)
import Language.Haskell.TH
import Data.Semigroup ( (<>) )
import Data.Morpheus.Execution.Internal.Declare
( tyConArgs )
import Data.Morpheus.Kind ( ENUM
, SCALAR
, WRAPPER
, INPUT
, OUTPUT
)
import Data.Morpheus.Types.GQLType ( GQLType(..)
, TRUE
)
import Data.Morpheus.Types.Internal.AST
( DataTypeKind(..)
, Meta(..)
, isObject
, isSchemaTypeName
, GQLTypeD(..)
, TypeD(..)
, Key
)
import Data.Morpheus.Types.Internal.TH
( instanceHeadT
, typeT
, typeInstanceDec
, instanceProxyFunD
)
import Data.Typeable ( Typeable )
genTypeName :: Key -> Key
genTypeName = pack . __genTypeName . unpack
where
__genTypeName ('S' : name) | isSchemaTypeName (pack name) = name
__genTypeName name = name
deriveGQLType :: GQLTypeD -> Q [Dec]
deriveGQLType GQLTypeD { typeD = TypeD { tName, tMeta }, typeKindD } =
pure <$> instanceD (cxt constrains) iHead (functions <> typeFamilies)
where
functions = map
instanceProxyFunD
[('__typeName, [|genTypeName tName|]), ('description, descriptionValue)]
where
descriptionValue = case tMeta >>= metaDescription of
Nothing -> [| Nothing |]
Just desc -> [| Just desc |]
typeArgs = tyConArgs typeKindD
iHead = instanceHeadT ''GQLType tName typeArgs
headSig = typeT (mkName $ unpack tName) typeArgs
constrains = map conTypeable typeArgs
where conTypeable name = typeT ''Typeable [name]
typeFamilies | isObject typeKindD = [deriveCUSTOM, deriveKind]
| otherwise = [deriveKind]
where
deriveCUSTOM = do
typeN <- headSig
pure $ typeInstanceDec ''CUSTOM typeN (ConT ''TRUE)
deriveKind = do
typeN <- headSig
pure $ typeInstanceDec ''KIND typeN (ConT $ toKIND typeKindD)
toKIND KindScalar = ''SCALAR
toKIND KindEnum = ''ENUM
toKIND (KindObject _) = ''OUTPUT
toKIND KindUnion = ''OUTPUT
toKIND KindInputObject = ''INPUT
toKIND KindList = ''WRAPPER
toKIND KindNonNull = ''WRAPPER
toKIND KindInputUnion = ''INPUT