morpheus-graphql-0.6.0: src/Data/Morpheus/Execution/Document/Convert.hs
{-# 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)
--
-- MORPHEUS
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 :: Text -> Text
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