{-# LANGUAGE EmptyDataDecls #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeSynonymInstances #-}

module Opaleye.Internal.PGTypesExternal
  (module Opaleye.Internal.PGTypesExternal, IsSqlType(..)) where

import           Opaleye.Internal.Column (Column)
import qualified Opaleye.Internal.Column as C
import qualified Opaleye.Internal.PGTypes as IPT
import           Opaleye.Internal.PGTypes (IsSqlType(..))

import qualified Opaleye.Internal.HaskellDB.PrimQuery as HPQ
import qualified Opaleye.Internal.HaskellDB.Sql.Default as HSD

import qualified Data.CaseInsensitive as CI
import qualified Data.Aeson as Ae
import qualified Data.Text as SText
import qualified Data.Text.Lazy as LText
import qualified Data.ByteString as SByteString
import qualified Data.ByteString.Lazy as LByteString
import           Data.Scientific as Sci
import qualified Data.Time as Time
import qualified Data.UUID as UUID

import           Data.Int (Int64)

import qualified Database.PostgreSQL.Simple.Range as R

instance C.SqlNum SqlFloat8 where
  sqlFromInteger :: Integer -> Column SqlFloat8
sqlFromInteger = Double -> Column SqlFloat8
pgDouble (Double -> Column SqlFloat8)
-> (Integer -> Double) -> Integer -> Column SqlFloat8
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Integer -> Double
forall a. Num a => Integer -> a
fromInteger

instance C.SqlNum SqlInt4 where
  sqlFromInteger :: Integer -> Column SqlInt4
sqlFromInteger = Int -> Column SqlInt4
pgInt4 (Int -> Column SqlInt4)
-> (Integer -> Int) -> Integer -> Column SqlInt4
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Integer -> Int
forall a. Num a => Integer -> a
fromInteger

instance C.SqlNum SqlInt8 where
  sqlFromInteger :: Integer -> Column SqlInt8
sqlFromInteger = Int64 -> Column SqlInt8
pgInt8 (Int64 -> Column SqlInt8)
-> (Integer -> Int64) -> Integer -> Column SqlInt8
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Integer -> Int64
forall a. Num a => Integer -> a
fromInteger

instance C.SqlNum SqlNumeric where
  sqlFromInteger :: Integer -> Column SqlNumeric
sqlFromInteger = Scientific -> Column SqlNumeric
pgNumeric (Scientific -> Column SqlNumeric)
-> (Integer -> Scientific) -> Integer -> Column SqlNumeric
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Integer -> Scientific
forall a. Num a => Integer -> a
fromInteger

instance C.SqlFractional SqlFloat8 where
  sqlFromRational :: Rational -> Column SqlFloat8
sqlFromRational = Double -> Column SqlFloat8
pgDouble (Double -> Column SqlFloat8)
-> (Rational -> Double) -> Rational -> Column SqlFloat8
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Rational -> Double
forall a. Fractional a => Rational -> a
fromRational

instance C.SqlIntegral SqlInt2
instance C.SqlIntegral SqlNumeric
instance C.SqlIntegral SqlInt4
instance C.SqlIntegral SqlInt8

instance C.SqlString SqlText where
  sqlFromString :: String -> Column SqlText
sqlFromString = String -> Column SqlText
pgString

instance C.SqlString SqlCitext where
  sqlFromString :: String -> Column SqlCitext
sqlFromString = CI Text -> Column SqlCitext
pgCiLazyText (CI Text -> Column SqlCitext)
-> (String -> CI Text) -> String -> Column SqlCitext
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> CI Text
forall s. FoldCase s => s -> CI s
CI.mk (Text -> CI Text) -> (String -> Text) -> String -> CI Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Text
LText.pack

-- * Creating SQL values

pgString :: String -> Column PGText
pgString :: String -> Column SqlText
pgString = Literal -> Column SqlText
forall a. IsSqlType a => Literal -> Column a
IPT.literalColumn (Literal -> Column SqlText)
-> (String -> Literal) -> String -> Column SqlText
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Literal
HPQ.StringLit

pgLazyByteString :: LByteString.ByteString -> Column PGBytea
pgLazyByteString :: ByteString -> Column PGBytea
pgLazyByteString = Literal -> Column PGBytea
forall a. IsSqlType a => Literal -> Column a
IPT.literalColumn (Literal -> Column PGBytea)
-> (ByteString -> Literal) -> ByteString -> Column PGBytea
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Literal
HPQ.ByteStringLit (ByteString -> Literal)
-> (ByteString -> ByteString) -> ByteString -> Literal
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> ByteString
LByteString.toStrict

pgStrictByteString :: SByteString.ByteString -> Column PGBytea
pgStrictByteString :: ByteString -> Column PGBytea
pgStrictByteString = Literal -> Column PGBytea
forall a. IsSqlType a => Literal -> Column a
IPT.literalColumn (Literal -> Column PGBytea)
-> (ByteString -> Literal) -> ByteString -> Column PGBytea
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Literal
HPQ.ByteStringLit

pgStrictText :: SText.Text -> Column PGText
pgStrictText :: Text -> Column SqlText
pgStrictText = Literal -> Column SqlText
forall a. IsSqlType a => Literal -> Column a
IPT.literalColumn (Literal -> Column SqlText)
-> (Text -> Literal) -> Text -> Column SqlText
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Literal
HPQ.StringLit (String -> Literal) -> (Text -> String) -> Text -> Literal
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> String
SText.unpack

pgLazyText :: LText.Text -> Column PGText
pgLazyText :: Text -> Column SqlText
pgLazyText = Literal -> Column SqlText
forall a. IsSqlType a => Literal -> Column a
IPT.literalColumn (Literal -> Column SqlText)
-> (Text -> Literal) -> Text -> Column SqlText
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Literal
HPQ.StringLit (String -> Literal) -> (Text -> String) -> Text -> Literal
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> String
LText.unpack

pgNumeric :: Sci.Scientific -> Column PGNumeric
pgNumeric :: Scientific -> Column SqlNumeric
pgNumeric = Literal -> Column SqlNumeric
forall a. IsSqlType a => Literal -> Column a
IPT.literalColumn (Literal -> Column SqlNumeric)
-> (Scientific -> Literal) -> Scientific -> Column SqlNumeric
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Scientific -> Literal
HPQ.NumericLit

pgInt4 :: Int -> Column PGInt4
pgInt4 :: Int -> Column SqlInt4
pgInt4 = Literal -> Column SqlInt4
forall a. IsSqlType a => Literal -> Column a
IPT.literalColumn (Literal -> Column SqlInt4)
-> (Int -> Literal) -> Int -> Column SqlInt4
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Integer -> Literal
HPQ.IntegerLit (Integer -> Literal) -> (Int -> Integer) -> Int -> Literal
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> Integer
forall a b. (Integral a, Num b) => a -> b
fromIntegral

pgInt8 :: Int64 -> Column PGInt8
pgInt8 :: Int64 -> Column SqlInt8
pgInt8 = Literal -> Column SqlInt8
forall a. IsSqlType a => Literal -> Column a
IPT.literalColumn (Literal -> Column SqlInt8)
-> (Int64 -> Literal) -> Int64 -> Column SqlInt8
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Integer -> Literal
HPQ.IntegerLit (Integer -> Literal) -> (Int64 -> Integer) -> Int64 -> Literal
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int64 -> Integer
forall a b. (Integral a, Num b) => a -> b
fromIntegral

pgDouble :: Double -> Column PGFloat8
pgDouble :: Double -> Column SqlFloat8
pgDouble = Literal -> Column SqlFloat8
forall a. IsSqlType a => Literal -> Column a
IPT.literalColumn (Literal -> Column SqlFloat8)
-> (Double -> Literal) -> Double -> Column SqlFloat8
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Double -> Literal
HPQ.DoubleLit

pgBool :: Bool -> Column PGBool
pgBool :: Bool -> Column PGBool
pgBool = Literal -> Column PGBool
forall a. IsSqlType a => Literal -> Column a
IPT.literalColumn (Literal -> Column PGBool)
-> (Bool -> Literal) -> Bool -> Column PGBool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Bool -> Literal
HPQ.BoolLit

pgUUID :: UUID.UUID -> Column PGUuid
pgUUID :: UUID -> Column PGUuid
pgUUID = Literal -> Column PGUuid
forall a. IsSqlType a => Literal -> Column a
IPT.literalColumn (Literal -> Column PGUuid)
-> (UUID -> Literal) -> UUID -> Column PGUuid
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Literal
HPQ.StringLit (String -> Literal) -> (UUID -> String) -> UUID -> Literal
forall b c a. (b -> c) -> (a -> b) -> a -> c
. UUID -> String
UUID.toString

pgDay :: Time.Day -> Column PGDate
pgDay :: Day -> Column PGDate
pgDay = String -> String -> Day -> Column PGDate
forall t c. FormatTime t => String -> String -> t -> Column c
IPT.unsafePgFormatTime String
"date" String
"'%F'"

pgUTCTime :: Time.UTCTime -> Column PGTimestamptz
pgUTCTime :: UTCTime -> Column PGTimestamptz
pgUTCTime = String -> String -> UTCTime -> Column PGTimestamptz
forall t c. FormatTime t => String -> String -> t -> Column c
IPT.unsafePgFormatTime String
"timestamptz" String
"'%FT%T%QZ'"

pgLocalTime :: Time.LocalTime -> Column PGTimestamp
pgLocalTime :: LocalTime -> Column PGTimestamp
pgLocalTime = String -> String -> LocalTime -> Column PGTimestamp
forall t c. FormatTime t => String -> String -> t -> Column c
IPT.unsafePgFormatTime String
"timestamp" String
"'%FT%T%Q'"

pgZonedTime :: Time.ZonedTime -> Column PGTimestamptz
pgZonedTime :: ZonedTime -> Column PGTimestamptz
pgZonedTime = String -> String -> ZonedTime -> Column PGTimestamptz
forall t c. FormatTime t => String -> String -> t -> Column c
IPT.unsafePgFormatTime String
"timestamptz" String
"'%FT%T%Q%z'"

pgTimeOfDay :: Time.TimeOfDay -> Column PGTime
pgTimeOfDay :: TimeOfDay -> Column PGTime
pgTimeOfDay = String -> String -> TimeOfDay -> Column PGTime
forall t c. FormatTime t => String -> String -> t -> Column c
IPT.unsafePgFormatTime String
"time" String
"'%T%Q'"

-- "We recommend not using the type time with time zone"
-- http://www.postgresql.org/docs/8.3/static/datatype-datetime.html


pgCiStrictText :: CI.CI SText.Text -> Column PGCitext
pgCiStrictText :: CI Text -> Column SqlCitext
pgCiStrictText = Literal -> Column SqlCitext
forall a. IsSqlType a => Literal -> Column a
IPT.literalColumn (Literal -> Column SqlCitext)
-> (CI Text -> Literal) -> CI Text -> Column SqlCitext
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Literal
HPQ.StringLit (String -> Literal) -> (CI Text -> String) -> CI Text -> Literal
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> String
SText.unpack (Text -> String) -> (CI Text -> Text) -> CI Text -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CI Text -> Text
forall s. CI s -> s
CI.original

pgCiLazyText :: CI.CI LText.Text -> Column PGCitext
pgCiLazyText :: CI Text -> Column SqlCitext
pgCiLazyText = Literal -> Column SqlCitext
forall a. IsSqlType a => Literal -> Column a
IPT.literalColumn (Literal -> Column SqlCitext)
-> (CI Text -> Literal) -> CI Text -> Column SqlCitext
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Literal
HPQ.StringLit (String -> Literal) -> (CI Text -> String) -> CI Text -> Literal
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> String
LText.unpack (Text -> String) -> (CI Text -> Text) -> CI Text -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CI Text -> Text
forall s. CI s -> s
CI.original

-- No CI String instance since postgresql-simple doesn't define
-- FromField (CI String)

-- The json data type was introduced in PostgreSQL version 9.2
-- JSON values must be SQL string quoted
pgJSON :: String -> Column PGJson
pgJSON :: String -> Column PGJson
pgJSON = String -> String -> Column PGJson
forall c. String -> String -> Column c
IPT.castToType String
"json" (String -> Column PGJson)
-> (String -> String) -> String -> Column PGJson
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> String
HSD.quote

pgStrictJSON :: SByteString.ByteString -> Column PGJson
pgStrictJSON :: ByteString -> Column PGJson
pgStrictJSON = String -> Column PGJson
pgJSON (String -> Column PGJson)
-> (ByteString -> String) -> ByteString -> Column PGJson
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> String
IPT.strictDecodeUtf8

pgLazyJSON :: LByteString.ByteString -> Column PGJson
pgLazyJSON :: ByteString -> Column PGJson
pgLazyJSON = String -> Column PGJson
pgJSON (String -> Column PGJson)
-> (ByteString -> String) -> ByteString -> Column PGJson
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> String
IPT.lazyDecodeUtf8

pgValueJSON :: Ae.ToJSON a => a -> Column PGJson
pgValueJSON :: a -> Column PGJson
pgValueJSON = ByteString -> Column PGJson
pgLazyJSON (ByteString -> Column PGJson)
-> (a -> ByteString) -> a -> Column PGJson
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> ByteString
forall a. ToJSON a => a -> ByteString
Ae.encode

-- The jsonb data type was introduced in PostgreSQL version 9.4
-- JSONB values must be SQL string quoted
--
-- TODO: We need to add literal JSON and JSONB types so we can say
-- `castToTypeTyped JSONB` rather than `castToType "jsonb"`.
pgJSONB :: String -> Column PGJsonb
pgJSONB :: String -> Column PGJsonb
pgJSONB = String -> String -> Column PGJsonb
forall c. String -> String -> Column c
IPT.castToType String
"jsonb" (String -> Column PGJsonb)
-> (String -> String) -> String -> Column PGJsonb
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> String
HSD.quote

pgStrictJSONB :: SByteString.ByteString -> Column PGJsonb
pgStrictJSONB :: ByteString -> Column PGJsonb
pgStrictJSONB = String -> Column PGJsonb
pgJSONB (String -> Column PGJsonb)
-> (ByteString -> String) -> ByteString -> Column PGJsonb
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> String
IPT.strictDecodeUtf8

pgLazyJSONB :: LByteString.ByteString -> Column PGJsonb
pgLazyJSONB :: ByteString -> Column PGJsonb
pgLazyJSONB = String -> Column PGJsonb
pgJSONB (String -> Column PGJsonb)
-> (ByteString -> String) -> ByteString -> Column PGJsonb
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> String
IPT.lazyDecodeUtf8

pgValueJSONB :: Ae.ToJSON a => a -> Column PGJsonb
pgValueJSONB :: a -> Column PGJsonb
pgValueJSONB = ByteString -> Column PGJsonb
pgLazyJSONB (ByteString -> Column PGJsonb)
-> (a -> ByteString) -> a -> Column PGJsonb
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> ByteString
forall a. ToJSON a => a -> ByteString
Ae.encode

pgArray :: forall a b. IsSqlType b
        => (a -> C.Column b) -> [a] -> C.Column (PGArray b)
pgArray :: (a -> Column b) -> [a] -> Column (PGArray b)
pgArray a -> Column b
pgEl [a]
xs = String -> Column Any -> Column (PGArray b)
forall a b. String -> Column a -> Column b
C.unsafeCast String
arrayTy (Column Any -> Column (PGArray b))
-> Column Any -> Column (PGArray b)
forall a b. (a -> b) -> a -> b
$
  PrimExpr -> Column Any
forall pgType. PrimExpr -> Column pgType
C.Column ([PrimExpr] -> PrimExpr
HPQ.ArrayExpr ((a -> PrimExpr) -> [a] -> [PrimExpr]
forall a b. (a -> b) -> [a] -> [b]
map a -> PrimExpr
oneEl [a]
xs))
  where
    oneEl :: a -> PrimExpr
oneEl = Column b -> PrimExpr
forall a. Column a -> PrimExpr
C.unColumn (Column b -> PrimExpr) -> (a -> Column b) -> a -> PrimExpr
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> Column b
pgEl
    arrayTy :: String
arrayTy = [PGArray b] -> String
forall sqlType (proxy :: * -> *).
IsSqlType sqlType =>
proxy sqlType -> String
showSqlType ([] :: [PGArray b])

pgRange :: forall a b. IsRangeType b
        => (a -> C.Column b) -> R.RangeBound a -> R.RangeBound a
        -> C.Column (PGRange b)
pgRange :: (a -> Column b)
-> RangeBound a -> RangeBound a -> Column (PGRange b)
pgRange a -> Column b
pgEl RangeBound a
start RangeBound a
end =
  PrimExpr -> Column (PGRange b)
forall pgType. PrimExpr -> Column pgType
C.Column (String -> BoundExpr -> BoundExpr -> PrimExpr
HPQ.RangeExpr ([b] -> String
forall pgType (proxy :: * -> *).
IsRangeType pgType =>
proxy pgType -> String
showRangeType ([] :: [b])) (RangeBound a -> BoundExpr
oneEl RangeBound a
start) (RangeBound a -> BoundExpr
oneEl RangeBound a
end))
  where oneEl :: RangeBound a -> BoundExpr
oneEl (R.Inclusive a
a) = PrimExpr -> BoundExpr
HPQ.Inclusive (PrimExpr -> BoundExpr)
-> (Column b -> PrimExpr) -> Column b -> BoundExpr
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Column b -> PrimExpr
forall a. Column a -> PrimExpr
C.unColumn (Column b -> BoundExpr) -> Column b -> BoundExpr
forall a b. (a -> b) -> a -> b
$ a -> Column b
pgEl a
a
        oneEl (R.Exclusive a
a) = PrimExpr -> BoundExpr
HPQ.Exclusive (PrimExpr -> BoundExpr)
-> (Column b -> PrimExpr) -> Column b -> BoundExpr
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Column b -> PrimExpr
forall a. Column a -> PrimExpr
C.unColumn (Column b -> BoundExpr) -> Column b -> BoundExpr
forall a b. (a -> b) -> a -> b
$ a -> Column b
pgEl a
a
        oneEl RangeBound a
R.NegInfinity   = BoundExpr
HPQ.NegInfinity
        oneEl RangeBound a
R.PosInfinity   = BoundExpr
HPQ.PosInfinity

instance IsSqlType SqlBool where
  showSqlType :: proxy PGBool -> String
showSqlType proxy PGBool
_ = String
"boolean"
instance IsSqlType SqlDate where
  showSqlType :: proxy PGDate -> String
showSqlType proxy PGDate
_ = String
"date"
instance IsSqlType SqlFloat4 where
  showSqlType :: proxy SqlFloat4 -> String
showSqlType proxy SqlFloat4
_ = String
"real"
instance IsSqlType SqlFloat8 where
  showSqlType :: proxy SqlFloat8 -> String
showSqlType proxy SqlFloat8
_ = String
"double precision"
instance IsSqlType SqlInt8 where
  showSqlType :: proxy SqlInt8 -> String
showSqlType proxy SqlInt8
_ = String
"bigint"
instance IsSqlType SqlInt4 where
  showSqlType :: proxy SqlInt4 -> String
showSqlType proxy SqlInt4
_ = String
"integer"
instance IsSqlType SqlInt2 where
  showSqlType :: proxy SqlInt2 -> String
showSqlType proxy SqlInt2
_ = String
"smallint"
instance IsSqlType SqlNumeric where
  showSqlType :: proxy SqlNumeric -> String
showSqlType proxy SqlNumeric
_ = String
"numeric"
instance IsSqlType SqlText where
  showSqlType :: proxy SqlText -> String
showSqlType proxy SqlText
_ = String
"text"
instance IsSqlType SqlTime where
  showSqlType :: proxy PGTime -> String
showSqlType proxy PGTime
_ = String
"time"
instance IsSqlType SqlTimestamp where
  showSqlType :: proxy PGTimestamp -> String
showSqlType proxy PGTimestamp
_ = String
"timestamp"
instance IsSqlType SqlTimestamptz where
  showSqlType :: proxy PGTimestamptz -> String
showSqlType proxy PGTimestamptz
_ = String
"timestamp with time zone"
instance IsSqlType SqlUuid where
  showSqlType :: proxy PGUuid -> String
showSqlType proxy PGUuid
_ = String
"uuid"
instance IsSqlType SqlCitext where
  showSqlType :: proxy SqlCitext -> String
showSqlType proxy SqlCitext
_ =  String
"citext"
instance IsSqlType SqlBytea where
  showSqlType :: proxy PGBytea -> String
showSqlType proxy PGBytea
_ = String
"bytea"
instance IsSqlType a => IsSqlType (SqlArray a) where
  showSqlType :: proxy (SqlArray a) -> String
showSqlType proxy (SqlArray a)
_ = [a] -> String
forall sqlType (proxy :: * -> *).
IsSqlType sqlType =>
proxy sqlType -> String
showSqlType ([] :: [a]) String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"[]"
instance IsSqlType SqlJson where
  showSqlType :: proxy PGJson -> String
showSqlType proxy PGJson
_ = String
"json"
instance IsSqlType SqlJsonb where
  showSqlType :: proxy PGJsonb -> String
showSqlType proxy PGJsonb
_ = String
"jsonb"
instance IsRangeType a => IsSqlType (SqlRange a) where
  showSqlType :: proxy (SqlRange a) -> String
showSqlType proxy (SqlRange a)
_ = [a] -> String
forall pgType (proxy :: * -> *).
IsRangeType pgType =>
proxy pgType -> String
showRangeType ([] :: [a])

class IsSqlType pgType => IsRangeType pgType where
  showRangeType :: proxy pgType -> String

instance IsRangeType SqlInt4 where
  showRangeType :: proxy SqlInt4 -> String
showRangeType proxy SqlInt4
_ = String
"int4range"

instance IsRangeType SqlInt8 where
  showRangeType :: proxy SqlInt8 -> String
showRangeType proxy SqlInt8
_ = String
"int8range"

instance IsRangeType SqlNumeric where
  showRangeType :: proxy SqlNumeric -> String
showRangeType proxy SqlNumeric
_ = String
"numrange"

instance IsRangeType SqlTimestamp where
  showRangeType :: proxy PGTimestamp -> String
showRangeType proxy PGTimestamp
_ = String
"tsrange"

instance IsRangeType SqlTimestamptz where
  showRangeType :: proxy PGTimestamptz -> String
showRangeType proxy PGTimestamptz
_ = String
"tstzrange"

instance IsRangeType SqlDate where
  showRangeType :: proxy PGDate -> String
showRangeType proxy PGDate
_ = String
"daterange"

-- * SQL datatypes

data SqlBool
data SqlDate
data SqlFloat4
data SqlFloat8
data SqlInt8
data SqlInt4
data SqlInt2
data SqlNumeric
data SqlText
data SqlTime
data SqlTimestamp
-- | Be careful if you use Haskell's `Time.ZonedTime` with
-- @SqlTimestamptz@. A Postgres @timestamptz@ does not actually
-- contain any time zone.  It is just a UTC time that is automatically
-- converted to or from local time on certain occasions, according to
-- the [timezone setting of the
-- server](https://www.postgresql.org/docs/9.1/runtime-config-client.html#GUC-TIMEZONE).
-- Therefore, although when you roundtrip an input 'Time.ZonedTime' to
-- obtain an output 'Time.ZonedTime' they each refer to the same
-- instant in time, the time zone attached to the output will not
-- necessarily the same as the time zone attached to the input.
data SqlTimestamptz
data SqlUuid
data SqlCitext
data SqlArray a
data SqlBytea
data SqlJson
data SqlJsonb
data SqlRange a

type PGBool = SqlBool
type PGDate = SqlDate
type PGFloat4 = SqlFloat4
type PGFloat8 = SqlFloat8
type PGInt8 = SqlInt8
type PGInt4 = SqlInt4
type PGInt2 = SqlInt2
type PGNumeric = SqlNumeric
type PGText = SqlText
type PGTime = SqlTime
type PGTimestamp = SqlTimestamp
type PGTimestamptz = SqlTimestamptz
type PGUuid = SqlUuid
type PGCitext = SqlCitext
type PGArray = SqlArray
type PGBytea = SqlBytea
type PGJson = SqlJson
type PGJsonb = SqlJsonb
type PGRange = SqlRange