Rewrite the executor tree
This commit is contained in:
		@@ -12,7 +12,6 @@ module Language.GraphQL.Executor
 | 
			
		||||
   , QueryError(..)
 | 
			
		||||
   , Response(..)
 | 
			
		||||
   , Segment(..)
 | 
			
		||||
   , coerceVariableValues
 | 
			
		||||
   , executeRequest
 | 
			
		||||
   ) where
 | 
			
		||||
 | 
			
		||||
@@ -21,10 +20,14 @@ import qualified Data.Aeson as Aeson
 | 
			
		||||
import Data.Foldable (find)
 | 
			
		||||
import Data.HashMap.Strict (HashMap)
 | 
			
		||||
import qualified Data.HashMap.Strict as HashMap
 | 
			
		||||
import Data.Int (Int32)
 | 
			
		||||
import Data.List.NonEmpty (NonEmpty)
 | 
			
		||||
import Data.Text (Text)
 | 
			
		||||
import qualified Data.Text as Text
 | 
			
		||||
import qualified Language.GraphQL.Execute.Coerce as Coerce
 | 
			
		||||
import qualified Language.GraphQL.Type as Type
 | 
			
		||||
import qualified Language.GraphQL.Type.Internal as Type.Internal
 | 
			
		||||
import Language.GraphQL.Type.Schema (Schema)
 | 
			
		||||
import qualified Language.GraphQL.Type.Schema as Schema
 | 
			
		||||
 | 
			
		||||
data Segment = Segment String | Index Int
 | 
			
		||||
@@ -83,59 +86,198 @@ data Operation = Operation
 | 
			
		||||
    Full.OperationType
 | 
			
		||||
    (Maybe String)
 | 
			
		||||
    [Full.VariableDefinition]
 | 
			
		||||
    Full.SelectionSet
 | 
			
		||||
    SelectionSet
 | 
			
		||||
    Full.Location
 | 
			
		||||
 | 
			
		||||
document :: Full.Document -> [Operation]
 | 
			
		||||
type SelectionSet = NonEmpty Selection
 | 
			
		||||
 | 
			
		||||
data Selection
 | 
			
		||||
    = FieldSelection Field
 | 
			
		||||
    | FragmentSpreadSelection FragmentSpread
 | 
			
		||||
    | InlineFragmentSelection InlineFragment
 | 
			
		||||
 | 
			
		||||
type SelectionSetOpt = [Selection]
 | 
			
		||||
 | 
			
		||||
data Argument = Argument Full.Name (Full.Node Value) Full.Location
 | 
			
		||||
 | 
			
		||||
data Field =
 | 
			
		||||
    Field (Maybe Full.Name) Full.Name [Argument] [Directive] SelectionSetOpt Full.Location
 | 
			
		||||
 | 
			
		||||
data InlineFragment = InlineFragment
 | 
			
		||||
    (Maybe Full.TypeCondition) [Directive] SelectionSet Full.Location
 | 
			
		||||
 | 
			
		||||
data FragmentSpread = FragmentSpread Full.Name [Directive] Full.Location
 | 
			
		||||
 | 
			
		||||
data Value
 | 
			
		||||
    = Variable Full.Name
 | 
			
		||||
    | Int Int32
 | 
			
		||||
    | Float Double
 | 
			
		||||
    | String Text
 | 
			
		||||
    | Boolean Bool
 | 
			
		||||
    | Null
 | 
			
		||||
    | Enum Full.Name
 | 
			
		||||
    | List [Full.Node Value]
 | 
			
		||||
    | Object [ObjectField]
 | 
			
		||||
 | 
			
		||||
