module Hasql.Generate.Codec
    ( PgCodec (..)
    ) where

----------------------------------------------------------------------------------------------------

import qualified Data.Aeson                 as Aeson
import           Data.Bool                  ( Bool )
import           Data.ByteString            ( ByteString )
import           Data.Char                  ( Char )
import           Data.Functor               ( fmap )
import qualified Data.Functor.Contravariant as Contravariant
import           Data.Int                   ( Int16, Int32, Int64 )
import           Data.Scientific            ( Scientific )
import           Data.String                ( String )
import           Data.Text                  ( Text )
import qualified Data.Text
import           Data.Time
    ( Day
    , DiffTime
    , LocalTime
    , TimeOfDay
    , TimeZone
    , UTCTime
    )
import           Data.UUID                  ( UUID )

import qualified Hasql.Decoders             as Decoders
import qualified Hasql.Encoders             as Encoders

import           Prelude                    ( Double, Float )

----------------------------------------------------------------------------------------------------

{-  Typeclass mapping a Haskell type to its hasql binary-protocol encoder and
    decoder. Each instance pairs a type with the corresponding hasql 'Value'
    encoder and decoder, enabling the TH code generator to resolve codecs by
    type inference alone.
-}
class PgCodec a where
  pgDecode :: Decoders.Value a
  pgEncode :: Encoders.Value a

----------------------------------------------------------------------------------------------------

instance PgCodec Bool where
  pgDecode :: Decoders.Value Bool
  pgDecode :: Value Bool
pgDecode = Value Bool
Decoders.bool
  pgEncode :: Encoders.Value Bool
  pgEncode :: Value Bool
pgEncode = Value Bool
Encoders.bool

instance PgCodec Int16 where
  pgDecode :: Decoders.Value Int16
  pgDecode :: Value Int16
pgDecode = Value Int16
Decoders.int2
  pgEncode :: Encoders.Value Int16
  pgEncode :: Value Int16
pgEncode = Value Int16
Encoders.int2

instance PgCodec Int32 where
  pgDecode :: Decoders.Value Int32
  pgDecode :: Value Int32
pgDecode = Value Int32
Decoders.int4
  pgEncode :: Encoders.Value Int32
  pgEncode :: Value Int32
pgEncode = Value Int32
Encoders.int4

instance PgCodec Int64 where
  pgDecode :: Decoders.Value Int64
  pgDecode :: Value Int64
pgDecode = Value Int64
Decoders.int8
  pgEncode :: Encoders.Value Int64
  pgEncode :: Value Int64
pgEncode = Value Int64
Encoders.int8

instance PgCodec Float where
  pgDecode :: Decoders.Value Float
  pgDecode :: Value Float
pgDecode = Value Float
Decoders.float4
  pgEncode :: Encoders.Value Float
  pgEncode :: Value Float
pgEncode = Value Float
Encoders.float4

instance PgCodec Double where
  pgDecode :: Decoders.Value Double
  pgDecode :: Value Double
pgDecode = Value Double
Decoders.float8
  pgEncode :: Encoders.Value Double
  pgEncode :: Value Double
pgEncode = Value Double
Encoders.float8

instance PgCodec Scientific where
  pgDecode :: Decoders.Value Scientific
  pgDecode :: Value Scientific
pgDecode = Value Scientific
Decoders.numeric
  pgEncode :: Encoders.Value Scientific
  pgEncode :: Value Scientific
pgEncode = Value Scientific
Encoders.numeric

instance PgCodec Char where
  pgDecode :: Decoders.Value Char
  pgDecode :: Value Char
pgDecode = Value Char
Decoders.char
  pgEncode :: Encoders.Value Char
  pgEncode :: Value Char
pgEncode = Value Char
Encoders.char

instance PgCodec Text where
  pgDecode :: Decoders.Value Text
  pgDecode :: Value Text
pgDecode = Value Text
Decoders.text
  pgEncode :: Encoders.Value Text
  pgEncode :: Value Text
