{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE OverloadedStrings #-}
module Data.Morpheus.Parsing.Document.TypeSystem
( parseDataType
) where
import Data.Text (Text)
import Text.Megaparsec (label, sepBy1, (<|>))
import Data.Morpheus.Parsing.Internal.Create (createField)
import Data.Morpheus.Parsing.Internal.Internal (Parser)
import Data.Morpheus.Parsing.Internal.Pattern (fieldsDefinition, inputValueDefinition, optionalDirectives,
typDeclaration)
import Data.Morpheus.Parsing.Internal.Terms (keyword, operator, optDescription, parseName, pipeLiteral,
sepByAnd, setOf)
import Data.Morpheus.Types.Internal.Data (DataField, DataFingerprint (..), DataFullType (..),
DataLeaf (..), DataTyCon (..), DataValidator (..), Key,
RawDataType (..))
scalarTypeDefinition :: Maybe Text -> Parser (Text, DataFullType)
scalarTypeDefinition typeDescription =
label "ScalarTypeDefinition" $ do
typeName <- typDeclaration "scalar"
_ <- optionalDirectives
pure (
typeName,
Leaf $ CustomScalar DataTyCon {
typeName,
typeDescription,
typeFingerprint = SystemFingerprint typeName,
typeData = DataValidator pure
}
)
objectTypeDefinition :: Maybe Text -> Parser (Text, RawDataType)
objectTypeDefinition typeDescription =
label "ObjectTypeDefinition" $ do
name <- typDeclaration "type"
interfaces <- optionalImplementsInterfaces
_directives <- optionalDirectives
fields <- fieldsDefinition
pure (name,
Implements interfaces $ DataTyCon {
typeName = name,
typeDescription,
typeFingerprint = SystemFingerprint name,
typeData = fields
}
)
optionalImplementsInterfaces :: Parser [Text]
optionalImplementsInterfaces = implements <|> pure []
where
implements = label "ImplementsInterfaces" $ keyword "implements" *> sepByAnd parseName
interfaceTypeDefinition :: Maybe Text -> Parser (Text, RawDataType)
interfaceTypeDefinition typeDescription =
label "InterfaceTypeDefinition" $ do
typeName <- typDeclaration "interface"
_directives <- optionalDirectives
fields <- fieldsDefinition
pure (
typeName,
Interface DataTyCon {
typeName,
typeDescription,
typeFingerprint = SystemFingerprint typeName,
typeData = fields
}
)
unionTypeDefinition :: Maybe Text -> Parser (Text, DataFullType)
unionTypeDefinition typeDescription =
label "UnionTypeDefinition" $ do
typeName <- typDeclaration "union"
_directives <- optionalDirectives
memberTypes <- unionMemberTypes
pure (
typeName,
Union DataTyCon {
typeName,
typeDescription,
typeFingerprint = SystemFingerprint typeName,
typeData = map unionField memberTypes
}
)
where
unionField fieldType = createField [] "" ([], fieldType)
unionMemberTypes = operator '=' *> parseName `sepBy1` pipeLiteral
enumTypeDefinition :: Maybe Text -> Parser (Text, DataFullType)
enumTypeDefinition typeDescription =
label "EnumTypeDefinition" $ do
typeName <- typDeclaration "enum"
_directives <- optionalDirectives
enumValuesDefinition <- setOf enumValueDefinition
pure (
typeName,
Leaf $ LeafEnum DataTyCon {
typeName,
typeDescription,
typeFingerprint = SystemFingerprint typeName,
typeData = enumValuesDefinition
}
)
where
enumValueDefinition = label "EnumValueDefinition" $ do
_fieldDescription <- optDescription
enumValueName <- parseName
_directive <- optionalDirectives
return enumValueName
inputObjectTypeDefinition :: Maybe Text -> Parser (Text, DataFullType)
inputObjectTypeDefinition typeDescription =
label "InputObjectTypeDefinition" $ do
typeName <- typDeclaration "input"
_directives <- optionalDirectives
fields <- inputFieldsDefinition
pure
(
typeName,
InputObject DataTyCon {
typeName,
typeDescription,
typeFingerprint = SystemFingerprint typeName,
typeData = fields
}
)
where
inputFieldsDefinition :: Parser [(Key, DataField)]
inputFieldsDefinition = label "InputFieldsDefinition" $ setOf inputValueDefinition
parseFinalDataType :: Maybe Text -> Parser (Text, DataFullType)
parseFinalDataType description = label "TypeDefinition" $
inputObjectTypeDefinition description
<|> unionTypeDefinition description
<|> enumTypeDefinition description
<|> scalarTypeDefinition description
parseDataType :: Parser (Text, RawDataType)
parseDataType = label "TypeDefinition" $ do
description <- optDescription
types description
where
types description = interfaceTypeDefinition description <|>
objectTypeDefinition description <|>
finalDataT
where
finalDataT = do
(name, datatype) <- parseFinalDataType description
pure (name, FinalDataType datatype)