forked from OSS/graphql
Rewrite the executor tree
This commit is contained in:
parent
d7422e46ca
commit
5751870d2a
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user