module Hasql.Generate.Column
    ( PgColumn
    ) where

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

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

import           GHC.TypeLits         ( Symbol )

import           Hasql.Generate.Codec ( PgCodec )

import           Prelude              ( Double, Float )

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

{-  Typeclass mapping a schema-qualified PostgreSQL type name to a Haskell type.
    The functional dependency @pgSchema pgName -> a@ ensures each
    (schema, type name) pair resolves to exactly one Haskell type.

    Built-in types use @\"pg_catalog\"@ as their schema. User-defined types
    (e.g. enums created with @fromType@) use their actual schema name.

    The TH code generator uses @reifyInstances@ on this class to discover the
    correct Haskell type for each column at compile time. Users can define
    additional instances for custom PostgreSQL types (e.g. enums).
-}
class (PgCodec a) => PgColumn (pgSchema :: Symbol) (pgName :: Symbol) a | pgSchema pgName -> a

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

instance PgColumn "pg_catalog" "bool" Bool
instance PgColumn "pg_catalog" "int2" Int16
instance PgColumn "pg_catalog" "int4" Int32
instance PgColumn "pg_catalog" "int8" Int64
instance PgColumn "pg_catalog" "float4" Float
instance PgColumn "pg_catalog" "float8" Double
instance PgColumn "pg_catalog" "numeric" Scientific
instance PgColumn "pg_catalog" "char" Char
instance PgColumn "pg_catalog" "text" Text
instance PgColumn "pg_catalog" "varchar" Text
instance PgColumn "pg_catalog" "bpchar" Text
instance PgColumn "pg_catalog" "name" Text
instance PgColumn "pg_catalog" "bytea" ByteString
instance PgColumn "pg_catalog" "date" Day
instance PgColumn "pg_catalog" "timestamp" LocalTime
instance PgColumn "pg_catalog" "timestamptz" UTCTime
instance PgColumn "pg_catalog" "time" TimeOfDay
instance PgColumn "pg_catalog" "timetz" (TimeOfDay, TimeZone)
instance PgColumn "pg_catalog" "interval" DiffTime
instance PgColumn "pg_catalog" "uuid" UUID
instance PgColumn "pg_catalog" "json" Aeson.Value
instance PgColumn "pg_catalog" "jsonb" Aeson.Value