{-# LANGUAGE DataKinds #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TemplateHaskellQuotes #-}
{-# LANGUAGE TypeApplications #-}
module Data.Morpheus.Execution.Internal.Declare
( declareType
, tyConArgs
) where
import Data.Maybe (maybe)
import Data.Text (pack, unpack)
import GHC.Generics (Generic)
import Language.Haskell.TH
import Data.Morpheus.Execution.Internal.Utils (nameSpaceType, nameSpaceWith)
import Data.Morpheus.Types.Internal.Data (ArgsType (..), DataField (..), DataTypeKind (..),
DataTypeKind (..), TypeAlias (..), WrapperD (..),
isOutputObject, isSubscription)
import Data.Morpheus.Types.Internal.DataD (ConsD (..), TypeD (..))
import Data.Morpheus.Types.Resolver (UnSubResolver)
type FUNC = (->)
declareTypeAlias :: Bool -> TypeAlias -> Type
declareTypeAlias isSub TypeAlias {aliasTyCon, aliasWrappers, aliasArgs} = wrappedT aliasWrappers
where
wrappedT :: [WrapperD] -> Type
wrappedT (ListD:xs) = AppT (ConT ''[]) $ wrappedT xs
wrappedT (MaybeD:xs) = AppT (ConT ''Maybe) $ wrappedT xs
wrappedT [] = decType aliasArgs
typeName = ConT (mkName $ unpack aliasTyCon)
decType _
| isSub = AppT typeName (AppT (ConT ''UnSubResolver) (VarT $ mkName "m"))
decType (Just par) = AppT typeName (VarT $ mkName $ unpack par)
decType _ = typeName
tyConArgs :: DataTypeKind -> [String]
tyConArgs kindD
| isOutputObject kindD || kindD == KindUnion = ["m"]
| otherwise = []
declareType :: Bool -> Maybe DataTypeKind -> [Name] -> TypeD -> Dec
declareType namespace kindD derivingList TypeD {tName, tCons, tNamespace} =
DataD [] (genName tName) tVars Nothing (map cons tCons) $ map derive (''Generic : derivingList)
where
genName = mkName . nameSpaceType (map pack tNamespace) . pack
tVars = maybe [] (declareTyVar . tyConArgs) kindD
where
declareTyVar = map (PlainTV . mkName)
defBang = Bang NoSourceUnpackedness NoSourceStrictness
derive className = DerivClause Nothing [ConT className]
cons ConsD {cName, cFields} = RecC (genName cName) (map declareField cFields)
where
declareField DataField {fieldName, fieldArgsType, fieldType} = (fName, defBang, fiType)
where
fName
| namespace = mkName (nameSpaceWith tName (unpack fieldName))
| otherwise = mkName (unpack fieldName)
fiType = genFieldT fieldArgsType
where
monadVar = VarT $ mkName "m"
genFieldT Nothing = fType False
genFieldT (Just ArgsType {argsTypeName}) = AppT (AppT arrowType argType) (fType True)
where
argType = ConT $ mkName (unpack argsTypeName)
arrowType = ConT ''FUNC
fType isResolver
| maybe False isSubscription kindD = AppT monadVar result
| isResolver = AppT monadVar result
| otherwise = result
result = declareTypeAlias (maybe False isSubscription kindD) fieldType