{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeOperators #-}
module Data.Morpheus.Execution.Document.Convert
( renderTHTypes
) where
import Data.Semigroup ((<>))
import Data.Text (Text, pack, unpack)
import Data.Morpheus.Error.Internal (internalError)
import Data.Morpheus.Execution.Internal.Utils (capital)
import Data.Morpheus.Types.Internal.Data (ArgsType (..), DataField (..), DataType (..),
DataTyCon (..), DataTypeKind (..), OperationType (..),
ResolverKind (..), TypeAlias (..), sysTypes)
import Data.Morpheus.Types.Internal.DataD (ConsD (..), GQLTypeD (..), TypeD (..))
import Data.Morpheus.Types.Internal.Validation (Validation)
renderTHTypes :: Bool -> [(Text, DataType)] -> Validation [GQLTypeD]
renderTHTypes namespace lib = traverse renderTHType lib
where
renderTHType :: (Text, DataType) -> Validation GQLTypeD
renderTHType (tyConName, x) = genType x
where
genArgsTypeName fieldName
| namespace = sysName tyConName <> argTName
| otherwise = argTName
where
argTName = capital fieldName <> "Args"
genArgumentType :: (Text, DataField) -> Validation [TypeD]
genArgumentType (_, DataField {fieldArgs = []}) = pure []
genArgumentType (fieldName, DataField {fieldArgs}) =
pure
[ TypeD
{ tName
, tNamespace = []
, tCons = [ConsD {cName = sysName $ pack tName, cFields = map genField fieldArgs}]
}
]
where
tName = genArgsTypeName $ sysName fieldName
genFieldTypeName = genTypeName
genTypeName "String" = "Text"
genTypeName "Boolean" = "Bool"
genTypeName name
| name `elem` sysTypes = "S" <> name
genTypeName name = name
sysName = unpack . genTypeName
genField :: (Text, DataField) -> DataField
genField (_, field@DataField {fieldType = alias@TypeAlias {aliasTyCon}}) =
field {fieldType = alias {aliasTyCon = genFieldTypeName aliasTyCon}}
genResField :: (Text, DataField) -> DataField
genResField (_, field@DataField {fieldName, fieldArgs, fieldType = alias@TypeAlias {aliasTyCon}}) =
field {fieldType = alias {aliasTyCon = ftName, aliasArgs}, fieldArgsType}
where
ftName = genFieldTypeName aliasTyCon
aliasArgs =
case lookup aliasTyCon lib of
Just DataObject {} -> Just "m"
Just DataUnion {} -> Just "m"
_ -> Nothing
fieldArgsType = Just $ ArgsType {argsTypeName, resKind = getFieldType ftName}
where
argsTypeName
| null fieldArgs = "()"
| otherwise = pack $ genArgsTypeName $ unpack fieldName
getFieldType key =
case lookup key lib of
Nothing -> ExternalResolver
Just DataObject {} -> TypeVarResolver
Just DataUnion {} -> TypeVarResolver
Just _ -> PlainResolver
genType (DataEnum DataTyCon {typeName, typeData}) =
pure
GQLTypeD
{ typeD = TypeD {tName = sysName typeName, tNamespace = [], tCons = map enumOption typeData}
, typeKindD = KindEnum
, typeArgD = []
}
where
enumOption name = ConsD {cName = sysName name, cFields = []}
genType (DataScalar _) = internalError "Scalar Types should defined By Native Haskell Types"
genType (DataInputUnion _) = internalError "Input Unions not Supported"
genType (DataInputObject DataTyCon {typeName, typeData}) =
pure
GQLTypeD
{ typeD =
TypeD
{ tName = sysName typeName
, tNamespace = []
, tCons = [ConsD {cName = sysName typeName, cFields = map genField typeData}]
}
, typeKindD = KindInputObject
, typeArgD = []
}
genType (DataObject DataTyCon {typeName, typeData}) = do
typeArgD <- concat <$> traverse genArgumentType typeData
pure
GQLTypeD
{ typeD =
TypeD
{ tName = sysName typeName
, tNamespace = []
, tCons = [ConsD {cName = sysName typeName, cFields = map genResField typeData}]
}
, typeKindD =
if typeName == "Subscription"
then KindObject (Just Subscription)
else KindObject Nothing
, typeArgD
}
genType (DataUnion DataTyCon {typeName, typeData}) = do
let tCons = map unionCon typeData
pure
GQLTypeD
{typeD = TypeD {tName = unpack typeName, tNamespace = [], tCons}, typeKindD = KindUnion, typeArgD = []}
where
unionCon field@DataField {fieldType} =
ConsD
{ cName
, cFields =
[ field
{ fieldName = pack $ "un" <> cName
, fieldType = TypeAlias {aliasTyCon = pack utName, aliasArgs = Just "m", aliasWrappers = []}
}
]
}
where
cName = sysName typeName <> utName
utName = sysName $ aliasTyCon fieldType