Deprecate Language.GraphQL.Execute.Schema

It is not a schema (at least not a complete one), but a resolver list,
and the resolvers should be provided by the user separately, because the
schema can originate from a GraphQL document. Schema name should be free
to provide a data type for the real schema later.
This commit is contained in:
Eugen Wissner 2019-08-30 07:26:04 +02:00
parent c1943c1979
commit 22313d05df
5 changed files with 67 additions and 64 deletions

View File

@ -6,7 +6,12 @@ All notable changes to this project will be documented in this file.
- Minimal documentation for all public symbols.
### Deprecated
- Language.GraphQL.AST.FragmentName. Replaced with Language.GraphQL.AST.Name.
- `Language.GraphQL.AST.FragmentName`. Replaced with Language.GraphQL.AST.Name.
- `Language.GraphQL.Execute.Schema` - It is not a schema (at least not a
complete one), but a resolver list, and the resolvers should be provided by
the user separately, because the schema can originate from a GraphQL
document. `Schema` name should be free to provide a data type for the real
schema later.
## [0.5.0.0] - 2019-08-14
### Added

View File

@ -5,32 +5,31 @@ module Language.GraphQL
) where
import Control.Monad.IO.Class (MonadIO)
import qualified Data.Text as T
import qualified Data.Aeson as Aeson
import Text.Megaparsec (parse)
import Data.List.NonEmpty (NonEmpty)
import qualified Data.Text as T
import Language.GraphQL.Error
import Language.GraphQL.Execute
import Language.GraphQL.Parser
import Language.GraphQL.Schema
import qualified Language.GraphQL.Schema as Schema
import Text.Megaparsec (parse)
import Language.GraphQL.Error
-- | Takes a 'Schema' and text representing a @GraphQL@ request document.
-- If the text parses correctly as a @GraphQL@ query the query is
-- executed according to the given 'Schema'.
--
-- Returns the response as an @Aeson.@'Aeson.Value'.
graphql :: MonadIO m => Schema m -> T.Text -> m Aeson.Value
-- | If the text parses correctly as a @GraphQL@ query the query is
-- executed using the given 'Schema.Resolver's.
graphql :: MonadIO m
=> NonEmpty (Schema.Resolver m) -- ^ Resolvers.
-> T.Text -- ^ Text representing a @GraphQL@ request document.
-> m Aeson.Value -- ^ Response.
graphql = flip graphqlSubs $ const Nothing
-- | Takes a 'Schema', a variable substitution function and text
-- representing a @GraphQL@ request document. If the text parses
-- correctly as a @GraphQL@ query the substitution is applied to the
-- query and the query is then executed according to the given 'Schema'.
--
-- Returns the response as an @Aeson.@'Aeson.Value'.
graphqlSubs :: MonadIO m => Schema m -> Subs -> T.Text -> m Aeson.Value
graphqlSubs schema f =
either parseError (execute schema f)
-- | If the text parses correctly as a @GraphQL@ query the substitution is
-- applied to the query and the query is then executed using to the given
-- 'Schema.Resolver's.
graphqlSubs :: MonadIO m
=> NonEmpty (Schema.Resolver m) -- ^ Resolvers.
-> Schema.Subs -- ^ Variable substitution function.
-> T.Text -- ^ Text representing a @GraphQL@ request document.
-> m Aeson.Value -- ^ Response.
graphqlSubs schema f
= either parseError (execute schema f)
. parse document ""

View File

