generated from tpl/purs
85 lines
3.4 KiB
Haskell
85 lines
3.4 KiB
Haskell
module Data.Postgres.Custom.Enum where
|
|
|
|
import Prelude
|
|
|
|
import Control.Alt ((<|>))
|
|
import Control.Monad.Error.Class (liftMaybe)
|
|
import Data.Array.NonEmpty.Internal (NonEmptyArray)
|
|
import Data.Bifunctor (lmap)
|
|
import Data.Foldable (intercalate)
|
|
import Data.Generic.Rep (class Generic)
|
|
import Data.Generic.Rep as G
|
|
import Data.Maybe (Maybe(..), fromMaybe)
|
|
import Data.Newtype as Newtype
|
|
import Data.Postgres (class Rep, RepT, deserialize, serialize)
|
|
import Data.Postgres.Custom (quoted)
|
|
import Data.Postgres.Query (Query, emptyQuery)
|
|
import Data.Postgres.Raw (Raw)
|
|
import Data.Symbol (class IsSymbol)
|
|
import Data.Traversable (find)
|
|
import Data.Tuple (fst, snd)
|
|
import Data.Tuple.Nested (type (/\), (/\))
|
|
import Foreign (ForeignError(..))
|
|
import Type.Prelude (Proxy(..), reflectSymbol)
|
|
|
|
typeName :: forall @a ty. CustomEnum a ty => String
|
|
typeName = reflectSymbol (Proxy @ty)
|
|
|
|
class (IsSymbol ty, Rep a, Eq a) <= CustomEnum a ty | a -> ty where
|
|
enumVariants :: NonEmptyArray (a /\ String)
|
|
parseEnum :: String -> Maybe a
|
|
printEnum :: a -> String
|
|
|
|
defaultParseEnum :: forall a ty. CustomEnum a ty => String -> Maybe a
|
|
defaultParseEnum s = map fst $ find (eq s <<< snd) enumVariants
|
|
|
|
defaultPrintEnum :: forall a ty. CustomEnum a ty => a -> String
|
|
defaultPrintEnum a = fromMaybe "ERROR: CustomEnum enumVariants was not exhaustive" $ map snd $ find (eq a <<< fst) enumVariants
|
|
|
|
defaultDeserializeEnum :: forall @a ty. CustomEnum a ty => Raw -> RepT a
|
|
defaultDeserializeEnum raw = do
|
|
s <- deserialize raw
|
|
let e = pure $ ForeignError $ "unsupported enum variant for " <> typeName @a <> ": " <> quoted s
|
|
liftMaybe e $ parseEnum s
|
|
|
|
defaultSerializeEnum :: forall @a ty. CustomEnum a ty => a -> RepT Raw
|
|
defaultSerializeEnum = serialize <<< printEnum
|
|
|
|
class GenericCustomEnum a where
|
|
genericEnumVariants' :: NonEmptyArray (a /\ String)
|
|
genericParseEnum' :: String -> Maybe a
|
|
genericPrintEnum' :: a -> String
|
|
|
|
instance IsSymbol n => GenericCustomEnum (G.Constructor n G.NoArguments) where
|
|
genericEnumVariants' = pure (G.Constructor @n G.NoArguments /\ reflectSymbol (Proxy @n))
|
|
genericParseEnum' s
|
|
| s == reflectSymbol (Proxy @n) = Just (G.Constructor @n G.NoArguments)
|
|
| otherwise = Nothing
|
|
genericPrintEnum' _ = reflectSymbol (Proxy @n)
|
|
|
|
instance (GenericCustomEnum a, GenericCustomEnum b) => GenericCustomEnum (G.Sum a b) where
|
|
genericEnumVariants' = (lmap G.Inl <$> genericEnumVariants' @a) <> (lmap G.Inr <$> genericEnumVariants' @b)
|
|
genericParseEnum' s = (G.Inl <$> genericParseEnum' @a s) <|> (G.Inr <$> genericParseEnum' @b s)
|
|
genericPrintEnum' (G.Inl a) = genericPrintEnum' a
|
|
genericPrintEnum' (G.Inr a) = genericPrintEnum' a
|
|
|
|
enumPrintExpr :: forall @a ty. CustomEnum a ty => a -> Maybe String
|
|
enumPrintExpr = Just <<< (\s -> quoted s <> " :: " <> typeName @a) <<< printEnum
|
|
|
|
genericEnumVariants :: forall a g. Generic a g => GenericCustomEnum g => NonEmptyArray (a /\ String)
|
|
genericEnumVariants = lmap G.to <$> genericEnumVariants'
|
|
|
|
genericParseEnum :: forall a g. Generic a g => GenericCustomEnum g => String -> Maybe a
|
|
genericParseEnum = map G.to <<< genericParseEnum'
|
|
|
|
genericPrintEnum :: forall a g. Generic a g => GenericCustomEnum g => a -> String
|
|
genericPrintEnum = genericPrintEnum' <<< G.from
|
|
|
|
create :: forall @a ty. CustomEnum a ty => Query
|
|
create =
|
|
let
|
|
variants = intercalate ", " $ quoted <$> snd <$> enumVariants @a
|
|
q = "create type " <> typeName @a <> " as enum (" <> variants <> ");"
|
|
in
|
|
Newtype.modify (_ { text = q }) emptyQuery
|