{-# LANGUAGE EmptyDataDecls #-}

module Opaleye.SQLite.PGTypes (module Opaleye.SQLite.PGTypes) where

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

import qualified Opaleye.SQLite.Internal.HaskellDB.PrimQuery as HPQ
import qualified Opaleye.SQLite.Internal.HaskellDB.Sql.Default as HSD (quote)

import qualified Data.CaseInsensitive as CI
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 qualified Data.Time as Time
import qualified Data.UUID as UUID

import           Data.Int (Int64)

data PGBool
data PGDate
data PGFloat4
data PGFloat8
data PGInt8
data PGInt4
data PGInt2
data PGNumeric
data PGText
data PGTime
data PGTimestamp
data PGTimestamptz
data PGUuid
data PGCitext
data PGArray a
data PGBytea
data PGJson
data PGJsonb

instance C.PGNum PGFloat8 where
  pgFromInteger :: Integer -> Column PGFloat8
pgFromInteger = Double -> Column PGFloat8
pgDouble (Double -> Column PGFloat8)
-> (Integer -> Double) -> Integer -> Column PGFloat8
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Integer -> Double
forall a. Num a => Integer -> a
fromInteger

instance C.PGNum PGInt4 where
  pgFromInteger :: Integer -> Column PGInt4
pgFromInteger = Int -> Column PGInt4
pgInt4 (Int -> Column PGInt4)
-> (Integer -> Int) -> Integer -> Column PGInt4
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Integer -> Int
forall a. Num a => Integer -> a
fromInteger

instance C.PGNum PGInt8 where
  pgFromInteger :: Integer -> Column PGInt8
pgFromInteger = Int64 -> Column PGInt8
pgInt8 (Int64 -> Column PGInt8)
-> (Integer -> Int64) -> Integer -> Column PGInt8
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Integer -> Int64
forall a. Num a => Integer -> a
fromInteger

instance C.PGFractional PGFloat8 where
  pgFromRational :: Rational -> Column PGFloat8
pgFromRational = Double -> Column PGFloat8
pgDouble (Double -> Column PGFloat8)
-> (Rational -> Double) -> Rational -> Column PGFloat8
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Rational -> Double
forall a. Fractional a => Rational -> a
fromRational

literalColumn :: HPQ.Literal -> Column a
literalColumn :: Literal -> Column a
literalColumn = Literal -> Column a
forall a. Literal -> Column a
IPT.literalColumn
{-# WARNING literalColumn
    "'literalColumn' has been moved to Opaleye.Internal.PGTypes"
  #-}

pgString :: String -> Column PGText
pgString :: String -> Column PGText
pgString = Literal -> Column PGText
forall a. Literal -> Column a
IPT.literalColumn (Literal -> Column PGText)
-> (String -> Literal) -> String -> Column PGText
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. 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. 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 PGText
pgStrictText = Literal -> Column PGText
forall a. Literal -> Column a
IPT.literalColumn (Literal -> Column PGText)
-> (Text -> Literal) -> Text -> Column PGText
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 PGText
pgLazyText = Literal -> Column PGText
forall a. Literal -> Column a
IPT.literalColumn (Literal -> Column PGText)
-> (Text -> Literal) -> Text -> Column PGText
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

pgInt4 :: Int -> Column PGInt4
pgInt4 :: Int -> Column PGInt4
pgInt4 = Literal -> Column PGInt4
forall a. Literal -> Column a
IPT.literalColumn (Literal -> Column PGInt4)
-> (Int -> Literal) -> Int -> Column PGInt4
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 PGInt8
pgInt8 = Literal -> Column PGInt8
forall a. Literal -> Column a
IPT.literalColumn (Literal -> Column PGInt8)
-> (Int64 -> Literal) -> Int64 -> Column PGInt8
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

-- SQLite needs to be told that numeric literals without decimal
-- points are actual REAL
pgDouble :: Double -> Column PGFloat8
pgDouble :: Double -> Column PGFloat8
pgDouble = String -> Column Any -> Column PGFloat8
forall a b. String -> Column a -> Column b
C.unsafeCast String
"REAL" (Column Any -> Column PGFloat8)
-> (Double -> Column Any) -> Double -> Column PGFloat8
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Literal -> Column Any
forall a. Literal -> Column a
IPT.literalColumn (Literal -> Column Any)
-> (Double -> Literal) -> Double -> Column Any
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. 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. 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

unsafePgFormatTime :: Time.FormatTime t => HPQ.Name -> String -> t -> Column c
unsafePgFormatTime :: String -> String -> t -> Column c
unsafePgFormatTime = String -> String -> t -> Column c
forall t c. FormatTime t => String -> String -> t -> Column c
IPT.unsafePgFormatTime
{-# WARNING unsafePgFormatTime
    "'unsafePgFormatTime' has been moved to Opaleye.Internal.PGTypes"
  #-}

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%TZ'"

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'"

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'"

-- "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 PGCitext
pgCiStrictText = Literal -> Column PGCitext
forall a. Literal -> Column a
IPT.literalColumn (Literal -> Column PGCitext)
-> (CI Text -> Literal) -> CI Text -> Column PGCitext
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 PGCitext
pgCiLazyText = Literal -> Column PGCitext
forall a. Literal -> Column a
IPT.literalColumn (Literal -> Column PGCitext)
-> (CI Text -> Literal) -> CI Text -> Column PGCitext
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

-- 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.
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