aboutsummaryrefslogtreecommitdiff
path: root/src/Language/GraphQL/Schema.hs
diff options
context:
space:
mode:
Diffstat (limited to 'src/Language/GraphQL/Schema.hs')
-rw-r--r--src/Language/GraphQL/Schema.hs138
1 files changed, 0 insertions, 138 deletions
diff --git a/src/Language/GraphQL/Schema.hs b/src/Language/GraphQL/Schema.hs
deleted file mode 100644
index c678e48..0000000
--- a/src/Language/GraphQL/Schema.hs
+++ /dev/null
@@ -1,138 +0,0 @@
-{-# LANGUAGE OverloadedStrings #-}
-
--- | This module provides a representation of a @GraphQL@ Schema in addition to
--- functions for defining and manipulating schemas.
-module Language.GraphQL.Schema
- ( Resolver(..)
- , Subs
- , object
- , resolve
- , resolversToMap
- , scalar
- , wrappedObject
- , wrappedScalar
- -- * AST Reexports
- , Field
- , Value(..)
- ) where
-
-import Control.Monad.Trans.Class (lift)
-import Control.Monad.Trans.Except (runExceptT)
-import Control.Monad.Trans.Reader (runReaderT)
-import Data.Foldable (fold, toList)
-import Data.Maybe (fromMaybe)
-import qualified Data.Aeson as Aeson
-import Data.HashMap.Strict (HashMap)
-import qualified Data.HashMap.Strict as HashMap
-import Data.Sequence (Seq)
-import Data.Text (Text)
-import qualified Data.Text as T
-import Language.GraphQL.AST.Core
-import Language.GraphQL.Error
-import Language.GraphQL.Trans
-import qualified Language.GraphQL.Type as Type
-
--- | Resolves a 'Field' into an @Aeson.@'Data.Aeson.Types.Object' with error
--- information (if an error has occurred). @m@ is an arbitrary monad, usually
--- 'IO'.
-data Resolver m = Resolver
- Text -- ^ Name
- (Field -> CollectErrsT m Aeson.Object) -- ^ Resolver
-
--- | Converts resolvers to a map.
-resolversToMap
- :: (Foldable f, Functor f)
- => f (Resolver m)
- -> HashMap Text (Field -> CollectErrsT m Aeson.Object)
-resolversToMap = HashMap.fromList . toList . fmap toKV
- where
- toKV (Resolver name f) = (name, f)
-
--- | Contains variables for the query. The key of the map is a variable name,
--- and the value is the variable value.
-type Subs = HashMap Name Value
-
--- | Create a new 'Resolver' with the given 'Name' from the given 'Resolver's.
-object :: Monad m => Name -> ActionT m [Resolver m] -> Resolver m
-object name f = Resolver name $ resolveFieldValue f resolveRight
- where
- resolveRight fld@(Field _ _ _ flds) resolver
- = withField (resolve (resolversToMap resolver) flds) fld
-
--- | Like 'object' but can be null or a list of objects.
-wrappedObject ::
- Monad m =>
- Name ->
- ActionT m (Type.Wrapping [Resolver m]) ->
- Resolver m
-wrappedObject name f = Resolver name $ resolveFieldValue f resolveRight
- where
- resolveRight fld@(Field _ _ _ sels) resolver
- = withField (traverse (resolveMap sels) resolver) fld
- resolveMap = flip (resolve . resolversToMap)
-
--- | A scalar represents a primitive value, like a string or an integer.
-scalar :: (Monad m, Aeson.ToJSON a) => Name -> ActionT m a -> Resolver m
-scalar name f = Resolver name $ resolveFieldValue f resolveRight
- where
- resolveRight fld result = withField (return result) fld
-
--- | Like 'scalar' but can be null or a list of scalars.
-wrappedScalar ::
- (Monad m, Aeson.ToJSON a) =>
- Name ->
- ActionT m (Type.Wrapping a) ->
- Resolver m
-wrappedScalar name f = Resolver name $ resolveFieldValue f resolveRight
- where
- resolveRight fld (Type.Named result) = withField (return result) fld
- resolveRight fld Type.Null
- = return $ HashMap.singleton (aliasOrName fld) Aeson.Null
- resolveRight fld (Type.List result) = withField (return result) fld
-
-resolveFieldValue ::
- Monad m =>
- ActionT m a ->
- (Field -> a -> CollectErrsT m Aeson.Object) ->
- Field ->
- CollectErrsT m (HashMap Text Aeson.Value)
-resolveFieldValue f resolveRight fld@(Field _ _ args _) = do
- result <- lift $ reader . runExceptT . runActionT $ f
- either resolveLeft (resolveRight fld) result
- where
- reader = flip runReaderT $ Context {arguments=args}
- resolveLeft err = do
- _ <- addErrMsg err
- return $ HashMap.singleton (aliasOrName fld) Aeson.Null
-
--- | Helper function to facilitate error handling and result emitting.
-withField :: (Monad m, Aeson.ToJSON a)
- => CollectErrsT m a -> Field -> CollectErrsT m (HashMap Text Aeson.Value)
-withField v fld
- = HashMap.singleton (aliasOrName fld) . Aeson.toJSON <$> runAppendErrs v
-
--- | Takes a list of 'Resolver's and a list of 'Field's and applies each
--- 'Resolver' to each 'Field'. Resolves into a value containing the
--- resolved 'Field', or a null value and error information.
-resolve :: Monad m
- => HashMap Text (Field -> CollectErrsT m Aeson.Object)
- -> Seq Selection
- -> CollectErrsT m Aeson.Value
-resolve resolvers = fmap (Aeson.toJSON . fold) . traverse tryResolvers
- where
- resolveTypeName f = do
- value <- f $ Field Nothing "__typename" mempty mempty
- return $ HashMap.lookupDefault "" "__typename" value
- tryResolvers (SelectionField fld@(Field _ name _ _))
- = fromMaybe (errmsg fld) $ HashMap.lookup name resolvers <*> Just fld
- tryResolvers (SelectionFragment (Fragment typeCondition selections')) = do
- that <- traverse resolveTypeName $ HashMap.lookup "__typename" resolvers
- if maybe True (Aeson.String typeCondition ==) that
- then fmap fold . traverse tryResolvers $ selections'
- else return mempty
- errmsg fld@(Field _ name _ _) = do
- addErrMsg $ T.unwords ["field", name, "not resolved."]
- return $ HashMap.singleton (aliasOrName fld) Aeson.Null
-
-aliasOrName :: Field -> Text
-aliasOrName (Field alias name _ _) = fromMaybe name alias