Release 1.0.0.0
This commit is contained in:
parent
c93c64a7f4
commit
1d7f016b9c
@ -6,4 +6,7 @@ The format is based on
|
|||||||
and this project adheres to
|
and this project adheres to
|
||||||
[Haskell Package Versioning Policy](https://pvp.haskell.org/).
|
[Haskell Package Versioning Policy](https://pvp.haskell.org/).
|
||||||
|
|
||||||
## [Unreleased]
|
## [1.0.0.0] - 2022-03-29
|
||||||
|
### Added
|
||||||
|
- JSON serialization.
|
||||||
|
- Test helpers.
|
||||||
|
@ -1,9 +1,4 @@
|
|||||||
packages:
|
packages:
|
||||||
.
|
.
|
||||||
|
|
||||||
source-repository-package
|
|
||||||
type: git
|
|
||||||
location: git://caraus.tech/pub/graphql.git
|
|
||||||
tag: 8503c0f288201223776f9962438c577241f08c9d
|
|
||||||
|
|
||||||
constraints: graphql -json
|
constraints: graphql -json
|
||||||
|
@ -31,12 +31,12 @@ library
|
|||||||
ghc-options: -Wall
|
ghc-options: -Wall
|
||||||
build-depends:
|
build-depends:
|
||||||
aeson ^>= 2.0.3,
|
aeson ^>= 2.0.3,
|
||||||
base ^>=4.14.3.0,
|
base >= 4.7 && < 5,
|
||||||
conduit ^>= 1.3.4,
|
conduit ^>= 1.3.4,
|
||||||
containers ^>= 0.6.2,
|
containers ^>= 0.6.2,
|
||||||
exceptions ^>= 0.10.4,
|
exceptions ^>= 0.10.4,
|
||||||
hspec-expectations >= 0.8.2 && < 0.9,
|
hspec-expectations >= 0.8.2 && < 0.9,
|
||||||
graphql ^>= 1.0.2,
|
graphql ^>= 1.0.3.0,
|
||||||
megaparsec >= 9.0 && < 10,
|
megaparsec >= 9.0 && < 10,
|
||||||
scientific ^>= 0.3.7,
|
scientific ^>= 0.3.7,
|
||||||
text >= 1.2 && < 3,
|
text >= 1.2 && < 3,
|
||||||
@ -48,6 +48,7 @@ test-suite graphql-test
|
|||||||
type: exitcode-stdio-1.0
|
type: exitcode-stdio-1.0
|
||||||
main-is: Spec.hs
|
main-is: Spec.hs
|
||||||
other-modules:
|
other-modules:
|
||||||
|
Language.GraphQL.CoerceSpec
|
||||||
Language.GraphQL.DirectiveSpec
|
Language.GraphQL.DirectiveSpec
|
||||||
Language.GraphQL.FragmentSpec
|
Language.GraphQL.FragmentSpec
|
||||||
Language.GraphQL.RootOperationSpec
|
Language.GraphQL.RootOperationSpec
|
||||||
@ -56,10 +57,11 @@ test-suite graphql-test
|
|||||||
ghc-options: -threaded -rtsopts -with-rtsopts=-N -Wall
|
ghc-options: -threaded -rtsopts -with-rtsopts=-N -Wall
|
||||||
build-depends:
|
build-depends:
|
||||||
aeson,
|
aeson,
|
||||||
base >= 4.8 && < 5,
|
base,
|
||||||
graphql,
|
graphql,
|
||||||
graphql-spice,
|
graphql-spice,
|
||||||
hspec >= 2.9.1 && < 3,
|
hspec >= 2.9.1 && < 3,
|
||||||
|
scientific,
|
||||||
text,
|
text,
|
||||||
unordered-containers
|
unordered-containers
|
||||||
default-language: Haskell2010
|
default-language: Haskell2010
|
||||||
|
@ -1,7 +1,12 @@
|
|||||||
|
{- This Source Code Form is subject to the terms of the Mozilla Public License,
|
||||||
|
v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||||
|
obtain one at https://mozilla.org/MPL/2.0/. -}
|
||||||
|
|
||||||
{-# LANGUAGE OverloadedStrings #-}
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
{-# LANGUAGE NamedFieldPuns #-}
|
{-# LANGUAGE NamedFieldPuns #-}
|
||||||
{-# LANGUAGE RecordWildCards #-}
|
{-# LANGUAGE RecordWildCards #-}
|
||||||
|
|
||||||
|
-- | JSON serialization.
|
||||||
module Language.GraphQL.JSON
|
module Language.GraphQL.JSON
|
||||||
( JSON(..)
|
( JSON(..)
|
||||||
, graphql
|
, graphql
|
||||||
@ -31,6 +36,7 @@ import qualified Language.GraphQL.Type.In as In
|
|||||||
import qualified Language.GraphQL.Type.Out as Out
|
import qualified Language.GraphQL.Type.Out as Out
|
||||||
import qualified Language.GraphQL.Type as Type
|
import qualified Language.GraphQL.Type as Type
|
||||||
|
|
||||||
|
-- | Wraps an aeson value.
|
||||||
newtype JSON = JSON Aeson.Value
|
newtype JSON = JSON Aeson.Value
|
||||||
|
|
||||||
instance Aeson.ToJSON JSON where
|
instance Aeson.ToJSON JSON where
|
||||||
@ -111,7 +117,7 @@ instance VariableValue JSON where
|
|||||||
foldVector _ Nothing = Nothing
|
foldVector _ Nothing = Nothing
|
||||||
foldVector variableValue (Just list) = do
|
foldVector variableValue (Just list) = do
|
||||||
coerced <- coerceVariableValue listType $ JSON variableValue
|
coerced <- coerceVariableValue listType $ JSON variableValue
|
||||||
pure $ coerced : list
|
pure $ coerced : list
|
||||||
coerceVariableValue _ _ = Nothing
|
coerceVariableValue _ _ = Nothing
|
||||||
|
|
||||||
-- | If the text parses correctly as a @GraphQL@ query the query is
|
-- | If the text parses correctly as a @GraphQL@ query the query is
|
||||||
|
98
tests/Language/GraphQL/CoerceSpec.hs
Normal file
98
tests/Language/GraphQL/CoerceSpec.hs
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
{- This Source Code Form is subject to the terms of the Mozilla Public License,
|
||||||
|
v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||||
|
obtain one at https://mozilla.org/MPL/2.0/. -}
|
||||||
|
|
||||||
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
|
module Language.GraphQL.CoerceSpec
|
||||||
|
( spec
|
||||||
|
) where
|
||||||
|
|
||||||
|
import Data.Aeson as Aeson ((.=))
|
||||||
|
import qualified Data.Aeson as Aeson
|
||||||
|
import qualified Data.Aeson.Types as Aeson
|
||||||
|
import qualified Data.HashMap.Strict as HashMap
|
||||||
|
import Data.Maybe (isNothing)
|
||||||
|
import Data.Scientific (scientific)
|
||||||
|
import qualified Language.GraphQL.Execute.Coerce as Coerce
|
||||||
|
import Language.GraphQL.JSON (JSON(..))
|
||||||
|
import qualified Language.GraphQL.Type.In as In
|
||||||
|
import Language.GraphQL.Type
|
||||||
|
import Prelude hiding (id)
|
||||||
|
import Test.Hspec (Spec, describe, it, shouldBe, shouldSatisfy)
|
||||||
|
|
||||||
|
singletonInputObject :: In.Type
|
||||||
|
singletonInputObject = In.NamedInputObjectType type'
|
||||||
|
where
|
||||||
|
type' = In.InputObjectType "ObjectName" Nothing inputFields
|
||||||
|
inputFields = HashMap.singleton "field" field
|
||||||
|
field = In.InputField Nothing (In.NamedScalarType string) Nothing
|
||||||
|
|
||||||
|
namedIdType :: In.Type
|
||||||
|
namedIdType = In.NamedScalarType id
|
||||||
|
|
||||||
|
spec :: Spec
|
||||||
|
spec =
|
||||||
|
describe "VariableValue Aeson" $ do
|
||||||
|
it "coerces strings" $
|
||||||
|
let expected = Just (String "asdf")
|
||||||
|
actual = Coerce.coerceVariableValue (In.NamedScalarType string)
|
||||||
|
$ JSON $ Aeson.String "asdf"
|
||||||
|
in actual `shouldBe` expected
|
||||||
|
it "coerces non-null strings" $
|
||||||
|
let expected = Just (String "asdf")
|
||||||
|
actual = Coerce.coerceVariableValue (In.NonNullScalarType string)
|
||||||
|
$ JSON $ Aeson.String "asdf"
|
||||||
|
in actual `shouldBe` expected
|
||||||
|
it "coerces booleans" $
|
||||||
|
let expected = Just (Boolean True)
|
||||||
|
actual = Coerce.coerceVariableValue (In.NamedScalarType boolean)
|
||||||
|
$ JSON $ Aeson.Bool True
|
||||||
|
in actual `shouldBe` expected
|
||||||
|
it "coerces zero to an integer" $
|
||||||
|
let expected = Just (Int 0)
|
||||||
|
actual = Coerce.coerceVariableValue (In.NamedScalarType int)
|
||||||
|
$ JSON $ Aeson.Number 0
|
||||||
|
in actual `shouldBe` expected
|
||||||
|
it "rejects fractional if an integer is expected" $
|
||||||
|
let actual = Coerce.coerceVariableValue (In.NamedScalarType int)
|
||||||
|
$ JSON $ Aeson.Number $ scientific 14 (-1)
|
||||||
|
in actual `shouldSatisfy` isNothing
|
||||||
|
it "coerces float numbers" $
|
||||||
|
let expected = Just (Float 1.4)
|
||||||
|
actual = Coerce.coerceVariableValue (In.NamedScalarType float)
|
||||||
|
$ JSON $ Aeson.Number $ scientific 14 (-1)
|
||||||
|
in actual `shouldBe` expected
|
||||||
|
it "coerces IDs" $
|
||||||
|
let expected = Just (String "1234")
|
||||||
|
json = JSON $ Aeson.String "1234"
|
||||||
|
actual = Coerce.coerceVariableValue namedIdType json
|
||||||
|
in actual `shouldBe` expected
|
||||||
|
it "coerces input objects" $
|
||||||
|
let actual = Coerce.coerceVariableValue singletonInputObject
|
||||||
|
$ JSON
|
||||||
|
$ Aeson.object ["field" .= ("asdf" :: Aeson.Value)]
|
||||||
|
expected = Just $ Object $ HashMap.singleton "field" "asdf"
|
||||||
|
in actual `shouldBe` expected
|
||||||
|
it "skips the field if it is missing in the variables" $
|
||||||
|
let actual = Coerce.coerceVariableValue singletonInputObject
|
||||||
|
$ JSON Aeson.emptyObject
|
||||||
|
expected = Just $ Object HashMap.empty
|
||||||
|
in actual `shouldBe` expected
|
||||||
|
it "fails if input object value contains extra fields" $
|
||||||
|
let actual = Coerce.coerceVariableValue singletonInputObject
|
||||||
|
$ JSON $ Aeson.object variableFields
|
||||||
|
variableFields =
|
||||||
|
[ "field" .= ("asdf" :: Aeson.Value)
|
||||||
|
, "extra" .= ("qwer" :: Aeson.Value)
|
||||||
|
]
|
||||||
|
in actual `shouldSatisfy` isNothing
|
||||||
|
it "preserves null" $
|
||||||
|
let actual = Coerce.coerceVariableValue namedIdType
|
||||||
|
$ JSON Aeson.Null
|
||||||
|
in actual `shouldBe` Just Null
|
||||||
|
it "preserves list order" $
|
||||||
|
let list = JSON $ Aeson.toJSONList ["asdf" :: Aeson.Value, "qwer"]
|
||||||
|
listType = (In.ListType $ In.NamedScalarType string)
|
||||||
|
actual = Coerce.coerceVariableValue listType list
|
||||||
|
expected = Just $ List [String "asdf", String "qwer"]
|
||||||
|
in actual `shouldBe` expected
|
Loading…
Reference in New Issue
Block a user