morpheus-graphql-0.3.0: src/Data/Morpheus/Parsing/JSONSchema/Parse.hs
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TypeOperators #-}
module Data.Morpheus.Parsing.JSONSchema.Parse
( decodeIntrospection
) where
import Data.Aeson
import Data.ByteString.Lazy (ByteString)
import Data.Morpheus.Error.Internal (internalError)
import Data.Morpheus.Parsing.Internal.Create (createArgument, createDataTypeLib, createEnumType,
createField, createScalarType, createType, createUnionType)
import Data.Morpheus.Parsing.JSONSchema.Types (EnumValue (..), Field (..), InputValue (..),
Introspection (..), Schema (..), Type (..))
import Data.Morpheus.Schema.TypeKind (TypeKind (..))
import Data.Morpheus.Types.Internal.Data (DataField, DataFullType (..), DataTypeLib,
DataTypeWrapper (..), Key, WrapperD, toHSWrappers)
import Data.Morpheus.Types.Internal.Validation (Validation)
import Data.Morpheus.Types.IO (JSONResponse (..))
import Data.Semigroup ((<>))
import Data.Text (Text, pack)
decodeIntrospection :: ByteString -> Validation DataTypeLib
decodeIntrospection jsonDoc =
case jsonSchema of
Left errors -> internalError $ pack errors
Right JSONResponse {responseData = Just Introspection {__schema = Schema {types}}} ->
traverse parse types >>= createDataTypeLib
Right res -> fail $ show res
where
jsonSchema :: Either String (JSONResponse Introspection)
jsonSchema = eitherDecode jsonDoc
class ParseJSONSchema a b where
parse :: a -> Validation (Key, b)
instance ParseJSONSchema Type DataFullType where
parse Type {name = Just typeName, kind = SCALAR} = pure $ createScalarType typeName
parse Type {name = Just typeName, kind = ENUM, enumValues = Just enums} =
pure $ createEnumType typeName (map enumName enums)
parse Type {name = Just typeName, kind = UNION, possibleTypes = Just unions} =
case traverse name unions of
Nothing -> fail "ERROR: GQL ERROR"
Just uni -> pure $ createUnionType typeName uni
parse Type {name = Just typeName, kind = INPUT_OBJECT, inputFields = Just iFields} = do
fields <- traverse parse iFields
pure (typeName, InputObject $ createType typeName fields)
parse Type {name = Just typeName, kind = OBJECT, fields = Just oFields} = do
fields <- traverse parse oFields
pure (typeName, OutputObject $ createType typeName fields)
parse x = internalError $ "Unsuported type" <> pack (show x)
instance ParseJSONSchema Field DataField where
parse Field {fieldName, fieldArgs, fieldType} = do
fType <- fieldTypeFromJSON fieldType
args <- traverse genArg fieldArgs
pure (fieldName, createField args fieldName fType)
where
genArg InputValue {inputName = argName, inputType = argType} =
createArgument argName <$> fieldTypeFromJSON argType
instance ParseJSONSchema InputValue DataField where
parse InputValue {inputName, inputType} = do
fieldType <- fieldTypeFromJSON inputType
pure (inputName, createField [] inputName fieldType)
fieldTypeFromJSON :: Type -> Validation ([WrapperD], Text)
fieldTypeFromJSON = fmap toHs . fieldTypeRec []
where
toHs (w, t) = (toHSWrappers w, t)
fieldTypeRec :: [DataTypeWrapper] -> Type -> Validation ([DataTypeWrapper], Text)
fieldTypeRec acc Type {kind = LIST, ofType = Just ofType} = fieldTypeRec (ListType : acc) ofType
fieldTypeRec acc Type {kind = NON_NULL, ofType = Just ofType} = fieldTypeRec (NonNullType : acc) ofType
fieldTypeRec acc Type {name = Just name} = pure (acc, name)
fieldTypeRec _ x = internalError $ "Unsuported Field" <> pack (show x)