packages feed

valiant-0.1.0.0: src/Valiant/Binary/Enum.hs

-- | Binary encode/decode for PostgreSQL enum types.
--
-- PG sends enum values as text (UTF-8 label) in binary format,
-- identical to the text encoding. This module provides the 'PgEnum'
-- type class for Haskell sum types that map to PG enums.
--
-- @
-- data Mood = Happy | Sad | Angry
--   deriving stock (Show, Eq, Bounded, Enum)
--
-- instance PgEnum Mood where
--   pgEnumToText Happy = "happy"
--   pgEnumToText Sad   = "sad"
--   pgEnumToText Angry = "angry"
--   pgEnumFromText "happy" = Right Happy
--   pgEnumFromText "sad"   = Right Sad
--   pgEnumFromText "angry" = Right Angry
--   pgEnumFromText t       = Left ("unknown mood: " <> T.unpack t)
-- @
module Valiant.Binary.Enum
  ( PgEnum (..)
  , pgEncodeEnum
  , pgDecodeEnum
  ) where

import Data.ByteString (ByteString)
import Data.Text (Text)
import Data.Text.Encoding qualified as TE

-- | Type class for Haskell types that correspond to PostgreSQL enums.
-- PG encodes enums as their text label in both text and binary format.
class PgEnum a where
  pgEnumToText :: a -> Text
  pgEnumFromText :: Text -> Either String a

-- | Encode an enum value to its PG binary representation (UTF-8 label).
pgEncodeEnum :: (PgEnum a) => a -> ByteString
pgEncodeEnum = TE.encodeUtf8 . pgEnumToText
{-# INLINE pgEncodeEnum #-}

-- | Decode a PG binary enum value (UTF-8 label) to a Haskell value.
pgDecodeEnum :: (PgEnum a) => ByteString -> Either String a
pgDecodeEnum = pgEnumFromText . TE.decodeUtf8
{-# INLINE pgDecodeEnum #-}