data ObjectField = ObjectField
 | 
			
		||||
    { name :: Full.Name
 | 
			
		||||
    , value :: Full.Node Value
 | 
			
		||||
    , location :: Full.Location
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
data Directive = Directive Full.Name [Argument] Full.Location
 | 
			
		||||
 | 
			
		||||
document :: Full.Document -> [Full.OperationDefinition]
 | 
			
		||||
document = foldr filterOperation []
 | 
			
		||||
  where
 | 
			
		||||
    filterOperation (Full.ExecutableDefinition executableDefinition) accumulator
 | 
			
		||||
        | Full.DefinitionOperation operationDefinition' <- executableDefinition =
 | 
			
		||||
           operationDefinition operationDefinition' : accumulator
 | 
			
		||||
           operationDefinition' : accumulator
 | 
			
		||||
    filterOperation _ accumulator = accumulator -- Fragment.
 | 
			
		||||
 | 
			
		||||
operationDefinition :: Full.OperationDefinition -> Operation
 | 
			
		||||
operationDefinition = \case
 | 
			
		||||
    Full.OperationDefinition operationType operationName variables _ selectionSet operationLocation ->
 | 
			
		||||
    Full.OperationDefinition operationType operationName variables _ selectionSet' operationLocation ->
 | 
			
		||||
        let maybeOperationName = Text.unpack <$> operationName
 | 
			
		||||
         in Operation operationType maybeOperationName variables selectionSet operationLocation
 | 
			
		||||
    Full.SelectionSet selectionSet operationLocation ->
 | 
			
		||||
        Operation Full.Query Nothing [] selectionSet operationLocation
 | 
			
		||||
         in Operation
 | 
			
		||||
            operationType
 | 
			
		||||
            maybeOperationName
 | 
			
		||||
            variables
 | 
			
		||||
            (selectionSet selectionSet')
 | 
			
		||||
            operationLocation
 | 
			
		||||
    Full.SelectionSet selectionSet' operationLocation ->
 | 
			
		||||
        Operation Full.Query Nothing [] (selectionSet selectionSet') operationLocation
 | 
			
		||||
 | 
			
		||||
executeRequest :: Type.Internal.Schema IO
 | 
			
		||||
selectionSet :: Full.SelectionSet -> SelectionSet
 | 
			
		||||
selectionSet = fmap selection
 | 
			
		||||
 | 
			
		||||
selectionSetOpt :: Full.SelectionSetOpt -> SelectionSetOpt
 | 
			
		||||
selectionSetOpt = fmap selection
 | 
			
		||||
 | 
			
		||||
selection :: Full.Selection -> Selection
 | 
			
		||||
selection (Full.FieldSelection field') = FieldSelection $ field field'
 | 
			
		||||
selection (Full.FragmentSpreadSelection fragmentSpread') =
 | 
			
		||||
    FragmentSpreadSelection $ fragmentSpread fragmentSpread'
 | 
			
		||||
selection (Full.InlineFragmentSelection inlineFragment') =
 | 
			
		||||
    InlineFragmentSelection $ inlineFragment inlineFragment'
 | 
			
		||||
 | 
			
		||||
inlineFragment :: Full.InlineFragment -> InlineFragment
 | 
			
		||||
inlineFragment (Full.InlineFragment typeCondition directives selectionSet' location) =
 | 
			
		||||
    InlineFragment
 | 
			
		||||
        typeCondition
 | 
			
		||||
        (directive <$> directives)
 | 
			
		||||
        (selectionSet selectionSet')
 | 
			
		||||
        location
 | 
			
		||||
 | 
			
		||||
fragmentSpread :: Full.FragmentSpread -> FragmentSpread
 | 
			
		||||
fragmentSpread (Full.FragmentSpread name' directives location) =
 | 
			
		||||
    FragmentSpread name' (directive <$> directives) location
 | 
			
		||||
 | 
			
		||||
field :: Full.Field -> Field
 | 
			
		||||
field (Full.Field alias' name' arguments' directives' selectionSet' location') =
 | 
			
		||||
    Field
 | 
			
		||||
        alias'
 | 
			
		||||
        name'
 | 
			
		||||
        (argument <$> arguments')
 | 
			
		||||
        (directive <$> directives')
 | 
			
		||||
        (selectionSetOpt selectionSet')
 | 
			
		||||
        location'
 | 
			
		||||
 | 
			
		||||
argument :: Full.Argument -> Argument
 | 
			
		||||
argument (Full.Argument name' valueNode location') =
 | 
			
		||||
    Argument name' (node valueNode) location'
 | 
			
		||||
 | 
			
		||||
directive :: Full.Directive -> Directive
 | 
			
		||||
directive (Full.Directive name' arguments location') =
 | 
			
		||||
    Directive name' (argument <$> arguments) location'
 | 
			
		||||
 | 
			
		||||
variableValue :: Full.Value -> Value
 | 
			
		||||
variableValue (Full.Variable name') = Variable name'
 | 
			
		||||
variableValue (Full.Int integer) = Int integer
 | 
			
		||||
variableValue (Full.Float double) = Float double
 | 
			
		||||
variableValue (Full.String string) = String string
 | 
			
		||||
variableValue (Full.Boolean boolean) = Boolean boolean
 | 
			
		||||
variableValue Full.Null = Null
 | 
			
		||||
variableValue (Full.Enum enum) = Enum enum
 | 
			
		||||
variableValue (Full.List list) = List $ node <$> list
 | 
			
		||||
variableValue (Full.Object objectFields) = Object $ objectField <$> objectFields
 | 
			
		||||
 | 
			
		||||
node :: Full.Node Full.Value -> Full.Node Value
 | 
			
		||||
node Full.Node{node = node', ..} = Full.Node (variableValue node') location
 | 
			
		||||
 | 
			
		||||
objectField :: Full.ObjectField Full.Value -> ObjectField
 | 
			
		||||
objectField Full.ObjectField{..} = ObjectField
 | 
			
		||||
    { name = name
 | 
			
		||||
    , value = node value
 | 
			
		||||
    , location = location
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
executeRequest :: Schema IO
 | 
			
		||||
    -> Full.Document
 | 
			
		||||
    -> Maybe String
 | 
			
		||||
    -> Aeson.Object
 | 
			
		||||
    -> Aeson.Object
 | 
			
		||||
    -> IO Response
 | 
			
		||||
executeRequest _schema sourceDocument operationName _variableValues _initialValue =
 | 
			
		||||
   let transformedDocument = document sourceDocument
 | 
			
		||||
       operation = getOperation transformedDocument operationName
 | 
			
		||||
    in case operation of
 | 
			
		||||
executeRequest schema sourceDocument operationName variableValues initialValue =
 | 
			
		||||
    case operationAndVariables of
 | 
			
		||||
        Left queryError' -> pure $ respondWithQueryError queryError'
 | 
			
		||||
        Right (Operation Full.Query _ _ _ _) -> executeQuery
 | 
			
		||||
        Right (Operation Full.Mutation _ _ _ _) -> executeMutation
 | 
			
		||||
        Right (Operation Full.Subscription _ _ _ _) -> subscribe
 | 
			
		||||
        Right (operation, coercedVariableValues')
 | 
			
		||||
            | Operation Full.Query _ _ _ _ <- operation ->
 | 
			
		||||
                executeQuery operation schema coercedVariableValues' initialValue
 | 
			
		||||
            | Operation Full.Mutation _ _ _ _ <- operation ->
 | 
			
		||||
                executeMutation operation schema coercedVariableValues' initialValue
 | 
			
		||||
            | Operation Full.Subscription _ _ _ _ <- operation ->
 | 
			
		||||
                subscribe operation schema coercedVariableValues' initialValue
 | 
			
		||||
  where
 | 
			
		||||
    schemaTypes = Schema.types schema
 | 
			
		||||
    transformedDocument = document sourceDocument
 | 
			
		||||
    operationAndVariables = do
 | 
			
		||||
        operation <- operationDefinition
 | 
			
		||||
            <$> getOperation transformedDocument operationName
 | 
			
		||||
        coercedVariableValues <- coerceVariableValues
 | 
			
		||||
            schemaTypes
 | 
			
		||||
            operation
 | 
			
		||||
            variableValues
 | 
			
		||||
        pure (operation, coercedVariableValues)
 | 
			
		||||
 | 
			
		||||
getOperation :: [Operation] -> Maybe String -> Either QueryError Operation
 | 
			
		||||
getOperation :: [Full.OperationDefinition] -> Maybe String -> Either QueryError Full.OperationDefinition
 | 
			
		||||
getOperation [operation] Nothing = Right operation
 | 
			
		||||
getOperation operations (Just givenOperationName)
 | 
			
		||||
    = maybe (Left $ OperationNotFound givenOperationName) Right
 | 
			
		||||
    $ find findOperationByName operations
 | 
			
		||||
  where
 | 
			
		||||
    findOperationByName (Operation _ (Just operationName) _ _ _) =
 | 
			
		||||
        givenOperationName == operationName
 | 
			
		||||
    findOperationByName (Full.OperationDefinition _ (Just operationName) _ _ _ _) =
 | 
			
		||||
        givenOperationName == Text.unpack operationName
 | 
			
		||||
    findOperationByName _ = False
 | 
			
		||||
getOperation _ _ = Left OperationNameRequired
 | 
			
		||||
 | 
			
		||||
executeQuery :: IO Response
 | 
			
		||||
executeQuery = pure $ Response mempty mempty
 | 
			
		||||
executeQuery :: forall m
 | 
			
		||||
    . Operation
 | 
			
		||||
    -> Schema m
 | 
			
		||||
    -> Type.Subs
 | 
			
		||||
    -> Aeson.Object
 | 
			
		||||
    -> IO Response
 | 
			
		||||
executeQuery _operation schema _coercedVariableValues _initialValue =
 | 
			
		||||
    let _queryType = Schema.query schema
 | 
			
		||||
     in pure $ Response mempty mempty
 | 
			
		||||
 | 
			
		||||
executeMutation :: IO Response
 | 
			
		||||
executeMutation = pure $ Response mempty mempty
 | 
			
		||||
executeMutation :: forall m
 | 
			
		||||
    . Operation
 | 
			
		||||
    -> Schema m
 | 
			
		||||
    -> Type.Subs
 | 
			
		||||
    -> Aeson.Object
 | 
			
		||||
    -> IO Response
 | 
			
		||||
executeMutation _operation _schema _coercedVariableValues _initialValue =
 | 
			
		||||
    pure $ Response mempty mempty
 | 
			
		||||
 | 
			
		||||
subscribe :: IO Response
 | 
			
		||||
subscribe = pure $ Response mempty mempty
 | 
			
		||||
subscribe :: forall m
 | 
			
		||||
    . Operation
 | 
			
		||||
    -> Schema m
 | 
			
		||||
    -> Type.Subs
 | 
			
		||||
    -> Aeson.Object
 | 
			
		||||
    -> IO Response
 | 
			
		||||
subscribe _operation _schema _coercedVariableValues _initialValue =
 | 
			
		||||
    pure $ Response mempty mempty
 | 
			
		||||
 | 
			
		||||
coerceVariableValues :: Coerce.VariableValue a
 | 
			
		||||
    => forall m
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user