morpheus-graphql-0.1.0: src/Data/Morpheus/Resolve/Decode.hs
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}
module Data.Morpheus.Resolve.Decode
( ArgumentsConstraint
, decodeArguments
) where
import Data.Morpheus.Error.Internal (internalArgumentError, internalTypeMismatch)
import Data.Morpheus.Kind (ENUM, INPUT_OBJECT, KIND, SCALAR, WRAPPER)
import Data.Morpheus.Resolve.Generics.EnumRep (EnumRep (..))
import Data.Morpheus.Types.GQLScalar (GQLScalar (..), toScalar)
import Data.Morpheus.Types.Internal.AST.Selection (Argument (..), Arguments)
import Data.Morpheus.Types.Internal.Validation (Validation)
import Data.Morpheus.Types.Internal.Value (Value (..))
import Data.Proxy (Proxy (..))
import Data.Text (Text, pack)
import GHC.Generics
type Decode_ a = Value -> Validation a
type ArgumentsConstraint a = (Generic a, GDecode Arguments (Rep a))
decodeArguments :: (Generic p, GDecode Arguments (Rep p)) => Arguments -> Validation p
decodeArguments args = to <$> gDecode "" args
--
-- GENERIC
--
fixProxy :: (a -> f a) -> f a
fixProxy f = f undefined
class GDecode i f where
gDecode :: Text -> i -> Validation (f a)
instance GDecode i U1 where
gDecode _ _ = pure U1
instance (Selector c, GDecode i f) => GDecode i (M1 S c f) where
gDecode _ gql = fixProxy (\x -> M1 <$> gDecode (pack $ selName x) gql)
instance (Datatype c, GDecode i f) => GDecode i (M1 D c f) where
gDecode key gql = fixProxy $ const (M1 <$> gDecode key gql)
instance GDecode i f => GDecode i (M1 C c f) where
gDecode meta gql = M1 <$> gDecode meta gql
instance (GDecode i f, GDecode i g) => GDecode i (f :*: g) where
gDecode meta gql = (:*:) <$> gDecode meta gql <*> gDecode meta gql
instance (Decode a (KIND a)) => GDecode Value (K1 i a) where
gDecode key' (Object object) =
case lookup key' object of
Nothing -> internalArgumentError "Missing Argument"
Just value -> K1 <$> decode value
gDecode _ isType = internalTypeMismatch "InputObject" isType
instance Decode a (KIND a) => GDecode Arguments (K1 i a) where
gDecode key' args =
case lookup key' args of
Nothing -> internalArgumentError "Required Argument Not Found"
Just (Argument x _pos) -> K1 <$> decode x
-- | Decode GraphQL query arguments and input values
decode ::
forall a. Decode a (KIND a)
=> Decode_ a
decode = __decode (Proxy @(KIND a))
-- | Decode GraphQL query arguments and input values
class Decode a b where
__decode :: Proxy b -> Decode_ a
--
-- SCALAR
--
instance (GQLScalar a) => Decode a SCALAR where
__decode _ value =
case toScalar value >>= parseValue of
Right scalar -> return scalar
Left errorMessage -> internalTypeMismatch errorMessage value
--
-- ENUM
--
instance (Generic a, EnumRep (Rep a)) => Decode a ENUM where
__decode _ (Enum value) = pure (to $ gToEnum value)
__decode _ isType = internalTypeMismatch "Enum" isType
--
-- INPUT_OBJECT
--
instance (Generic a, GDecode Value (Rep a)) => Decode a INPUT_OBJECT where
__decode _ (Object x) = to <$> gDecode "" (Object x)
__decode _ isType = internalTypeMismatch "InputObject" isType
--
-- WRAPPERS: Maybe, List
--
instance Decode a (KIND a) => Decode (Maybe a) WRAPPER where
__decode _ Null = pure Nothing
__decode _ x = Just <$> decode x
instance Decode a (KIND a) => Decode [a] WRAPPER where
__decode _ (List li) = mapM decode li
__decode _ isType = internalTypeMismatch "List" isType