@ -1,7 +1,6 @@
{-# LANGUAGE OverloadedStrings #-}
-- | This module provides the function to execute a @GraphQL@ request --
-- according to a 'Schema'.
-- | This module provides functions to execute a @GraphQL@ request.
module Language.GraphQL.Execute
( execute
, executeWithName
@ -9,51 +8,53 @@ module Language.GraphQL.Execute
import Control.Monad.IO.Class (MonadIO)
import qualified Data.Aeson as Aeson
import Data.List.NonEmpty (NonEmpty(..))
import qualified Data.List.NonEmpty as NE
import Data.List.NonEmpty (NonEmpty((:|)))
import Data.Text (Text)
import qualified Data.Text as Text
import qualified Language.GraphQL.AST as AST
import qualified Language.GraphQL.AST.Core as AST.Core
import qualified Language.GraphQL.AST.Transform as Transform
import Language.GraphQL.Error
import Language.GraphQL.Schema (Schema)
import qualified Language.GraphQL.Schema as Schema
-- | Takes a 'Schema', a variable substitution function ('Schema.Subs'), and a
-- @GraphQL@ 'document'. The substitution is applied to the document using
-- 'rootFields', and the 'Schema''s resolvers are applied to the resulting fields.
-- | The substitution is applied to the document, and the resolvers are applied
-- to the resulting fields.
--
-- Returns the result of the query against the 'Schema' wrapped in a /data/ field, or
-- errors wrapped in an /errors/ field.
-- Returns the result of the query against the schema wrapped in a /data/
-- field, or errors wrapped in an /errors/ field.
execute :: MonadIO m
=> Schema m
-> Schema.Subs
-> AST.Document
=> NonEmpty (Schema.Resolver m) -- ^ Resolvers.
-> Schema.Subs -- ^ Variable substitution function.
-> AST.Document -- @GraphQL@ document.
-> m Aeson.Value
execute schema subs doc =
maybe transformError (document schema Nothing) $ Transform.document subs doc
where
transformError = return $ singleError "Schema transformation error."
-- | Takes a 'Schema', operation name, a variable substitution function ('Schema.Subs'),
-- and a @GraphQL@ 'document'. The substitution is applied to the document using
-- 'rootFields', and the 'Schema''s resolvers are applied to the resulting fields.
-- | The substitution is applied to the document, and the resolvers are applied
-- to the resulting fields. The operation name can be used if the document
-- defines multiple root operations.
--
-- Returns the result of the query against the 'Schema' wrapped in a /data/ field, or
-- errors wrapped in an /errors/ field.
-- Returns the result of the query against the schema wrapped in a /data/
-- field, or errors wrapped in an /errors/ field.
executeWithName :: MonadIO m
=> Schema m
-> Text
-> Schema.Subs
-> AST.Document
=> NonEmpty (Schema.Resolver m) -- ^ Resolvers
-> Text -- ^ Operation name.
-> Schema.Subs -- ^ Variable substitution function.
-> AST.Document -- ^ @GraphQL@ Document.
-> m Aeson.Value
executeWithName schema name subs doc =
maybe transformError (document schema $ Just name) $ Transform.document subs doc
where
transformError = return $ singleError "Schema transformation error."
document :: MonadIO m => Schema m -> Maybe Text -> AST.Core.Document -> m Aeson.Value
document :: MonadIO m
=> NonEmpty (Schema.Resolver m)
-> Maybe Text
-> AST.Core.Document
-> m Aeson.Value
document schema Nothing (op :| []) = operation schema op
document schema (Just name) operations = case NE.dropWhile matchingName operations of
[] -> return $ singleError
@ -65,7 +66,10 @@ document schema (Just name) operations = case NE.dropWhile matchingName operatio
matchingName _ = False
document _ _ _ = return $ singleError "Missing operation name."
operation :: MonadIO m => Schema m -> AST.Core.Operation -> m Aeson.Value
operation :: MonadIO m
=> NonEmpty (Schema.Resolver m)
-> AST.Core.Operation
-> m Aeson.Value
operation schema (AST.Core.Query _ flds)
= runCollectErrs (Schema.resolve (NE.toList schema) (NE.toList flds))
operation schema (AST.Core.Mutation _ flds)

View File

@ -1,7 +1,7 @@
{-# LANGUAGE OverloadedStrings #-}
-- | This module provides a representation of a @GraphQL@ Schema in addition to
-- functions for defining and manipulating Schemas.
-- functions for defining and manipulating schemas.
module Language.GraphQL.Schema
( Resolver
, Schema
@ -43,6 +43,7 @@ import Language.GraphQL.Trans
import Language.GraphQL.Type
import Language.GraphQL.AST.Core
{-# DEPRECATED Schema "Use NonEmpty (Resolver m) instead" #-}
-- | A GraphQL schema.
-- @m@ is usually expected to be an instance of 'MonadIO'.
type Schema m = NonEmpty (Resolver m)

View File

@ -11,46 +11,40 @@ module Test.StarWars.Schema
import Control.Monad.Trans.Except (throwE)
import Control.Monad.Trans.Class (lift)
import Control.Monad.IO.Class (MonadIO(..))
import Data.List.NonEmpty (NonEmpty((:|)))
import Language.GraphQL.Schema ( Schema
, Resolver
, Argument(..)
, Value(..)
)
import Data.List.NonEmpty (NonEmpty(..))
import qualified Language.GraphQL.Schema as Schema
import Language.GraphQL.Trans
import Language.GraphQL.Type
import Test.StarWars.Data
-- * Schema
-- See https://github.com/graphql/graphql-js/blob/master/src/__tests__/starWarsSchema.js
schema :: MonadIO m => Schema m
schema :: MonadIO m => NonEmpty (Schema.Resolver m)
schema = hero :| [human, droid]
hero :: MonadIO m => Resolver m
hero :: MonadIO m => Schema.Resolver m
hero = Schema.objectA "hero" $ \case
[] -> character artoo
[Argument "episode" (ValueEnum "NEWHOPE")] -> character $ getHero 4
[Argument "episode" (ValueEnum "EMPIRE" )] -> character $ getHero 5
[Argument "episode" (ValueEnum "JEDI" )] -> character $ getHero 6
[Schema.Argument "episode" (Schema.ValueEnum "NEWHOPE")] -> character $ getHero 4
[Schema.Argument "episode" (Schema.ValueEnum "EMPIRE" )] -> character $ getHero 5
[Schema.Argument "episode" (Schema.ValueEnum "JEDI" )] -> character $ getHero 6
_ -> ActionT $ throwE "Invalid arguments."
human :: MonadIO m => Resolver m
human :: MonadIO m => Schema.Resolver m
human = Schema.wrappedObjectA "human" $ \case
[Argument "id" (ValueString i)] -> do
[Schema.Argument "id" (Schema.ValueString i)] -> do
humanCharacter <- lift $ return $ getHuman i >>= Just
case humanCharacter of
Nothing -> return Null
Just e -> Named <$> character e
_ -> ActionT $ throwE "Invalid arguments."
droid :: MonadIO m => Resolver m
droid :: MonadIO m => Schema.Resolver m
droid = Schema.objectA "droid" $ \case
[Argument "id" (ValueString i)] -> character =<< liftIO (getDroid i)
[Schema.Argument "id" (Schema.ValueString i)] -> character =<< liftIO (getDroid i)
_ -> ActionT $ throwE "Invalid arguments."
character :: MonadIO m => Character -> ActionT m [Resolver m]
character :: MonadIO m => Character -> ActionT m [Schema.Resolver m]
character char = return
[ Schema.scalar "id" $ return $ id_ char
, Schema.scalar "name" $ return $ name char