morpheus-graphql-0.3.0: src/Data/Morpheus/Execution/Internal/Decode.hs
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TemplateHaskell #-}
module Data.Morpheus.Execution.Internal.Decode
( withObject
, withMaybe
, withList
, withEnum
, withUnion
, decodeFieldWith
, decodeObjectExpQ
) where
import Data.Semigroup ((<>))
import Data.Text (unpack)
import Language.Haskell.TH (ExpQ, conE, mkName, uInfixE, varE)
-- MORPHEUS
import Data.Morpheus.Error.Internal (internalArgumentError, internalTypeMismatch)
import Data.Morpheus.Types.Internal.Data (DataField (..), Key)
import Data.Morpheus.Types.Internal.DataD (ConsD (..))
import Data.Morpheus.Types.Internal.Validation (Validation)
import Data.Morpheus.Types.Internal.Value (Object, Value (..))
decodeObjectExpQ :: ExpQ -> ConsD -> ExpQ
decodeObjectExpQ fieldDecoder ConsD {cName, cFields} = handleFields cFields
where
consName = conE (mkName cName)
----------------------------------------------------------------------------------
handleFields fNames = uInfixE consName (varE '(<$>)) (applyFields fNames)
where
applyFields [] = fail "No Empty fields"
applyFields [x] = defField x
applyFields (x:xs) = uInfixE (defField x) (varE '(<*>)) (applyFields xs)
------------------------------------------------------------------------
defField DataField {fieldName} = uInfixE (varE (mkName "o")) fieldDecoder [|fName|]
where
fName = unpack fieldName
withObject :: (Object -> Validation a) -> Value -> Validation a
withObject f (Object object) = f object
withObject _ isType = internalTypeMismatch "Object" isType
withMaybe :: Monad m => (Value -> m a) -> Value -> m (Maybe a)
withMaybe _ Null = pure Nothing
withMaybe decode x = Just <$> decode x
withList :: (Value -> Validation a) -> Value -> Validation [a]
withList decode (List li) = mapM decode li
withList _ isType = internalTypeMismatch "List" isType
withEnum :: (Key -> Validation a) -> Value -> Validation a
withEnum decode (Enum value) = decode value
withEnum _ isType = internalTypeMismatch "Enum" isType
withUnion :: (Key -> Object -> Object -> Validation a) -> Object -> Validation a
withUnion decoder unions =
case lookup "tag" unions of
Just (Enum key) ->
case lookup key unions of
Nothing -> internalArgumentError ("type \"" <> key <> "\" was not provided on object")
Just value -> withObject (decoder key unions) value
Just _ -> internalArgumentError "tag must be Enum"
Nothing -> internalArgumentError "tag not found on Input Union"
decodeFieldWith :: (Value -> Validation a) -> Key -> Object -> Validation a
decodeFieldWith decoder name object =
case lookup name object of
Nothing -> internalArgumentError ("Missing Field: \"" <> name <> "\"")
Just value -> decoder value