2016-02-11 14:24:31 +01:00
|
|
|
{-# LANGUAGE CPP #-}
|
2016-02-17 18:13:10 +01:00
|
|
|
module Data.GraphQL.Schema
|
|
|
|
( Schema(..)
|
|
|
|
, QueryRoot
|
|
|
|
, ResolverO
|
|
|
|
, ResolverM
|
|
|
|
, Output(..)
|
|
|
|
, Subs
|
|
|
|
, Scalar(..)
|
|
|
|
, withField
|
|
|
|
, withFieldFinal
|
|
|
|
, withFields
|
|
|
|
, withArgument
|
|
|
|
, outputTraverse
|
|
|
|
, fields
|
|
|
|
-- * Reexports
|
|
|
|
, Field
|
|
|
|
, Argument
|
|
|
|
) where
|
2015-10-17 13:19:00 +02:00
|
|
|
|
2016-02-11 14:24:31 +01:00
|
|
|
#if !MIN_VERSION_base(4,8,0)
|
2016-02-17 18:13:10 +01:00
|
|
|
import Data.Traversable (traverse)
|
2016-02-11 14:24:31 +01:00
|
|
|
#endif
|
2016-02-17 18:13:10 +01:00
|
|
|
import Control.Applicative
|
|
|
|
import Data.Maybe (catMaybes)
|
|
|
|
import Data.Foldable (fold)
|
2016-02-15 14:25:15 +01:00
|
|
|
import Data.String (IsString(fromString))
|
2015-10-17 13:19:00 +02:00
|
|
|
|
2016-01-26 12:43:18 +01:00
|
|
|
import Data.Aeson (ToJSON(toJSON))
|
2016-02-11 14:24:31 +01:00
|
|
|
import Data.HashMap.Strict (HashMap)
|
2016-02-17 18:13:10 +01:00
|
|
|
import qualified Data.HashMap.Strict as HashMap
|
2016-02-15 14:25:15 +01:00
|
|
|
import Data.Text (Text, pack)
|
2016-02-17 18:13:10 +01:00
|
|
|
import qualified Data.Text as T (null)
|
|
|
|
|
|
|
|
import Data.GraphQL.AST
|
2015-10-17 13:19:00 +02:00
|
|
|
|
2016-02-17 13:13:01 +01:00
|
|
|
data Schema f = Schema (QueryRoot f)
|
2016-01-26 13:38:02 +01:00
|
|
|
|
2016-02-17 18:13:10 +01:00
|
|
|
type QueryRoot f = ResolverM f
|
2015-10-17 13:19:00 +02:00
|
|
|
|
2016-02-17 18:13:10 +01:00
|
|
|
-- TODO: Come up with a unique data type or better renaming
|
|
|
|
type ResolverM f = Field -> f (HashMap Text Output)
|
|
|
|
type ResolverO f = [Field] -> f Output
|
2015-10-17 13:19:00 +02:00
|
|
|
|
2016-02-11 14:24:31 +01:00
|
|
|
data Output = OutputObject (HashMap Text Output)
|
|
|
|
| OutputList [Output]
|
|
|
|
| OutputScalar Scalar
|
|
|
|
| OutputEnum Text
|
|
|
|
deriving (Show)
|
2015-10-17 13:19:00 +02:00
|
|
|
|
2016-02-17 18:13:10 +01:00
|
|
|
type Subs = Text -> Maybe Text
|
2016-01-26 12:43:18 +01:00
|
|
|
|
2016-02-17 13:13:01 +01:00
|
|
|
-- TODO: GraphQL spec for Integer Scalar is 32bits
|
2016-01-26 12:43:18 +01:00
|
|
|
data Scalar = ScalarInt Int
|
|
|
|
| ScalarFloat Double
|
|
|
|
| ScalarString Text
|
|
|
|
| ScalarBoolean Bool
|
|
|
|
| ScalarID Text
|
|
|
|
deriving (Show)
|
|
|
|
|
2016-02-15 14:25:15 +01:00
|
|
|
instance IsString Scalar where
|
2016-02-17 13:13:01 +01:00
|
|
|
fromString = ScalarString . pack
|
2016-02-15 14:25:15 +01:00
|
|
|
|
2016-01-26 12:43:18 +01:00
|
|
|
instance ToJSON Scalar where
|
|
|
|
toJSON (ScalarInt x) = toJSON x
|
|
|
|
toJSON (ScalarFloat x) = toJSON x
|
|
|
|
toJSON (ScalarString x) = toJSON x
|
|
|
|
toJSON (ScalarBoolean x) = toJSON x
|
|
|
|
toJSON (ScalarID x) = toJSON x
|
2016-02-11 14:24:31 +01:00
|
|
|
|
|
|
|
instance ToJSON Output where
|
|
|
|
toJSON (OutputObject x) = toJSON $ toJSON <$> x
|
|
|
|
toJSON (OutputList x) = toJSON $ toJSON <$> x
|
|
|
|
toJSON (OutputScalar x) = toJSON x
|
|
|
|
toJSON (OutputEnum x) = toJSON x
|
|
|
|
|
2016-02-17 18:13:10 +01:00
|
|
|
-- * Helpers
|
|
|
|
|
|
|
|
withField :: Alternative f => Text -> ([Argument] -> ResolverO f) -> ResolverM f
|
|
|
|
withField n f (Field alias name' args _ sels) =
|
|
|
|
if n == name'
|
|
|
|
then HashMap.singleton aliasOrName <$> f args (fields sels)
|
|
|
|
else empty
|
|
|
|
where
|
|
|
|
aliasOrName = if T.null alias then name' else alias
|
|
|
|
|
|
|
|
withFieldFinal :: Alternative f => Text -> Output -> ResolverM f
|
|
|
|
withFieldFinal n o fld@(Field _ _ [] _ []) = withField n (\_ _ -> pure o) fld
|
|
|
|
withFieldFinal _ _ _ = empty
|
|
|
|
|
|
|
|
withFields :: Alternative f => ResolverM f -> ResolverO f
|
|
|
|
withFields f = fmap (OutputObject . fold) . traverse f
|
|
|
|
|
|
|
|
outputTraverse :: Applicative f => (a -> f Output) -> [a] -> f Output
|
|
|
|
outputTraverse f = fmap OutputList . traverse f
|
|
|
|
|
|
|
|
withArgument :: Text -> [Argument] -> Maybe Scalar
|
|
|
|
withArgument x [Argument n s] = if x == n then scalarValue s else Nothing
|
|
|
|
withArgument _ _ = Nothing
|
|
|
|
|
|
|
|
scalarValue :: Value -> Maybe Scalar
|
|
|
|
scalarValue (ValueInt x) = Just . ScalarInt $ fromIntegral x
|
|
|
|
scalarValue (ValueString (StringValue x)) = Just $ ScalarString x
|
|
|
|
scalarValue _ = Nothing
|
|
|
|
|
|
|
|
fields :: SelectionSet -> [Field]
|
|
|
|
fields = catMaybes . fmap field
|
|
|
|
|
|
|
|
field :: Selection -> Maybe Field
|
|
|
|
field (SelectionField x) = Just x
|
|
|
|
field _ = Nothing
|