packages feed

rel8-1.7.0.0: src/Rel8/Type/Decoder.hs

{-# language DerivingStrategies #-}
{-# language DeriveFunctor #-}
{-# language NamedFieldPuns #-}
{-# language StandaloneKindSignatures #-}
{-# language DuplicateRecordFields #-}

module Rel8.Type.Decoder (
  Decoder (..),
  Parser,
  parseDecoder,
) where

-- base
import Control.Monad ((>=>))
import Data.Bifunctor (first)
import Data.Kind (Type)
import Prelude

-- bytestring
import Data.ByteString (ByteString)

-- hasql
import qualified Hasql.Decoders as Hasql

-- text
import qualified Data.Text as Text


type Parser :: Type -> Type
type Parser a = ByteString -> Either String a


type Decoder :: Type -> Type
data Decoder a = Decoder
  { binary :: Hasql.Value a
    -- ^ How to deserialize from PostgreSQL's binary format.
  , text :: Parser a
    -- ^ How to deserialize from PostgreSQL's text format.
  }
  deriving stock (Functor)


-- | Apply a parser to 'Decoder'.
--
-- This can be used if the data stored in the database should only be subset of
-- a given 'Decoder'. The parser is applied when deserializing rows
-- returned.
parseDecoder :: (a -> Either String b) -> Decoder a -> Decoder b
parseDecoder f Decoder {binary, text} =
  Decoder
    { binary = Hasql.refine (first Text.pack . f) binary
    , text = text >=> f
    }