pgEncode = Value Text
Encoders.text

instance PgCodec String where
  pgDecode :: Decoders.Value String
  pgDecode :: Value String
pgDecode = (Text -> String) -> Value Text -> Value String
forall a b. (a -> b) -> Value a -> Value b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Text -> String
Data.Text.unpack Value Text
Decoders.text
  pgEncode :: Encoders.Value String
  pgEncode :: Value String
pgEncode = (String -> Text) -> Value Text -> Value String
forall a' a. (a' -> a) -> Value a -> Value a'
forall (f :: * -> *) a' a.
Contravariant f =>
(a' -> a) -> f a -> f a'
Contravariant.contramap String -> Text
Data.Text.pack Value Text
Encoders.text

instance PgCodec ByteString where
  pgDecode :: Decoders.Value ByteString
  pgDecode :: Value ByteString
pgDecode = Value ByteString
Decoders.bytea
  pgEncode :: Encoders.Value ByteString
  pgEncode :: Value ByteString
pgEncode = Value ByteString
Encoders.bytea

instance PgCodec Day where
  pgDecode :: Decoders.Value Day
  pgDecode :: Value Day
pgDecode = Value Day
Decoders.date
  pgEncode :: Encoders.Value Day
  pgEncode :: Value Day
pgEncode = Value Day
Encoders.date

instance PgCodec LocalTime where
  pgDecode :: Decoders.Value LocalTime
  pgDecode :: Value LocalTime
pgDecode = Value LocalTime
Decoders.timestamp
  pgEncode :: Encoders.Value LocalTime
  pgEncode :: Value LocalTime
pgEncode = Value LocalTime
Encoders.timestamp

instance PgCodec UTCTime where
  pgDecode :: Decoders.Value UTCTime
  pgDecode :: Value UTCTime
pgDecode = Value UTCTime
Decoders.timestamptz
  pgEncode :: Encoders.Value UTCTime
  pgEncode :: Value UTCTime
pgEncode = Value UTCTime
Encoders.timestamptz

instance PgCodec TimeOfDay where
  pgDecode :: Decoders.Value TimeOfDay
  pgDecode :: Value TimeOfDay
pgDecode = Value TimeOfDay
Decoders.time
  pgEncode :: Encoders.Value TimeOfDay
  pgEncode :: Value TimeOfDay
pgEncode = Value TimeOfDay
Encoders.time

instance PgCodec (TimeOfDay, TimeZone) where
  pgDecode :: Decoders.Value (TimeOfDay, TimeZone)
  pgDecode :: Value (TimeOfDay, TimeZone)
pgDecode = Value (TimeOfDay, TimeZone)
Decoders.timetz
  pgEncode :: Encoders.Value (TimeOfDay, TimeZone)
  pgEncode :: Value (TimeOfDay, TimeZone)
pgEncode = Value (TimeOfDay, TimeZone)
Encoders.timetz

instance PgCodec DiffTime where
  pgDecode :: Decoders.Value DiffTime
  pgDecode :: Value DiffTime
pgDecode = Value DiffTime
Decoders.interval
  pgEncode :: Encoders.Value DiffTime
  pgEncode :: Value DiffTime
pgEncode = Value DiffTime
Encoders.interval

instance PgCodec UUID where
  pgDecode :: Decoders.Value UUID
  pgDecode :: Value UUID
pgDecode = Value UUID
Decoders.uuid
  pgEncode :: Encoders.Value UUID
  pgEncode :: Value UUID
pgEncode = Value UUID
Encoders.uuid

instance PgCodec Aeson.Value where
  pgDecode :: Decoders.Value Aeson.Value
  pgDecode :: Value Value
pgDecode = Value Value
Decoders.jsonb
  pgEncode :: Encoders.Value Aeson.Value
  pgEncode :: Value Value
pgEncode = Value Value
Encoders.jsonb