{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeOperators #-}
module Data.Morpheus.Execution.Server.Generics.EnumRep
( EnumRep(..)
) where
import Data.Proxy (Proxy (..))
import Data.Semigroup ((<>))
import Data.Text (Text, pack)
import GHC.Generics
import Data.Morpheus.Error.Internal (internalError)
import Data.Morpheus.Types.Internal.Validation (Validation)
class EnumRep f where
encodeRep :: f a -> Text
decodeEnum :: Text -> Validation (f a)
enumTags :: Proxy f -> [Text]
instance (Datatype c, EnumRep f) => EnumRep (M1 D c f) where
encodeRep (M1 src) = encodeRep src
decodeEnum = fmap M1 . decodeEnum
enumTags _ = enumTags (Proxy @f)
instance (Constructor c) => EnumRep (M1 C c U1) where
encodeRep m@(M1 _) = pack $ conName m
decodeEnum _ = pure $ M1 U1
enumTags _ = [pack $ conName (undefined :: (M1 C c U1 x))]
instance (EnumRep a, EnumRep b) => EnumRep (a :+: b) where
encodeRep (L1 x) = encodeRep x
encodeRep (R1 x) = encodeRep x
decodeEnum name
| name `elem` enumTags (Proxy @a) = L1 <$> decodeEnum name
| name `elem` enumTags (Proxy @b) = R1 <$> decodeEnum name
| otherwise =
internalError ("Constructor \"" <> name <> "\" could not find in Union")
enumTags _ = enumTags (Proxy @a) ++ enumTags (Proxy @b)