forked from OSS/graphql
Inline fragment spreads
This commit is contained in:
parent
4f7e990bf9
commit
fef7c1ed98
@ -17,10 +17,11 @@ module Language.GraphQL.Executor
|
|||||||
) where
|
) where
|
||||||
|
|
||||||
import Control.Monad.Trans.Class (MonadTrans(..))
|
import Control.Monad.Trans.Class (MonadTrans(..))
|
||||||
import Control.Monad.Trans.Reader (ReaderT(..), ask, asks, runReader)
|
import Control.Monad.Trans.Reader (ReaderT(..), asks, runReader)
|
||||||
import Control.Monad (foldM)
|
import Control.Monad (foldM)
|
||||||
import qualified Language.GraphQL.AST.Document as Full
|
import qualified Language.GraphQL.AST.Document as Full
|
||||||
import qualified Data.Aeson as Aeson
|
import qualified Data.Aeson as Aeson
|
||||||
|
import Data.Bifunctor (first)
|
||||||
import Data.Foldable (find)
|
import Data.Foldable (find)
|
||||||
import Data.Functor.Identity (Identity)
|
import Data.Functor.Identity (Identity)
|
||||||
import Data.HashMap.Strict (HashMap)
|
import Data.HashMap.Strict (HashMap)
|
||||||
@ -28,6 +29,7 @@ import qualified Data.HashMap.Strict as HashMap
|
|||||||
import Data.Int (Int32)
|
import Data.Int (Int32)
|
||||||
import Data.List.NonEmpty (NonEmpty)
|
import Data.List.NonEmpty (NonEmpty)
|
||||||
import qualified Data.List.NonEmpty as NonEmpty
|
import qualified Data.List.NonEmpty as NonEmpty
|
||||||
|
import Data.Maybe (catMaybes)
|
||||||
import Data.Text (Text)
|
import Data.Text (Text)
|
||||||
import qualified Data.Text as Text
|
import qualified Data.Text as Text
|
||||||
import qualified Language.GraphQL.Execute.Coerce as Coerce
|
import qualified Language.GraphQL.Execute.Coerce as Coerce
|
||||||
@ -38,8 +40,13 @@ import qualified Language.GraphQL.Type.Internal as Type.Internal
|
|||||||
import Language.GraphQL.Type.Schema (Schema)
|
import Language.GraphQL.Type.Schema (Schema)
|
||||||
import qualified Language.GraphQL.Type.Schema as Schema
|
import qualified Language.GraphQL.Type.Schema as Schema
|
||||||
|
|
||||||
|
data Replacement = Replacement
|
||||||
|
{ variableValues :: Type.Subs
|
||||||
|
, fragmentDefinitions :: HashMap Full.Name Full.FragmentDefinition
|
||||||
|
}
|
||||||
|
|
||||||
newtype TransformT m a = TransformT
|
newtype TransformT m a = TransformT
|
||||||
{ runTransformT :: ReaderT Type.Subs m a
|
{ runTransformT :: ReaderT Replacement m a
|
||||||
}
|
}
|
||||||
|
|
||||||
instance Functor m => Functor (TransformT m) where
|
instance Functor m => Functor (TransformT m) where
|
||||||
@ -118,8 +125,7 @@ type SelectionSet = [Selection]
|
|||||||
|
|
||||||
data Selection
|
data Selection
|
||||||
= FieldSelection Field
|
= FieldSelection Field
|
||||||
| FragmentSpreadSelection FragmentSpread
|
| FragmentSelection Fragment
|
||||||
| InlineFragmentSelection InlineFragment
|
|
||||||
|
|
||||||
data Argument = Argument Full.Name (Full.Node Value) Full.Location
|
data Argument = Argument Full.Name (Full.Node Value) Full.Location
|
||||||
|
|
||||||
@ -131,11 +137,9 @@ data Field = Field
|
|||||||
SelectionSet
|
SelectionSet
|
||||||
Full.Location
|
Full.Location
|
||||||
|
|
||||||
data InlineFragment = InlineFragment
|
data Fragment = Fragment
|
||||||
(Maybe Full.TypeCondition) [Type.Directive] SelectionSet Full.Location
|
(Maybe Full.TypeCondition) [Type.Directive] SelectionSet Full.Location
|
||||||
|
|
||||||
data FragmentSpread = FragmentSpread Full.Name [Type.Directive] Full.Location
|
|
||||||
|
|
||||||
data Value
|
data Value
|
||||||
= Variable Full.Name
|
= Variable Full.Name
|
||||||
| Int Int32
|
| Int Int32
|
||||||
@ -153,52 +157,70 @@ data ObjectField = ObjectField
|
|||||||
, location :: Full.Location
|
, location :: Full.Location
|
||||||
}
|
}
|
||||||
|
|
||||||
document :: Full.Document -> [Full.OperationDefinition]
|
document :: Full.Document
|
||||||
document = foldr filterOperation []
|
-> ([Full.OperationDefinition], HashMap Full.Name Full.FragmentDefinition)
|
||||||
|
document = foldr filterOperation ([], HashMap.empty)
|
||||||
where
|
where
|
||||||
filterOperation (Full.ExecutableDefinition executableDefinition) accumulator
|
filterOperation (Full.ExecutableDefinition executableDefinition) accumulator
|
||||||
| Full.DefinitionOperation operationDefinition' <- executableDefinition =
|
| Full.DefinitionOperation operationDefinition' <- executableDefinition =
|
||||||
operationDefinition' : accumulator
|
first (operationDefinition' :) accumulator
|
||||||
filterOperation _ accumulator = accumulator -- Fragment.
|
| Full.DefinitionFragment fragmentDefinition <- executableDefinition
|
||||||
|
, Full.FragmentDefinition fragmentName _ _ _ _ <- fragmentDefinition =
|
||||||
|
HashMap.insert fragmentName fragmentDefinition <$> accumulator
|
||||||
|
filterOperation _ accumulator = accumulator -- Type system definitions.
|
||||||
|
|
||||||
transform :: Full.OperationDefinition -> Transform Operation
|
transform :: Full.OperationDefinition -> Transform Operation
|
||||||
transform (Full.OperationDefinition operationType _ _ _ selectionSet' _) = do
|
transform (Full.OperationDefinition operationType _ _ _ selectionSet' _) = do
|
||||||
coercedVariableValues <- TransformT ask
|
coercedVariableValues <- TransformT $ asks variableValues
|
||||||
transformedSelections <- selectionSet selectionSet'
|
transformedSelections <- selectionSet selectionSet'
|
||||||
pure $ Operation operationType coercedVariableValues transformedSelections
|
pure $ Operation operationType coercedVariableValues transformedSelections
|
||||||
transform (Full.SelectionSet selectionSet' _) = do
|
transform (Full.SelectionSet selectionSet' _) = do
|
||||||
coercedVariableValues <- TransformT ask
|
coercedVariableValues <- TransformT $ asks variableValues
|
||||||
transformedSelections <- selectionSet selectionSet'
|
transformedSelections <- selectionSet selectionSet'
|
||||||
pure $ Operation Full.Query coercedVariableValues transformedSelections
|
pure $ Operation Full.Query coercedVariableValues transformedSelections
|
||||||
|
|
||||||
selectionSet :: Full.SelectionSet -> Transform SelectionSet
|
selectionSet :: Full.SelectionSet -> Transform SelectionSet
|
||||||
selectionSet = traverse selection . NonEmpty.toList
|
selectionSet = fmap catMaybes . traverse selection . NonEmpty.toList
|
||||||
|
|
||||||
selection :: Full.Selection -> Transform Selection
|
selection :: Full.Selection -> Transform (Maybe Selection)
|
||||||
selection (Full.FieldSelection field') = FieldSelection <$> field field'
|
selection (Full.FieldSelection field') = Just . FieldSelection <$> field field'
|
||||||
selection (Full.FragmentSpreadSelection fragmentSpread') =
|
selection (Full.FragmentSpreadSelection fragmentSpread') =
|
||||||
FragmentSpreadSelection <$> fragmentSpread fragmentSpread'
|
fmap FragmentSelection <$> fragmentSpread fragmentSpread'
|
||||||
selection (Full.InlineFragmentSelection inlineFragment') =
|
selection (Full.InlineFragmentSelection inlineFragment') =
|
||||||
InlineFragmentSelection <$> inlineFragment inlineFragment'
|
Just . FragmentSelection <$> inlineFragment inlineFragment'
|
||||||
|
|
||||||
inlineFragment :: Full.InlineFragment -> Transform InlineFragment
|
inlineFragment :: Full.InlineFragment -> Transform Fragment
|
||||||
inlineFragment (Full.InlineFragment typeCondition directives selectionSet' location) = do
|
inlineFragment (Full.InlineFragment typeCondition directives selectionSet' location) = do
|
||||||
transformedSelections <- selectionSet selectionSet'
|
transformedSelections <- selectionSet selectionSet'
|
||||||
transformedDirectives <- traverse directive directives
|
transformedDirectives <- traverse directive directives
|
||||||
pure $ InlineFragment
|
pure $ Fragment
|
||||||
typeCondition
|
typeCondition
|
||||||
transformedDirectives
|
transformedDirectives
|
||||||
transformedSelections
|
transformedSelections
|
||||||
location
|
location
|
||||||
|
|
||||||
fragmentSpread :: Full.FragmentSpread -> Transform FragmentSpread
|
fragmentSpread :: Full.FragmentSpread -> Transform (Maybe Fragment)
|
||||||
fragmentSpread (Full.FragmentSpread name' directives location) = do
|
fragmentSpread (Full.FragmentSpread spreadName directives location) = do
|
||||||
transformedDirectives <- traverse directive directives
|
transformedDirectives <- traverse directive directives
|
||||||
pure $ FragmentSpread name' transformedDirectives location
|
possibleFragmentDefinition <- TransformT
|
||||||
|
$ asks
|
||||||
|
$ HashMap.lookup spreadName
|
||||||
|
. fragmentDefinitions
|
||||||
|
case possibleFragmentDefinition of
|
||||||
|
Just (Full.FragmentDefinition _ typeCondition _ selections _) -> do
|
||||||
|
transformedSelections <- selectionSet selections
|
||||||
|
pure $ Just $ Fragment
|
||||||
|
(Just typeCondition)
|
||||||
|
transformedDirectives
|
||||||
|
transformedSelections
|
||||||
|
location
|
||||||
|
Nothing ->
|
||||||
|
pure Nothing
|
||||||
|
|
||||||
|
|
||||||
field :: Full.Field -> Transform Field
|
field :: Full.Field -> Transform Field
|
||||||
field (Full.Field alias' name' arguments' directives selectionSet' location') = do
|
field (Full.Field alias' name' arguments' directives selectionSet' location') = do
|
||||||
transformedSelections <- traverse selection selectionSet'
|
transformedSelections <- catMaybes <$> traverse selection selectionSet'
|
||||||
transformedDirectives <- traverse directive directives
|
transformedDirectives <- traverse directive directives
|
||||||
pure $ Field
|
pure $ Field
|
||||||
alias'
|
alias'
|
||||||
@ -224,8 +246,10 @@ directive (Full.Directive name' arguments _)
|
|||||||
|
|
||||||
directiveValue :: Full.Value -> Transform Type.Value
|
directiveValue :: Full.Value -> Transform Type.Value
|
||||||
directiveValue = \case
|
directiveValue = \case
|
||||||
(Full.Variable name') ->
|
(Full.Variable name') -> TransformT
|
||||||
TransformT $ asks (HashMap.lookupDefault Type.Null name')
|
$ asks
|
||||||
|
$ HashMap.lookupDefault Type.Null name'
|
||||||
|
. variableValues
|
||||||
(Full.Int integer) -> pure $ Type.Int integer
|
(Full.Int integer) -> pure $ Type.Int integer
|
||||||
(Full.Float double) -> pure $ Type.Float double
|
(Full.Float double) -> pure $ Type.Float double
|
||||||
(Full.String string) -> pure $ Type.String string
|
(Full.String string) -> pure $ Type.String string
|
||||||
@ -280,15 +304,19 @@ executeRequest schema sourceDocument operationName variableValues initialValue =
|
|||||||
subscribe topSelections schema coercedVariables initialValue
|
subscribe topSelections schema coercedVariables initialValue
|
||||||
where
|
where
|
||||||
schemaTypes = Schema.types schema
|
schemaTypes = Schema.types schema
|
||||||
operationDefinitions = document sourceDocument
|
(operationDefinitions, fragmentDefinitions') = document sourceDocument
|
||||||
operationAndVariables = do
|
operationAndVariables = do
|
||||||
operationDefinition <- getOperation operationDefinitions operationName
|
operationDefinition <- getOperation operationDefinitions operationName
|
||||||
coercedVariableValues <- coerceVariableValues
|
coercedVariableValues <- coerceVariableValues
|
||||||
schemaTypes
|
schemaTypes
|
||||||
operationDefinition
|
operationDefinition
|
||||||
variableValues
|
variableValues
|
||||||
|
let replacement = Replacement
|
||||||
|
{ variableValues = coercedVariableValues
|
||||||
|
, fragmentDefinitions = fragmentDefinitions'
|
||||||
|
}
|
||||||
pure
|
pure
|
||||||
$ flip runReader coercedVariableValues
|
$ flip runReader replacement
|
||||||
$ runTransformT
|
$ runTransformT
|
||||||
$ transform operationDefinition
|
$ transform operationDefinition
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user