{-# 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 )
deriveGQLType :: GQLTypeD -> Q [Dec]
deriveGQLType GQLTypeD { typeD = TypeD { tName, tMeta }, typeKindD } =
pure <$> instanceD (cxt constrains) iHead (functions <> typeFamilies)
where
functions = map
instanceProxyFunD
[('__typeName, [|toHSTypename 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 = [deriveKIND, deriveCUSTOM]
| otherwise = [deriveKIND]
where
deriveCUSTOM = deriveInstance ''CUSTOM ''TRUE
deriveKIND = deriveInstance ''KIND (kindName typeKindD)
deriveInstance :: Name -> Name -> Q Dec
deriveInstance insName tyName = do
typeN <- headSig
pure $ typeInstanceDec insName typeN (ConT tyName)
kindName :: DataTypeKind -> Name
kindName KindObject {} = ''OUTPUT
kindName KindScalar = ''SCALAR
kindName KindEnum = ''ENUM
kindName KindUnion = ''OUTPUT
kindName KindInputObject = ''INPUT
kindName KindList = ''WRAPPER
kindName KindNonNull = ''WRAPPER
kindName KindInputUnion = ''INPUT
toHSTypename :: Key -> Key
toHSTypename = pack . hsTypename . unpack
where
hsTypename ('S' : name) | isSchemaTypeName (pack name) = name
hsTypename name = name