summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEugen Wissner <belka@caraus.de>2020-06-10 11:42:00 +0200
committerEugen Wissner <belka@caraus.de>2020-06-10 11:42:00 +0200
commitc37b9c88b1f64d842ad837a18bfbe01026324abb (patch)
tree729da648f29f6db9062e654ee159d610d418fe17
parentfdb1268213f9ea6da33d82fc57e1b0c7874c3fe2 (diff)
downloadgraphql-c37b9c88b1f64d842ad837a18bfbe01026324abb.tar.gz
Skip unknown fields
-rw-r--r--CHANGELOG.md3
-rw-r--r--src/Language/GraphQL/Execute/Execution.hs14
-rw-r--r--stack.yaml2
-rw-r--r--tests/Language/GraphQL/ExecuteSpec.hs42
4 files changed, 51 insertions, 10 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index ce71877..dc93324 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -13,10 +13,11 @@ and this project adheres to
constants cannot be variables. `AST.Document.ConstValue` was added,
`AST.Document.ObjectField` was modified.
- 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.
- Argument value coercion.
- Variable value coercion.
+- The executor should skip the fields missing in the object type and not fail.
### Changed
- `Schema.Resolver` was moved to `Type.Out`, it is a field and resolver function
diff --git a/src/Language/GraphQL/Execute/Execution.hs b/src/Language/GraphQL/Execute/Execution.hs
index 79646c3..a7b57f8 100644
--- a/src/Language/GraphQL/Execute/Execution.hs
+++ b/src/Language/GraphQL/Execute/Execution.hs
@@ -17,7 +17,6 @@ import qualified Data.Map.Strict as Map
import Data.Maybe (fromMaybe)
import Data.Sequence (Seq(..))
import Data.Text (Text)
-import qualified Data.Text as Text
import qualified Data.Sequence as Seq
import Language.GraphQL.AST (Name)
import Language.GraphQL.AST.Core
@@ -100,10 +99,10 @@ instanceOf objectType (AbstractUnionType unionType) =
executeField :: Monad m
=> Definition.Value
- -> Out.Resolver m
-> Field m
+ -> Out.Resolver m
-> 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 Field _ _ arguments' _ = field
case coerceArgumentValues argumentDefinitions arguments' of
@@ -160,13 +159,12 @@ executeSelectionSet result objectType@(Out.ObjectType _ _ _ resolvers) selection
pure $ Aeson.toJSON resolvedValues
where
forEach _responseKey (field :<| _) =
- tryResolvers field >>= lift . pure . pure
+ let Field _ name _ _ = field
+ in traverse (tryResolver field) $ lookupResolver name
forEach _ _ = pure Nothing
lookupResolver = flip HashMap.lookup resolvers
- tryResolvers fld@(Field _ name _ _)
- | Just typeField <- lookupResolver name =
- executeField result typeField fld
- | otherwise = errmsg $ Text.unwords ["field", name, "not resolved."]
+ tryResolver typeField field =
+ executeField result typeField field >>= lift . pure
coerceArgumentValues
:: HashMap Name In.Argument
diff --git a/stack.yaml b/stack.yaml
index 894eb1a..4df91ed 100644
--- a/stack.yaml
+++ b/stack.yaml
@@ -1,4 +1,4 @@
-resolver: lts-15.16
+resolver: lts-16.0
packages:
- .
diff --git a/tests/Language/GraphQL/ExecuteSpec.hs b/tests/Language/GraphQL/ExecuteSpec.hs
new file mode 100644
index 0000000..d0e7a66
--- /dev/null
+++ b/tests/Language/GraphQL/ExecuteSpec.hs
@@ -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