Propagate Maybe in the transform tree
Since the transform tree can already find some errors, it may fail here and there. Almost all functions return a Maybe to signalize an error. Will be replaced with an Either of course.
This commit is contained in:
parent
0e3b6184be
commit
417ff5da7d
@ -1,5 +1,3 @@
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
|
||||
-- | After the document is parsed, before getting executed the AST is
|
||||
-- transformed into a similar, simpler AST. This module is responsible for
|
||||
-- this transformation.
|
||||
@ -12,26 +10,24 @@ import Data.HashMap.Strict (HashMap)
|
||||
import qualified Data.HashMap.Strict as HashMap
|
||||
import Data.List.NonEmpty (NonEmpty)
|
||||
import qualified Data.List.NonEmpty as NonEmpty
|
||||
import Data.Maybe (fromMaybe)
|
||||
import qualified Language.GraphQL.AST as Full
|
||||
import qualified Language.GraphQL.AST.Core as Core
|
||||
import qualified Language.GraphQL.Schema as Schema
|
||||
|
||||
-- | Associates a fragment name with a list of 'Core.Field's.
|
||||
type Fragments = HashMap Core.Name [Core.Field]
|
||||
type Fragments = HashMap Core.Name (NonEmpty Core.Field)
|
||||
|
||||
-- | Rewrites the original syntax tree into an intermediate representation used
|
||||
-- for query execution.
|
||||
document :: Schema.Subs -> Full.Document -> Maybe Core.Document
|
||||
document subs doc = operations subs fragments operations'
|
||||
document subs doc =
|
||||
case fragments of
|
||||
Just fragments' -> operations subs fragments' operations'
|
||||
Nothing -> Nothing
|
||||
where
|
||||
(fragments, operations') = foldr (defrag subs) mempty
|
||||
(fragments, operations') = foldr (defrag subs) (Just HashMap.empty, [])
|
||||
$ NonEmpty.toList doc
|
||||
|
||||
extractFragment :: Fragments -> Core.Name -> [Core.Selection]
|
||||
extractFragment fragments name = Core.SelectionField
|
||||
<$> fromMaybe mempty (HashMap.lookup name fragments)
|
||||
|
||||
-- * Operation
|
||||
|
||||
-- TODO: Replace Maybe by MonadThrow CustomError
|
||||
@ -53,27 +49,27 @@ operation subs fragments (Full.OperationSelectionSet sels) =
|
||||
operation subs fragments $ Full.OperationDefinition Full.Query mempty mempty mempty sels
|
||||
-- TODO: Validate Variable definitions with substituter
|
||||
operation subs fragments (Full.OperationDefinition Full.Query name _vars _dirs sels) =
|
||||
pure $ Core.Query name $ appendSelection subs fragments sels
|
||||
Core.Query name <$> appendSelection subs fragments sels
|
||||
operation subs fragments (Full.OperationDefinition Full.Mutation name _vars _dirs sels) =
|
||||
pure $ Core.Mutation name $ appendSelection subs fragments sels
|
||||
Core.Mutation name <$> appendSelection subs fragments sels
|
||||
|
||||
selection ::
|
||||
Schema.Subs ->
|
||||
Fragments ->
|
||||
Full.Selection ->
|
||||
Either [Core.Selection] Core.Selection
|
||||
Maybe (Either (NonEmpty Core.Selection) Core.Selection)
|
||||
selection subs fragments (Full.SelectionField fld)
|
||||
= Right $ Core.SelectionField $ field subs fragments fld
|
||||
= Right . Core.SelectionField <$> field subs fragments fld
|
||||
selection _ fragments (Full.SelectionFragmentSpread (Full.FragmentSpread name _))
|
||||
= Left $ extractFragment fragments name
|
||||
= Left . fmap Core.SelectionField <$> HashMap.lookup name fragments
|
||||
selection subs fragments (Full.SelectionInlineFragment fragment)
|
||||
| (Full.InlineFragment (Just typeCondition) _ selectionSet) <- fragment
|
||||
= Right
|
||||
$ Core.SelectionFragment
|
||||
$ Core.Fragment typeCondition
|
||||
$ appendSelection subs fragments selectionSet
|
||||
. Core.SelectionFragment
|
||||
. Core.Fragment typeCondition
|
||||
<$> appendSelection subs fragments selectionSet
|
||||
| (Full.InlineFragment Nothing _ selectionSet) <- fragment
|
||||
= Left $ NonEmpty.toList $ appendSelection subs fragments selectionSet
|
||||
= Left <$> appendSelection subs fragments selectionSet
|
||||
|
||||
-- * Fragment replacement
|
||||
|
||||
@ -81,35 +77,37 @@ selection subs fragments (Full.SelectionInlineFragment fragment)
|
||||
defrag ::
|
||||
Schema.Subs ->
|
||||
Full.Definition ->
|
||||
(Fragments, [Full.OperationDefinition]) ->
|
||||
(Fragments, [Full.OperationDefinition])
|
||||
(Maybe Fragments, [Full.OperationDefinition]) ->
|
||||
(Maybe Fragments, [Full.OperationDefinition])
|
||||
defrag _ (Full.DefinitionOperation op) (fragments, operations') =
|
||||
(fragments, op : operations')
|
||||
defrag subs (Full.DefinitionFragment fragDef) (fragments, operations') =
|
||||
defrag subs (Full.DefinitionFragment fragDef) (Just fragments, operations') =
|
||||
(fragmentDefinition subs fragments fragDef, operations')
|
||||
defrag _ _ (Nothing, operations') =
|
||||
(Nothing, operations')
|
||||
|
||||
fragmentDefinition ::
|
||||
Schema.Subs ->
|
||||
Fragments ->
|
||||
Full.FragmentDefinition ->
|
||||
Fragments
|
||||
fragmentDefinition subs fragments (Full.FragmentDefinition name _tc _dirs sels) =
|
||||
HashMap.insert name (extractField <$> emitValue) fragments
|
||||
Maybe Fragments
|
||||
fragmentDefinition subs fragments (Full.FragmentDefinition name _tc _dirs sels) = do
|
||||
emitted <- emitValue
|
||||
newValue <- traverse extractField emitted
|
||||
Just $ HashMap.insert name newValue fragments
|
||||
where
|
||||
emitValue :: Maybe (NonEmpty Core.Selection)
|
||||
emitValue = do
|
||||
selections <- NonEmpty.toList $ selection subs mempty <$> sels
|
||||
either id pure selections
|
||||
extractField (Core.SelectionField field') = field'
|
||||
extractField _ = error "Fragments within fragments are not supported yet"
|
||||
selections <- traverse (selection subs fragments) sels
|
||||
pure $ selections >>= either id pure
|
||||
extractField :: Core.Selection -> Maybe Core.Field
|
||||
extractField (Core.SelectionField field') = Just field'
|
||||
extractField _ = Nothing -- Fragments within fragments are not supported yet
|
||||
|
||||
field :: Schema.Subs -> Fragments -> Full.Field -> Core.Field
|
||||
field :: Schema.Subs -> Fragments -> Full.Field -> Maybe Core.Field
|
||||
field subs fragments (Full.Field a n args _dirs sels) =
|
||||
Core.Field a n (fold $ argument subs `traverse` args) (foldr go mempty sels)
|
||||
where
|
||||
go :: Full.Selection -> [Core.Selection] -> [Core.Selection]
|
||||
go (Full.SelectionFragmentSpread (Full.FragmentSpread name _dirs)) =
|
||||
(extractFragment fragments name <>)
|
||||
go sel = (either id pure (selection subs fragments sel) <>)
|
||||
Core.Field a n (fold $ argument subs `traverse` args)
|
||||
<$> appendSelectionOpt subs fragments sels
|
||||
|
||||
argument :: Schema.Subs -> Full.Argument -> Maybe Core.Argument
|
||||
argument subs (Full.Argument n v) = Core.Argument n <$> value subs v
|
||||
@ -130,10 +128,25 @@ value subs (Full.ValueObject o) =
|
||||
objectField :: Schema.Subs -> Full.ObjectField -> Maybe Core.ObjectField
|
||||
objectField subs (Full.ObjectField n v) = Core.ObjectField n <$> value subs v
|
||||
|
||||
appendSelectionOpt ::
|
||||
Traversable t =>
|
||||
Schema.Subs ->
|
||||
Fragments ->
|
||||
t Full.Selection ->
|
||||
Maybe [Core.Selection]
|
||||
appendSelectionOpt subs fragments = foldr go (Just [])
|
||||
where
|
||||
go :: Full.Selection -> Maybe [Core.Selection] -> Maybe [Core.Selection]
|
||||
go _ Nothing = Nothing
|
||||
go sel (Just acc) = append acc <$> selection subs fragments sel
|
||||
append acc (Left list) = NonEmpty.toList list <> acc
|
||||
append acc (Right one) = one : acc
|
||||
|
||||
appendSelection ::
|
||||
Schema.Subs ->
|
||||
Fragments ->
|
||||
NonEmpty Full.Selection ->
|
||||
NonEmpty Core.Selection
|
||||
appendSelection subs fragments = NonEmpty.fromList
|
||||
. foldr (either (++) (:) . selection subs fragments) []
|
||||
Maybe (NonEmpty Core.Selection)
|
||||
appendSelection subs fragments fullSelection = do
|
||||
coreSelection <-appendSelectionOpt subs fragments fullSelection
|
||||
NonEmpty.nonEmpty coreSelection
|
||||
|
Loading…
Reference in New Issue
Block a user