{-# language LambdaCase #-}
{-# language NamedFieldPuns #-}
{-# language RecordWildCards #-}
{-# language StandaloneKindSignatures #-}
{-# language StrictData #-}
{-# language DuplicateRecordFields #-}

module Rel8.Type.Encoder (
  Encoder (..),
) where

-- base
import Data.Functor.Contravariant (Contravariant, (>$<), contramap)
import Data.Kind (Type)
import Prelude

-- bytestring
import Data.ByteString.Builder (Builder)

-- hasql
import qualified Hasql.Encoders as Hasql

-- opaleye
import qualified Opaleye.Internal.HaskellDB.PrimQuery as Opaleye


type Encoder :: Type -> Type
data Encoder a = Encoder
  { forall a. Encoder a -> Value a
binary :: Hasql.Value a
    -- ^ How to serialize to PostgreSQL's binary format.
  , forall a. Encoder a -> a -> Builder
text :: a -> Builder
    -- ^ How to serialize to PostgreSQL's text format.
  , forall a. Encoder a -> a -> PrimExpr
quote :: a -> Opaleye.PrimExpr
    -- ^ How to encode a single Haskell value as an SQL expression.
  }


instance Contravariant Encoder where
  contramap :: forall a' a. (a' -> a) -> Encoder a -> Encoder a'
contramap a' -> a
f Encoder {Value a
a -> Builder
a -> PrimExpr
binary :: forall a. Encoder a -> Value a
text :: forall a. Encoder a -> a -> Builder
quote :: forall a. Encoder a -> a -> PrimExpr
binary :: Value a
text :: a -> Builder
quote :: a -> PrimExpr
..} = Encoder
    { binary :: Value a'
binary = a' -> a
f (a' -> a) -> Value a -> Value a'
forall (f :: * -> *) a b. Contravariant f => (a -> b) -> f b -> f a
>$< Value a
binary
    , text :: a' -> Builder
text = a -> Builder
text (a -> Builder) -> (a' -> a) -> a' -> Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a' -> a
f
    , quote :: a' -> PrimExpr
quote = a -> PrimExpr
quote (a -> PrimExpr) -> (a' -> a) -> a' -> PrimExpr
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a' -> a
f
    }