{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE TupleSections #-}
module Data.Morpheus.Validation.Document.Validation
( validatePartialDocument
)
where
import Data.Maybe
import Data.Morpheus.Error.Document.Interface
( ImplementsError(..)
, partialImplements
, unknownInterface
)
import Data.Morpheus.Rendering.RenderGQL
( RenderGQL(..) )
import Data.Morpheus.Types.Internal.AST
( DataField(..)
, DataType(..)
, DataObject
, DataTypeContent(..)
, Name
, Key
, TypeRef(..)
, isWeaker
)
import Data.Morpheus.Types.Internal.Resolving
( Validation
, Failure(..)
)
validatePartialDocument :: [(Key, DataType)] -> Validation [(Key, DataType)]
validatePartialDocument lib = catMaybes <$> traverse validateType lib
where
validateType :: (Key, DataType) -> Validation (Maybe (Key, DataType))
validateType (name, dt@DataType { typeName , typeContent = DataObject { objectImplements , objectFields} }) = do
interface <- traverse getInterfaceByKey objectImplements
case concatMap (mustBeSubset objectFields) interface of
[] -> pure $ Just (name, dt)
errors -> failure $ partialImplements typeName errors
validateType (_,DataType { typeContent = DataInterface {}}) = pure Nothing
validateType (name, x) = pure $ Just (name, x)
mustBeSubset
:: DataObject -> (Name, DataObject) -> [(Key, Key, ImplementsError)]
mustBeSubset objFields (typeName, interfaceFields ) = concatMap
checkField
interfaceFields
where
checkField :: (Key, DataField) -> [(Key, Key, ImplementsError)]
checkField (key, DataField { fieldType = interfaceT@TypeRef { typeConName = interfaceTypeName, typeWrappers = interfaceWrappers } })
= case lookup key objFields of
Just DataField { fieldType = objT@TypeRef { typeConName, typeWrappers } }
| typeConName == interfaceTypeName && not
(isWeaker typeWrappers interfaceWrappers)
-> []
| otherwise
-> [ ( typeName
, key
, UnexpectedType { expectedType = render interfaceT
, foundType = render objT
}
)
]
Nothing -> [(typeName, key, UndefinedField)]
getInterfaceByKey :: Key -> Validation (Name,DataObject)
getInterfaceByKey key = case lookup key lib of
Just DataType { typeContent = DataInterface { interfaceFields } } -> pure (key,interfaceFields)
_ -> failure $ unknownInterface key