forked from OSS/graphql
Skip unknown fields
This commit is contained in:
parent
fdb1268213
commit
c37b9c88b1
@ -13,10 +13,11 @@ and this project adheres to
|
|||||||
constants cannot be variables. `AST.Document.ConstValue` was added,
|
constants cannot be variables. `AST.Document.ConstValue` was added,
|
||||||
`AST.Document.ObjectField` was modified.
|
`AST.Document.ObjectField` was modified.
|
||||||
- AST transformation should never fail.
|
- AST transformation should never fail.
|
||||||
* Missing variable are assumed to be null.
|
* Arguments and fields with a missing variable as value should be left out.
|
||||||
* Invalid (recusrive or non-existing) fragments should be skipped.
|
* Invalid (recusrive or non-existing) fragments should be skipped.
|
||||||
- Argument value coercion.
|
- Argument value coercion.
|
||||||
- Variable value coercion.
|
- Variable value coercion.
|
||||||
|
- The executor should skip the fields missing in the object type and not fail.
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
- `Schema.Resolver` was moved to `Type.Out`, it is a field and resolver function
|
- `Schema.Resolver` was moved to `Type.Out`, it is a field and resolver function
|
||||||
|
@ -17,7 +17,6 @@ import qualified Data.Map.Strict as Map
|
|||||||
import Data.Maybe (fromMaybe)
|
import Data.Maybe (fromMaybe)
|
||||||
import Data.Sequence (Seq(..))
|
import Data.Sequence (Seq(..))
|
||||||
import Data.Text (Text)
|
import Data.Text (Text)
|
||||||
import qualified Data.Text as Text
|
|
||||||
import qualified Data.Sequence as Seq
|
import qualified Data.Sequence as Seq
|
||||||
import Language.GraphQL.AST (Name)
|
import Language.GraphQL.AST (Name)
|
||||||
import Language.GraphQL.AST.Core
|
import Language.GraphQL.AST.Core
|
||||||
@ -100,10 +99,10 @@ instanceOf objectType (AbstractUnionType unionType) =
|
|||||||
|
|
||||||
executeField :: Monad m
|
executeField :: Monad m
|
||||||
=> Definition.Value
|
=> Definition.Value
|
||||||
-> Out.Resolver m
|
|
||||||
-> Field m
|
-> Field m
|
||||||
|
-> Out.Resolver m
|
||||||
-> CollectErrsT m Aeson.Value
|
-> CollectErrsT m Aeson.Value
|
||||||
executeField prev (Out.Resolver fieldDefinition resolver) field = do
|
executeField prev field (Out.Resolver fieldDefinition resolver) = do
|
||||||
let Out.Field _ fieldType argumentDefinitions = fieldDefinition
|
let Out.Field _ fieldType argumentDefinitions = fieldDefinition
|
||||||
let Field _ _ arguments' _ = field
|
let Field _ _ arguments' _ = field
|
||||||
case coerceArgumentValues argumentDefinitions arguments' of
|
case coerceArgumentValues argumentDefinitions arguments' of
|
||||||
@ -160,13 +159,12 @@ executeSelectionSet result objectType@(Out.ObjectType _ _ _ resolvers) selection
|
|||||||
pure $ Aeson.toJSON resolvedValues
|
pure $ Aeson.toJSON resolvedValues
|
||||||
where
|
where
|
||||||
forEach _responseKey (field :<| _) =
|
forEach _responseKey (field :<| _) =
|
||||||
tryResolvers field >>= lift . pure . pure
|
let Field _ name _ _ = field
|
||||||
|
in traverse (tryResolver field) $ lookupResolver name
|
||||||
forEach _ _ = pure Nothing
|
forEach _ _ = pure Nothing
|
||||||
lookupResolver = flip HashMap.lookup resolvers
|
lookupResolver = flip HashMap.lookup resolvers
|
||||||
tryResolvers fld@(Field _ name _ _)
|
tryResolver typeField field =
|
||||||
| Just typeField <- lookupResolver name =
|
executeField result typeField field >>= lift . pure
|
||||||
executeField result typeField fld
|
|
||||||
| otherwise = errmsg $ Text.unwords ["field", name, "not resolved."]
|
|
||||||
|
|
||||||
coerceArgumentValues
|
coerceArgumentValues
|
||||||
:: HashMap Name In.Argument
|
:: HashMap Name In.Argument
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
resolver: lts-15.16
|
resolver: lts-16.0
|
||||||
|
|
||||||
packages:
|
packages:
|
||||||
- .
|
- .
|
||||||
|
42
tests/Language/GraphQL/ExecuteSpec.hs
Normal file
42
tests/Language/GraphQL/ExecuteSpec.hs
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
|
module Language.GraphQL.ExecuteSpec
|
||||||
|
( spec
|
||||||
|
) where
|
||||||
|
|
||||||
|
import Data.Aeson ((.=))
|
||||||
|
import qualified Data.Aeson as Aeson
|
||||||
|
import Data.Functor.Identity (Identity(..))
|
||||||
|
import Data.HashMap.Strict (HashMap)
|
||||||
|
import qualified Data.HashMap.Strict as HashMap
|
||||||
|
import Language.GraphQL.AST (Name)
|
||||||
|
import Language.GraphQL.AST.Parser (document)
|
||||||
|
import Language.GraphQL.Error
|
||||||
|
import Language.GraphQL.Execute
|
||||||
|
import Language.GraphQL.Type
|
||||||
|
import Language.GraphQL.Type.Out as Out
|
||||||
|
import Test.Hspec (Spec, describe, it, shouldBe)
|
||||||
|
import Text.Megaparsec (parse)
|
||||||
|
|
||||||
|
schema :: Schema Identity
|
||||||
|
schema = Schema {query = queryType, mutation = Nothing}
|
||||||
|
|
||||||
|
queryType :: Out.ObjectType Identity
|
||||||
|
queryType = Out.ObjectType "Query" Nothing []
|
||||||
|
$ HashMap.singleton "count"
|
||||||
|
$ Out.Resolver countField
|
||||||
|
$ pure
|
||||||
|
$ Int 8
|
||||||
|
where
|
||||||
|
countField = Out.Field Nothing (Out.NonNullScalarType int) HashMap.empty
|
||||||
|
|
||||||
|
spec :: Spec
|
||||||
|
spec =
|
||||||
|
describe "execute" $
|
||||||
|
it "skips unknown fields" $
|
||||||
|
let expected = Aeson.object
|
||||||
|
["data" .= Aeson.object ["count" .= (8 :: Int)]]
|
||||||
|
execute' = execute schema (mempty :: HashMap Name Aeson.Value)
|
||||||
|
actual = runIdentity
|
||||||
|
$ either parseError execute'
|
||||||
|
$ parse document "" "{ count number }"
|
||||||
|
in actual `shouldBe` expected
|
Loading…
Reference in New Issue
Block a user