summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Language/GraphQL/AST/Core.hs21
-rw-r--r--src/Language/GraphQL/Execute/Coerce.hs63
-rw-r--r--src/Language/GraphQL/Execute/Transform.hs45
-rw-r--r--src/Language/GraphQL/Schema.hs87
-rw-r--r--src/Language/GraphQL/Trans.hs7
-rw-r--r--src/Language/GraphQL/Type.hs63
-rw-r--r--src/Language/GraphQL/Type/Definition.hs20
-rw-r--r--src/Language/GraphQL/Type/Directive.hs5
-rw-r--r--src/Language/GraphQL/Type/In.hs26
-rw-r--r--src/Language/GraphQL/Type/Out.hs58
10 files changed, 191 insertions, 204 deletions
diff --git a/src/Language/GraphQL/AST/Core.hs b/src/Language/GraphQL/AST/Core.hs
index d719912..6dcfb81 100644
--- a/src/Language/GraphQL/AST/Core.hs
+++ b/src/Language/GraphQL/AST/Core.hs
@@ -9,15 +9,13 @@ module Language.GraphQL.AST.Core
, Operation(..)
, Selection(..)
, TypeCondition
- , Value(..)
) where
-import Data.Int (Int32)
import Data.HashMap.Strict (HashMap)
import Data.Sequence (Seq)
-import Data.String (IsString(..))
import Data.Text (Text)
import Language.GraphQL.AST (Alias, Name, TypeCondition)
+import qualified Language.GraphQL.Type.In as In
-- | GraphQL has 3 operation types: queries, mutations and subscribtions.
--
@@ -33,7 +31,7 @@ data Field
deriving (Eq, Show)
-- | Argument list.
-newtype Arguments = Arguments (HashMap Name Value)
+newtype Arguments = Arguments (HashMap Name In.Value)
deriving (Eq, Show)
instance Semigroup Arguments where
@@ -56,18 +54,3 @@ data Selection
= SelectionFragment Fragment
| SelectionField Field
deriving (Eq, Show)
-
--- | Represents accordingly typed GraphQL values.
-data Value
- = Int Int32
- | Float Double -- ^ GraphQL Float is double precision
- | String Text
- | Boolean Bool
- | Null
- | Enum Name
- | List [Value]
- | Object (HashMap Name Value)
- deriving (Eq, Show)
-
-instance IsString Value where
- fromString = String . fromString
diff --git a/src/Language/GraphQL/Execute/Coerce.hs b/src/Language/GraphQL/Execute/Coerce.hs
index 6997945..32c48fd 100644
--- a/src/Language/GraphQL/Execute/Coerce.hs
+++ b/src/Language/GraphQL/Execute/Coerce.hs
@@ -15,7 +15,8 @@ import qualified Data.Text.Lazy as Text.Lazy
import qualified Data.Text.Lazy.Builder as Text.Builder
import qualified Data.Text.Lazy.Builder.Int as Text.Builder
import Data.Scientific (toBoundedInteger, toRealFloat)
-import Language.GraphQL.AST.Core
+import Language.GraphQL.AST.Document (Name)
+import qualified Language.GraphQL.Type.In as In
import Language.GraphQL.Schema
import Language.GraphQL.Type.Definition
@@ -46,26 +47,26 @@ class VariableValue a where
coerceVariableValue
:: InputType -- ^ Expected type (variable type given in the query).
-> a -- ^ Variable value being coerced.
- -> Maybe Value -- ^ Coerced value on success, 'Nothing' otherwise.
+ -> Maybe In.Value -- ^ Coerced value on success, 'Nothing' otherwise.
instance VariableValue Aeson.Value where
- coerceVariableValue _ Aeson.Null = Just Null
+ coerceVariableValue _ Aeson.Null = Just In.Null
coerceVariableValue (ScalarInputTypeDefinition scalarType) value
- | (Aeson.String stringValue) <- value = Just $ String stringValue
- | (Aeson.Bool booleanValue) <- value = Just $ Boolean booleanValue
+ | (Aeson.String stringValue) <- value = Just $ In.String stringValue
+ | (Aeson.Bool booleanValue) <- value = Just $ In.Boolean booleanValue
| (Aeson.Number numberValue) <- value
, (ScalarType "Float" _) <- scalarType =
- Just $ Float $ toRealFloat numberValue
+ Just $ In.Float $ toRealFloat numberValue
| (Aeson.Number numberValue) <- value = -- ID or Int
- Int <$> toBoundedInteger numberValue
+ In.Int <$> toBoundedInteger numberValue
coerceVariableValue (EnumInputTypeDefinition _) (Aeson.String stringValue) =
- Just $ Enum stringValue
+ Just $ In.Enum stringValue
coerceVariableValue (ObjectInputTypeDefinition objectType) value
| (Aeson.Object objectValue) <- value = do
let (InputObjectType _ _ inputFields) = objectType
(newObjectValue, resultMap) <- foldWithKey objectValue inputFields
if HashMap.null newObjectValue
- then Just $ Object resultMap
+ then Just $ In.Object resultMap
else Nothing
where
foldWithKey objectValue = HashMap.foldrWithKey matchFieldValues
@@ -81,7 +82,7 @@ instance VariableValue Aeson.Value where
pure (newObjectValue, insert coerced)
Nothing -> Just (objectValue, resultMap)
coerceVariableValue (ListInputTypeDefinition listType) value
- | (Aeson.Array arrayValue) <- value = List
+ | (Aeson.Array arrayValue) <- value = In.List
<$> foldr foldVector (Just []) arrayValue
| otherwise = coerceVariableValue listType value
where
@@ -95,7 +96,7 @@ instance VariableValue Aeson.Value where
-- corresponding types.
coerceInputLiterals
:: HashMap Name InputType
- -> HashMap Name Value
+ -> HashMap Name In.Value
-> Maybe Subs
coerceInputLiterals variableTypes variableValues =
foldWithKey operator variableTypes
@@ -105,34 +106,34 @@ coerceInputLiterals variableTypes variableValues =
<$> (lookupVariable variableName >>= coerceInputLiteral variableType)
<*> resultMap
coerceInputLiteral (ScalarInputType type') value
- | (String stringValue) <- value
- , (ScalarType "String" _) <- type' = Just $ String stringValue
- | (Boolean booleanValue) <- value
- , (ScalarType "Boolean" _) <- type' = Just $ Boolean booleanValue
- | (Int intValue) <- value
- , (ScalarType "Int" _) <- type' = Just $ Int intValue
- | (Float floatValue) <- value
- , (ScalarType "Float" _) <- type' = Just $ Float floatValue
- | (Int intValue) <- value
+ | (In.String stringValue) <- value
+ , (ScalarType "String" _) <- type' = Just $ In.String stringValue
+ | (In.Boolean booleanValue) <- value
+ , (ScalarType "Boolean" _) <- type' = Just $ In.Boolean booleanValue
+ | (In.Int intValue) <- value
+ , (ScalarType "Int" _) <- type' = Just $ In.Int intValue
+ | (In.Float floatValue) <- value
+ , (ScalarType "Float" _) <- type' = Just $ In.Float floatValue
+ | (In.Int intValue) <- value
, (ScalarType "Float" _) <- type' =
- Just $ Float $ fromIntegral intValue
- | (String stringValue) <- value
- , (ScalarType "ID" _) <- type' = Just $ String stringValue
- | (Int intValue) <- value
+ Just $ In.Float $ fromIntegral intValue
+ | (In.String stringValue) <- value
+ , (ScalarType "ID" _) <- type' = Just $ In.String stringValue
+ | (In.Int intValue) <- value
, (ScalarType "ID" _) <- type' = Just $ decimal intValue
- coerceInputLiteral (EnumInputType type') (Enum enumValue)
- | member enumValue type' = Just $ Enum enumValue
- coerceInputLiteral (ObjectInputType type') (Object _) =
+ coerceInputLiteral (EnumInputType type') (In.Enum enumValue)
+ | member enumValue type' = Just $ In.Enum enumValue
+ coerceInputLiteral (ObjectInputType type') (In.Object _) =
let (InputObjectType _ _ inputFields) = type'
- in Object <$> foldWithKey matchFieldValues inputFields
+ in In.Object <$> foldWithKey matchFieldValues inputFields
coerceInputLiteral _ _ = Nothing
member value (EnumType _ _ members) = Set.member value members
matchFieldValues fieldName (InputField _ type' defaultValue) resultMap =
case lookupVariable fieldName of
- Just Null
+ Just In.Null
| isNonNullInputType type' -> Nothing
| otherwise ->
- HashMap.insert fieldName Null <$> resultMap
+ HashMap.insert fieldName In.Null <$> resultMap
Just variableValue -> HashMap.insert fieldName
<$> coerceInputLiteral type' variableValue
<*> resultMap
@@ -144,7 +145,7 @@ coerceInputLiterals variableTypes variableValues =
| otherwise -> resultMap
lookupVariable = flip HashMap.lookup variableValues
foldWithKey f = HashMap.foldrWithKey f (Just HashMap.empty)
- decimal = String
+ decimal = In.String
. Text.Lazy.toStrict
. Text.Builder.toLazyText
. Text.Builder.decimal
diff --git a/src/Language/GraphQL/Execute/Transform.hs b/src/Language/GraphQL/Execute/Transform.hs
index df64254..9768675 100644
--- a/src/Language/GraphQL/Execute/Transform.hs
+++ b/src/Language/GraphQL/Execute/Transform.hs
@@ -32,6 +32,7 @@ import Language.GraphQL.Execute.Coerce
import qualified Language.GraphQL.Schema as Schema
import qualified Language.GraphQL.Type.Definition as Definition
import qualified Language.GraphQL.Type.Directive as Directive
+import qualified Language.GraphQL.Type.In as In
import Language.GraphQL.Type.Schema
-- | Associates a fragment name with a list of 'Core.Field's.
@@ -136,23 +137,23 @@ coerceVariableValues schema operationDefinition variableValues' =
<*> coercedValues
choose Nothing defaultValue variableType
| Just _ <- defaultValue = defaultValue
- | not (isNonNullInputType variableType) = Just Core.Null
+ | not (isNonNullInputType variableType) = Just In.Null
choose (Just value') _ variableType
| Just coercedValue <- coerceVariableValue variableType value'
- , not (isNonNullInputType variableType) || coercedValue /= Core.Null =
+ , not (isNonNullInputType variableType) || coercedValue /= In.Null =
Just coercedValue
choose _ _ _ = Nothing
-constValue :: Full.ConstValue -> Core.Value
-constValue (Full.ConstInt i) = Core.Int i
-constValue (Full.ConstFloat f) = Core.Float f
-constValue (Full.ConstString x) = Core.String x
-constValue (Full.ConstBoolean b) = Core.Boolean b
-constValue Full.ConstNull = Core.Null
-constValue (Full.ConstEnum e) = Core.Enum e
-constValue (Full.ConstList l) = Core.List $ constValue <$> l
+constValue :: Full.ConstValue -> In.Value
+constValue (Full.ConstInt i) = In.Int i
+constValue (Full.ConstFloat f) = In.Float f
+constValue (Full.ConstString x) = In.String x
+constValue (Full.ConstBoolean b) = In.Boolean b
+constValue Full.ConstNull = In.Null
+constValue (Full.ConstEnum e) = In.Enum e
+constValue (Full.ConstList l) = In.List $ constValue <$> l
constValue (Full.ConstObject o) =
- Core.Object $ HashMap.fromList $ constObjectField <$> o
+ In.Object $ HashMap.fromList $ constObjectField <$> o
where
constObjectField (Full.ObjectField key value') = (key, constValue value')
@@ -294,19 +295,19 @@ arguments = fmap Core.Arguments . foldM go HashMap.empty
substitutedValue <- value value'
return $ HashMap.insert name substitutedValue arguments'
-value :: Full.Value -> TransformT Core.Value
+value :: Full.Value -> TransformT In.Value
value (Full.Variable name) =
- gets $ fromMaybe Core.Null . HashMap.lookup name . variableValues
-value (Full.Int i) = pure $ Core.Int i
-value (Full.Float f) = pure $ Core.Float f
-value (Full.String x) = pure $ Core.String x
-value (Full.Boolean b) = pure $ Core.Boolean b
-value Full.Null = pure Core.Null
-value (Full.Enum e) = pure $ Core.Enum e
+ gets $ fromMaybe In.Null . HashMap.lookup name . variableValues
+value (Full.Int i) = pure $ In.Int i
+value (Full.Float f) = pure $ In.Float f
+value (Full.String x) = pure $ In.String x
+value (Full.Boolean b) = pure $ In.Boolean b
+value Full.Null = pure In.Null
+value (Full.Enum e) = pure $ In.Enum e
value (Full.List l) =
- Core.List <$> traverse value l
+ In.List <$> traverse value l
value (Full.Object o) =
- Core.Object . HashMap.fromList <$> traverse objectField o
+ In.Object . HashMap.fromList <$> traverse objectField o
-objectField :: Full.ObjectField Full.Value -> TransformT (Core.Name, Core.Value)
+objectField :: Full.ObjectField Full.Value -> TransformT (Core.Name, In.Value)
objectField (Full.ObjectField name value') = (name,) <$> value value'
diff --git a/src/Language/GraphQL/Schema.hs b/src/Language/GraphQL/Schema.hs
index 69f697e..34abf10 100644
--- a/src/Language/GraphQL/Schema.hs
+++ b/src/Language/GraphQL/Schema.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE ExplicitForAll #-}
{-# LANGUAGE OverloadedStrings #-}
-- | This module provides a representation of a @GraphQL@ Schema in addition to
@@ -8,10 +9,6 @@ module Language.GraphQL.Schema
, object
, resolve
, resolversToMap
- , wrappedObject
- -- * AST Reexports
- , Field
- , Value(..)
) where
import Control.Monad.Trans.Class (lift)
@@ -28,38 +25,35 @@ import qualified Data.Text as T
import Language.GraphQL.AST.Core
import Language.GraphQL.Error
import Language.GraphQL.Trans
-import qualified Language.GraphQL.Type.Definition as Definition
-import qualified Language.GraphQL.Type as Type
+import qualified Language.GraphQL.Type.In as In
+import qualified Language.GraphQL.Type.Out as Out
-- | 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 Name (Definition.FieldResolver m)
+-- information (if an error has occurred). @m@ is an arbitrary monad, usually
+-- 'IO'.
+--
+-- Resolving a field can result in a leaf value or an object, which is
+-- represented as a list of nested resolvers, used to resolve the fields of that
+-- object.
+data Resolver m = Resolver Name (ActionT m (Out.Value m))
-- | Converts resolvers to a map.
resolversToMap :: (Foldable f, Functor f)
- => f (Resolver m)
- -> HashMap Text (Definition.FieldResolver m)
+ => forall m
+ . f (Resolver m)
+ -> HashMap Text (ActionT m (Out.Value m))
resolversToMap = HashMap.fromList . toList . fmap toKV
where
toKV (Resolver name r) = (name, r)
-- | 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
+type Subs = HashMap Name In.Value
--- | Like 'object' but can be null or a list of objects.
-wrappedObject :: Monad m
- => Name
- -> ActionT m (Type.Wrapping (Definition.FieldResolver m))
- -> Resolver m
-wrappedObject name = Resolver name . Definition.NestingResolver
-
--- | Create a new 'Resolver' with the given 'Name' from the given 'Resolver's.
-object :: Monad m
- => [Resolver m]
- -> Type.Wrapping (Definition.FieldResolver m)
-object = Type.O . resolversToMap
+-- | Create a new 'Resolver' with the given 'Name' from the given
+-- Resolver's.
+object :: Monad m => [Resolver m] -> Out.Value m
+object = Out.Object . resolversToMap
resolveFieldValue :: Monad m => Field -> ActionT m a -> m (Either Text a)
resolveFieldValue field@(Field _ _ args _) =
@@ -69,26 +63,25 @@ resolveFieldValue field@(Field _ _ args _) =
withField :: Monad m
=> Field
- -> Definition.FieldResolver m
+ -> ActionT m (Out.Value m)
-> CollectErrsT m Aeson.Object
-withField field (Definition.ValueResolver resolver) = do
- answer <- lift $ resolveFieldValue field resolver
- either (errmsg field) (pure . HashMap.singleton (aliasOrName field)) answer
-withField field (Definition.NestingResolver resolver) = do
+withField field resolver = do
answer <- lift $ resolveFieldValue field resolver
case answer of
- Right result -> HashMap.singleton (aliasOrName field) <$> toJSON field result
+ Right result -> HashMap.singleton (aliasOrName field)
+ <$> toJSON field result
Left errorMessage -> errmsg field errorMessage
-toJSON :: Monad m => Field -> Type.Wrapping (Definition.FieldResolver m) -> CollectErrsT m Aeson.Value
-toJSON _ Type.Null = pure Aeson.Null
-toJSON _ (Type.I i) = pure $ Aeson.toJSON i
-toJSON _ (Type.B i) = pure $ Aeson.toJSON i
-toJSON _ (Type.F i) = pure $ Aeson.toJSON i
-toJSON _ (Type.E i) = pure $ Aeson.toJSON i
-toJSON _ (Type.S i) = pure $ Aeson.toJSON i
-toJSON field (Type.List list) = Aeson.toJSON <$> traverse (toJSON field) list
-toJSON (Field _ _ _ seqSelection) (Type.O map') = map' `resolve` seqSelection
+toJSON :: Monad m => Field -> Out.Value m -> CollectErrsT m Aeson.Value
+toJSON _ Out.Null = pure Aeson.Null
+toJSON _ (Out.Int integer) = pure $ Aeson.toJSON integer
+toJSON _ (Out.Boolean boolean) = pure $ Aeson.Bool boolean
+toJSON _ (Out.Float float) = pure $ Aeson.toJSON float
+toJSON _ (Out.Enum enum) = pure $ Aeson.String enum
+toJSON _ (Out.String string) = pure $ Aeson.String string
+toJSON field (Out.List list) = Aeson.toJSON <$> traverse (toJSON field) list
+toJSON (Field _ _ _ seqSelection) (Out.Object map') =
+ map' `resolve` seqSelection
errmsg :: Monad m => Field -> Text -> CollectErrsT m (HashMap Text Aeson.Value)
errmsg field errorMessage = do
@@ -96,10 +89,10 @@ errmsg field errorMessage = do
pure $ HashMap.singleton (aliasOrName field) Aeson.Null
-- | 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.
+-- 'Resolver' to each 'Field'. Resolves into a value containing the
+-- resolved 'Field', or a null value and error information.
resolve :: Monad m
- => HashMap Text (Definition.FieldResolver m)
+ => HashMap Text (ActionT m (Out.Value m))
-> Seq Selection
-> CollectErrsT m Aeson.Value
resolve resolvers = fmap (Aeson.toJSON . fold) . traverse tryResolvers
@@ -109,17 +102,11 @@ resolve resolvers = fmap (Aeson.toJSON . fold) . traverse tryResolvers
| (Just resolver) <- lookupResolver name = withField fld resolver
| otherwise = errmsg fld $ T.unwords ["field", name, "not resolved."]
tryResolvers (SelectionFragment (Fragment typeCondition selections'))
- | Just (Definition.ValueResolver resolver) <- lookupResolver "__typename" = do
- let fakeField = Field Nothing "__typename" mempty mempty
- that <- lift $ resolveFieldValue fakeField resolver
- if Right (Aeson.String typeCondition) == that
- then fmap fold . traverse tryResolvers $ selections'
- else pure mempty
- | Just (Definition.NestingResolver resolver) <- lookupResolver "__typename" = do
+ | Just resolver <- lookupResolver "__typename" = do
let fakeField = Field Nothing "__typename" mempty mempty
that <- lift $ resolveFieldValue fakeField resolver
case that of
- Right (Type.S typeCondition')
+ Right (Out.String typeCondition')
| typeCondition' == typeCondition ->
fmap fold . traverse tryResolvers $ selections'
_ -> pure mempty
diff --git a/src/Language/GraphQL/Trans.hs b/src/Language/GraphQL/Trans.hs
index f09a8a0..3c3ffa4 100644
--- a/src/Language/GraphQL/Trans.hs
+++ b/src/Language/GraphQL/Trans.hs
@@ -15,6 +15,7 @@ import qualified Data.HashMap.Strict as HashMap
import Data.Maybe (fromMaybe)
import Data.Text (Text)
import Language.GraphQL.AST.Core
+import qualified Language.GraphQL.Type.In as In
import Prelude hiding (lookup)
-- | Resolution context holds resolver arguments.
@@ -55,11 +56,11 @@ instance Monad m => MonadPlus (ActionT m) where
mplus = (<|>)
-- | Retrieves an argument by its name. If the argument with this name couldn't
--- be found, returns 'Value.Null' (i.e. the argument is assumed to
+-- be found, returns 'In.Null' (i.e. the argument is assumed to
-- be optional then).
-argument :: Monad m => Name -> ActionT m Value
+argument :: Monad m => Name -> ActionT m In.Value
argument argumentName = do
argumentValue <- ActionT $ lift $ asks $ lookup . arguments
- pure $ fromMaybe Null argumentValue
+ pure $ fromMaybe In.Null argumentValue
where
lookup (Arguments argumentMap) = HashMap.lookup argumentName argumentMap
diff --git a/src/Language/GraphQL/Type.hs b/src/Language/GraphQL/Type.hs
deleted file mode 100644
index 12b38dc..0000000
--- a/src/Language/GraphQL/Type.hs
+++ /dev/null
@@ -1,63 +0,0 @@
--- | Definitions for @GraphQL@ input types.
-module Language.GraphQL.Type
- ( Wrapping(..)
- ) where
-
-import Data.HashMap.Strict (HashMap)
-import Data.Text (Text)
-import Language.GraphQL.AST.Document (Name)
-
--- | GraphQL distinguishes between "wrapping" and "named" types. Each wrapping
--- type can wrap other wrapping or named types. Wrapping types are lists and
--- Non-Null types (named types are nullable by default).
---
--- This 'Wrapping' type doesn\'t reflect this distinction exactly but it is
--- used in the resolvers to take into account that the returned value can be
--- nullable or an (arbitrary nested) list.
-data Wrapping a
- = List [Wrapping a] -- ^ Arbitrary nested list
--- | Named a -- ^ Named type without further wrapping
- | Null -- ^ Null
- | O (HashMap Name a)
- | I Int
- | B Bool
- | F Float
- | E Text
- | S Text
- deriving (Eq, Show)
-
-instance Functor Wrapping where
- fmap f (List list) = List $ fmap (fmap f) list
- fmap f (O map') = O $ f <$> map'
- fmap _ Null = Null
- fmap _ (I i) = I i
- fmap _ (B i) = B i
- fmap _ (F i) = F i
- fmap _ (E i) = E i
- fmap _ (S i) = S i
-
- {-instance Foldable Wrapping where
- foldr f acc (List list) = foldr (flip $ foldr f) acc list
- foldr f acc (O map') = foldr f acc map'
- foldr _ acc _ = acc -}
-
- {-instance Traversable Wrapping where
- traverse f (List list) = List <$> traverse (traverse f) list
- traverse f (Named named) = Named <$> f named
- traverse _ Null = pure Null
- traverse f (O map') = O <$> traverse f map'-}
-
-{-instance Applicative Wrapping where
- pure = Named
- Null <*> _ = Null
- _ <*> Null = Null
- (Named f) <*> (Named x) = Named $ f x
- (List fs) <*> (List xs) = List $ (<*>) <$> fs <*> xs
- (Named f) <*> list = f <$> list
- (List fs) <*> named = List $ (<*> named) <$> fs
-
-instance Monad Wrapping where
- return = pure
- Null >>= _ = Null
- (Named x) >>= f = f x
- (List xs) >>= f = List $ fmap (>>= f) xs-}
diff --git a/src/Language/GraphQL/Type/Definition.hs b/src/Language/GraphQL/Type/Definition.hs
index 559611b..54eac85 100644
--- a/src/Language/GraphQL/Type/Definition.hs
+++ b/src/Language/GraphQL/Type/Definition.hs
@@ -8,7 +8,6 @@ module Language.GraphQL.Type.Definition
( Argument(..)
, EnumType(..)
, Field(..)
- , FieldResolver(..)
, InputField(..)
, InputObjectType(..)
, InputType(..)
@@ -31,13 +30,13 @@ module Language.GraphQL.Type.Definition
, string
) where
-import qualified Data.Aeson as Aeson
import Data.HashMap.Strict (HashMap)
import Data.Set (Set)
import Data.Text (Text)
-import Language.GraphQL.AST.Core (Name, Value)
+import Language.GraphQL.AST.Document (Name)
import Language.GraphQL.Trans
-import qualified Language.GraphQL.Type as Type
+import qualified Language.GraphQL.Type.In as In
+import qualified Language.GraphQL.Type.Out as Out
import Prelude hiding (id)
-- | Object type definition.
@@ -51,17 +50,10 @@ data Field m = Field
(Maybe Text) -- ^ Description.
(OutputType m) -- ^ Field type.
(HashMap Name Argument) -- ^ Arguments.
- (FieldResolver m) -- ^ Resolver.
-
--- | Resolving a field can result in a leaf value or an object, which is
--- represented as a list of nested resolvers, used to resolve the fields of that
--- object.
-data FieldResolver m
- = ValueResolver (ActionT m Aeson.Value)
- | NestingResolver (ActionT m (Type.Wrapping (FieldResolver m)))
+ (ActionT m (Out.Value m)) -- ^ Resolver.
-- | Field argument definition.
-data Argument = Argument (Maybe Text) InputType (Maybe Value)
+data Argument = Argument (Maybe Text) InputType (Maybe In.Value)
-- | Scalar type definition.
--
@@ -77,7 +69,7 @@ data ScalarType = ScalarType Name (Maybe Text)
data EnumType = EnumType Name (Maybe Text) (Set Text)
-- | Single field of an 'InputObjectType'.
-data InputField = InputField (Maybe Text) InputType (Maybe Value)
+data InputField = InputField (Maybe Text) InputType (Maybe In.Value)
-- | Input object type definition.
--
diff --git a/src/Language/GraphQL/Type/Directive.hs b/src/Language/GraphQL/Type/Directive.hs
index afd97da..9675df8 100644
--- a/src/Language/GraphQL/Type/Directive.hs
+++ b/src/Language/GraphQL/Type/Directive.hs
@@ -6,6 +6,7 @@ module Language.GraphQL.Type.Directive
import qualified Data.HashMap.Strict as HashMap
import Language.GraphQL.AST.Core
+import qualified Language.GraphQL.Type.In as In
-- | Directive processing status.
data Status
@@ -36,7 +37,7 @@ skip = handle skip'
where
skip' directive'@(Directive "skip" (Arguments arguments)) =
case HashMap.lookup "if" arguments of
- (Just (Boolean True)) -> Skip
+ (Just (In.Boolean True)) -> Skip
_ -> Include directive'
skip' directive' = Continue directive'
@@ -45,6 +46,6 @@ include = handle include'
where
include' directive'@(Directive "include" (Arguments arguments)) =
case HashMap.lookup "if" arguments of
- (Just (Boolean True)) -> Include directive'
+ (Just (In.Boolean True)) -> Include directive'
_ -> Skip
include' directive' = Continue directive'
diff --git a/src/Language/GraphQL/Type/In.hs b/src/Language/GraphQL/Type/In.hs
new file mode 100644
index 0000000..a6d35e2
--- /dev/null
+++ b/src/Language/GraphQL/Type/In.hs
@@ -0,0 +1,26 @@
+-- | This module is intended to be imported qualified, to avoid name clashes
+-- with 'Language.GraphQL.Type.Out'.
+module Language.GraphQL.Type.In
+ ( Value(..)
+ ) where
+
+import Data.HashMap.Strict (HashMap)
+import Data.Int (Int32)
+import Data.String (IsString(..))
+import Data.Text (Text)
+import Language.GraphQL.AST.Document (Name)
+
+-- | Represents accordingly typed GraphQL values.
+data Value
+ = Int Int32
+ | Float Double -- ^ GraphQL Float is double precision
+ | String Text
+ | Boolean Bool
+ | Null
+ | Enum Name
+ | List [Value]
+ | Object (HashMap Name Value)
+ deriving (Eq, Show)
+
+instance IsString Value where
+ fromString = String . fromString
diff --git a/src/Language/GraphQL/Type/Out.hs b/src/Language/GraphQL/Type/Out.hs
new file mode 100644
index 0000000..96bc9cf
--- /dev/null
+++ b/src/Language/GraphQL/Type/Out.hs
@@ -0,0 +1,58 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+-- | This module is intended to be imported qualified, to avoid name clashes
+-- with 'Language.GraphQL.Type.In'.
+module Language.GraphQL.Type.Out
+ ( Value(..)
+ ) where
+
+import Data.HashMap.Strict (HashMap)
+import qualified Data.HashMap.Strict as HashMap
+import Data.Int (Int32)
+import Data.String (IsString(..))
+import Data.Text (Text)
+import qualified Data.Text as Text
+import Language.GraphQL.AST.Document (Name)
+import Language.GraphQL.Trans
+
+-- | GraphQL distinguishes between "wrapping" and "named" types. Each wrapping
+-- type can wrap other wrapping or named types. Wrapping types are lists and
+-- Non-Null types (named types are nullable by default).
+--
+-- This 'Value' type doesn\'t reflect this distinction exactly but it is used
+-- in the resolvers to take into account that the returned value can be nullable
+-- or an (arbitrary nested) list.
+data Value m
+ = Int Int32
+ | Float Double
+ | String Text
+ | Boolean Bool
+ | Null
+ | Enum Name
+ | List [Value m] -- ^ Arbitrary nested list.
+ | Object (HashMap Name (ActionT m (Value m)))
+
+instance IsString (Value m) where
+ fromString = String . fromString
+
+instance Show (Value m) where
+ show (Int integer) = "Int " ++ show integer
+ show (Float float) = "Float " ++ show float
+ show (String text) = Text.unpack $ "String " <> text
+ show (Boolean True) = "Boolean True"
+ show (Boolean False) = "Boolean False"
+ show Null = "Null"
+ show (Enum enum) = Text.unpack $ "Enum " <> enum
+ show (List list) = show list
+ show (Object object) = Text.unpack
+ $ "Object [" <> Text.intercalate ", " (HashMap.keys object) <> "]"
+
+instance Eq (Value m) where
+ (Int this) == (Int that) = this == that
+ (Float this) == (Float that) = this == that
+ (String this) == (String that) = this == that
+ (Boolean this) == (Boolean that) = this == that
+ (Enum this) == (Enum that) = this == that
+ (List this) == (List that) = this == that
+ (Object this) == (Object that) = HashMap.keys this == HashMap.keys that
+ _ == _ = False