morpheus-graphql-core-0.16.0: src/Data/Morpheus/Validation/Internal/Directive.hs
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE NoImplicitPrelude #-}
module Data.Morpheus.Validation.Internal.Directive
( shouldIncludeSelection,
validateDirectives,
)
where
import Data.Morpheus.Error.Utils
( validationErrorMessage,
)
import Data.Morpheus.Internal.Utils
( Failure (..),
selectOr,
)
import Data.Morpheus.Types.Internal.AST
( Argument (..),
Directive (..),
DirectiveDefinition (..),
DirectiveLocation (..),
Directives,
FieldName,
Ref (..),
ScalarValue (..),
Schema (..),
VALID,
Value (..),
msg,
)
import Data.Morpheus.Types.Internal.Validation
( Validator,
askSchema,
selectKnown,
selectRequired,
withDirective,
)
import Data.Morpheus.Validation.Internal.Arguments
( ArgumentsConstraints,
validateDirectiveArguments,
)
import Relude
validateDirectives ::
ArgumentsConstraints ctx schemaS s =>
DirectiveLocation ->
Directives s ->
Validator schemaS ctx (Directives VALID)
validateDirectives location = traverse (validate location)
validate ::
ArgumentsConstraints c schemaS s =>
DirectiveLocation ->
Directive s ->
Validator schemaS c (Directive VALID)
validate location directive@Directive {..} =
withDirective directive $ do
Schema {directiveDefinitions} <- askSchema
directiveDef <- selectKnown directive directiveDefinitions
Directive directivePosition directiveName
<$> ( validateDirectiveLocation location directive directiveDef
*> validateDirectiveArguments directiveDef directiveArgs
)
validateDirectiveLocation ::
DirectiveLocation ->
Directive s ->
DirectiveDefinition s' ->
Validator schemaS ctx ()
validateDirectiveLocation
loc
Directive {directiveName, directivePosition}
DirectiveDefinition {directiveDefinitionLocations}
| loc `elem` directiveDefinitionLocations = pure ()
| otherwise =
failure $
validationErrorMessage
(Just directivePosition)
("Directive " <> msg directiveName <> " may not to be used on " <> msg loc)
directiveFulfilled ::
Bool ->
FieldName ->
Directives s ->
Validator schemaS ctx Bool
directiveFulfilled target = selectOr (pure True) (argumentIf target)
shouldIncludeSelection ::
Directives VALID ->
Validator schemaS ctx Bool
shouldIncludeSelection directives = do
dontSkip <- directiveFulfilled False "skip" directives
include <- directiveFulfilled True "include" directives
pure (dontSkip && include)
argumentIf ::
Bool ->
Directive s ->
Validator schemaS ctx Bool
argumentIf target Directive {directiveArgs, directivePosition} =
selectRequired (Ref "if" directivePosition) directiveArgs
>>= assertArgument target
assertArgument ::
Bool ->
Argument s ->
Validator schemaS ctx Bool
assertArgument asserted Argument {argumentValue = Scalar (Boolean actual)} = pure (asserted == actual)
assertArgument _ Argument {argumentValue, argumentPosition} =
failure
$ validationErrorMessage
(Just argumentPosition)
$ "Expected type Boolean!, found " <> msg argumentValue <> "."