Handle top-level fragments

Fixes #17.
This commit is contained in:
Eugen Wissner 2019-10-19 10:00:25 +02:00
parent 37254c8c95
commit c7d5b02911
4 changed files with 34 additions and 21 deletions

View File

@ -31,11 +31,10 @@ dependencies:
- megaparsec - megaparsec
- text - text
- transformers - transformers
- unordered-containers
library: library:
source-dirs: src source-dirs: src
dependencies:
- unordered-containers
tests: tests:
tasty: tasty:

View File

@ -8,10 +8,10 @@ module Language.GraphQL.AST.Transform
) where ) where
import Control.Applicative (empty) import Control.Applicative (empty)
import Control.Monad ((<=<))
import Data.Bifunctor (first) import Data.Bifunctor (first)
import Data.Either (partitionEithers) import Data.Either (partitionEithers)
import Data.Foldable (fold, foldMap) import Data.Foldable (fold, foldMap)
import Data.List.NonEmpty (NonEmpty)
import qualified Data.List.NonEmpty as NonEmpty import qualified Data.List.NonEmpty as NonEmpty
import Data.Monoid (Alt(Alt,getAlt), (<>)) import Data.Monoid (Alt(Alt,getAlt), (<>))
import qualified Language.GraphQL.AST as Full import qualified Language.GraphQL.AST as Full
@ -44,22 +44,20 @@ operations
-> Fragmenter -> Fragmenter
-> [Full.OperationDefinition] -> [Full.OperationDefinition]
-> Maybe Core.Document -> Maybe Core.Document
operations subs fr = NonEmpty.nonEmpty <=< traverse (operation subs fr) operations subs fr = NonEmpty.nonEmpty . fmap (operation subs fr)
operation operation
:: Schema.Subs :: Schema.Subs
-> Fragmenter -> Fragmenter
-> Full.OperationDefinition -> Full.OperationDefinition
-> Maybe Core.Operation -> Core.Operation
operation subs fr (Full.OperationSelectionSet sels) = operation subs fr (Full.OperationSelectionSet sels) =
operation subs fr $ Full.OperationDefinition Full.Query empty empty empty sels operation subs fr $ Full.OperationDefinition Full.Query empty empty empty sels
-- TODO: Validate Variable definitions with substituter -- TODO: Validate Variable definitions with substituter
operation subs fr (Full.OperationDefinition operationType name _vars _dirs sels) operation subs fr (Full.OperationDefinition Full.Query name _vars _dirs sels) =
= case operationType of Core.Query name $ appendSelection subs fr sels
Full.Query -> Core.Query name <$> node operation subs fr (Full.OperationDefinition Full.Mutation name _vars _dirs sels) =
Full.Mutation -> Core.Mutation name <$> node Core.Mutation name $ appendSelection subs fr sels
where
node = traverse (hush . selection subs fr) sels
selection selection
:: Schema.Subs :: Schema.Subs
@ -75,12 +73,9 @@ selection subs fr (Full.SelectionInlineFragment fragment)
= Right = Right
$ Core.SelectionFragment $ Core.SelectionFragment
$ Core.Fragment typeCondition $ Core.Fragment typeCondition
$ NonEmpty.fromList $ appendSelection subs fr selectionSet
$ appendSelection selectionSet
| (Full.InlineFragment Nothing _ selectionSet) <- fragment | (Full.InlineFragment Nothing _ selectionSet) <- fragment
= Left $ appendSelection selectionSet = Left $ NonEmpty.toList $ appendSelection subs fr selectionSet
where
appendSelection = foldr (either (++) (:) . selection subs fr) []
-- * Fragment replacement -- * Fragment replacement
@ -132,5 +127,10 @@ value subs (Full.ValueObject o) =
objectField :: Schema.Subs -> Full.ObjectField -> Maybe Core.ObjectField objectField :: Schema.Subs -> Full.ObjectField -> Maybe Core.ObjectField
objectField subs (Full.ObjectField n v) = Core.ObjectField n <$> value subs v objectField subs (Full.ObjectField n v) = Core.ObjectField n <$> value subs v
hush :: Either a b -> Maybe b appendSelection ::
hush = either (const Nothing) Just Schema.Subs ->
Fragmenter ->
NonEmpty Full.Selection ->
NonEmpty Core.Selection
appendSelection subs fr = NonEmpty.fromList
. foldr (either (++) (:) . selection subs fr) []

View File

@ -1,4 +1,4 @@
resolver: lts-14.8 resolver: lts-14.10
packages: packages:
- . - .

View File

@ -4,12 +4,13 @@ module Test.FragmentSpec
( spec ( spec
) where ) where
import Data.Aeson (object, (.=)) import Data.Aeson (Value(..), object, (.=))
import qualified Data.HashMap.Strict as HashMap
import Data.List.NonEmpty (NonEmpty(..)) import Data.List.NonEmpty (NonEmpty(..))
import Data.Text (Text) import Data.Text (Text)
import Language.GraphQL import Language.GraphQL
import qualified Language.GraphQL.Schema as Schema import qualified Language.GraphQL.Schema as Schema
import Test.Hspec (Spec, describe, it, shouldBe) import Test.Hspec (Spec, describe, it, shouldBe, shouldNotSatisfy)
import Text.RawString.QQ (r) import Text.RawString.QQ (r)
size :: Schema.Resolver IO size :: Schema.Resolver IO
@ -81,3 +82,16 @@ spec = describe "Inline fragment executor" $ do
] ]
] ]
in actual `shouldBe` expected in actual `shouldBe` expected
it "evaluates fragments on Query" $ do
let query = [r|{
... {
size
}
}|]
actual <- graphql (size :| []) query
actual `shouldNotSatisfy` hasErrors
where
hasErrors (Object object') = HashMap.member "errors" object'
hasErrors _ = True