{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
module Preql.Wire.ToSql where
import Preql.Imports
import Preql.Wire.Tuples (deriveToSqlTuple)
import Preql.Wire.Types
import Data.Functor.Contravariant
import Data.Int
import Data.Time (Day, TimeOfDay, UTCTime)
import Data.UUID (UUID)
import qualified ByteString.StrictBuilder as B
import qualified Data.Aeson as JSON
import qualified Data.ByteString.Lazy as BSL
import qualified Data.Text as T
import qualified Data.Text.Lazy as TL
import qualified Database.PostgreSQL.LibPQ as PQ
import qualified PostgreSQL.Binary.Encoding as PGB
import qualified Preql.Wire.TypeInfo.Static as OID
data FieldEncoder a = FieldEncoder PQ.Oid (a -> B.Builder)
instance Contravariant FieldEncoder where
contramap f (FieldEncoder oid enc) = FieldEncoder oid (enc . f)
runFieldEncoder :: FieldEncoder p -> p -> (PQ.Oid, ByteString)
runFieldEncoder (FieldEncoder oid enc) p = (oid, B.builderBytes (enc p))
type RowEncoder a = a -> [(PQ.Oid, ByteString)]
runEncoder :: RowEncoder p -> p -> [Maybe (PQ.Oid, ByteString, PQ.Format)]
runEncoder fields p = fields p <&> \(oid, bs) -> Just (oid, bs, PQ.Binary)
oneField :: FieldEncoder a -> RowEncoder a
oneField enc = \p -> [runFieldEncoder enc p]
class ToSqlField a where
toSqlField :: FieldEncoder a
class ToSql a where
toSql :: RowEncoder a
instance ToSqlField Bool where
toSqlField = FieldEncoder OID.boolOid PGB.bool
instance ToSql Bool where toSql = oneField toSqlField
instance ToSqlField Int16 where
toSqlField = FieldEncoder OID.int2Oid PGB.int2_int16
instance ToSql Int16 where toSql = oneField toSqlField
instance ToSqlField Int32 where
toSqlField = FieldEncoder OID.int4Oid PGB.int4_int32
instance ToSql Int32 where toSql = oneField toSqlField
instance ToSqlField Int64 where
toSqlField = FieldEncoder OID.int8Oid PGB.int8_int64
instance ToSql Int64 where toSql = oneField toSqlField
instance ToSqlField Float where
toSqlField = FieldEncoder OID.float4Oid PGB.float4
instance ToSql Float where toSql = oneField toSqlField
instance ToSqlField Double where
toSqlField = FieldEncoder OID.float8Oid PGB.float8
instance ToSql Double where toSql = oneField toSqlField
instance ToSqlField Char where
toSqlField = FieldEncoder OID.charOid PGB.char_utf8
instance ToSql Char where toSql = oneField toSqlField
instance ToSqlField String where
toSqlField = FieldEncoder OID.textOid (PGB.text_strict . T.pack)
instance ToSql String where toSql = oneField toSqlField
instance ToSqlField Text where
toSqlField = FieldEncoder OID.textOid PGB.text_strict
instance ToSql Text where toSql = oneField toSqlField
instance ToSqlField TL.Text where
toSqlField = FieldEncoder OID.textOid PGB.text_lazy
instance ToSql TL.Text where toSql = oneField toSqlField
instance ToSqlField ByteString where
toSqlField = FieldEncoder OID.byteaOid PGB.bytea_strict
instance ToSql ByteString where toSql = oneField toSqlField
instance ToSqlField BSL.ByteString where
toSqlField = FieldEncoder OID.byteaOid PGB.bytea_lazy
instance ToSql BSL.ByteString where toSql = oneField toSqlField
instance ToSqlField UTCTime where
toSqlField = FieldEncoder OID.timestamptzOid PGB.timestamptz_int
instance ToSql UTCTime where toSql = oneField toSqlField
instance ToSqlField Day where
toSqlField = FieldEncoder OID.dateOid PGB.date
instance ToSql Day where toSql = oneField toSqlField
instance ToSqlField TimeOfDay where
toSqlField = FieldEncoder OID.timeOid PGB.time_int
instance ToSql TimeOfDay where toSql = oneField toSqlField
instance ToSqlField TimeTZ where
toSqlField = FieldEncoder OID.timetzOid (\(TimeTZ tod tz) -> PGB.timetz_int (tod, tz))
instance ToSql TimeTZ where toSql = oneField toSqlField
instance ToSqlField UUID where
toSqlField = FieldEncoder OID.uuidOid PGB.uuid
instance ToSql UUID where toSql = oneField toSqlField
instance ToSqlField JSON.Value where
toSqlField = FieldEncoder OID.jsonbOid PGB.jsonb_ast
instance ToSql JSON.Value where toSql = oneField toSqlField
toSqlJsonField :: JSON.ToJSON a => FieldEncoder a
toSqlJsonField = FieldEncoder OID.jsonbOid (PGB.jsonb_bytes . BSL.toStrict . JSON.encode)
instance ToSql () where
toSql () = []
instance (ToSqlField a, ToSqlField b) => ToSql (a, b) where
toSql (a, b) = [runFieldEncoder toSqlField a, runFieldEncoder toSqlField b]
instance (ToSqlField a, ToSqlField b, ToSqlField c) => ToSql (a, b, c) where
toSql (a, b, c) =
[runFieldEncoder toSqlField a, runFieldEncoder toSqlField b, runFieldEncoder toSqlField c]
$(deriveToSqlTuple 4)
$(deriveToSqlTuple 5)
$(deriveToSqlTuple 6)
$(deriveToSqlTuple 7)
$(deriveToSqlTuple 8)
$(deriveToSqlTuple 9)
$(deriveToSqlTuple 10)
$(deriveToSqlTuple 11)
$(deriveToSqlTuple 12)
$(deriveToSqlTuple 13)
$(deriveToSqlTuple 14)
$(deriveToSqlTuple 15)
$(deriveToSqlTuple 16)
$(deriveToSqlTuple 17)
$(deriveToSqlTuple 18)
$(deriveToSqlTuple 19)
$(deriveToSqlTuple 20)
$(deriveToSqlTuple 21)
$(deriveToSqlTuple 22)
$(deriveToSqlTuple 23)
$(deriveToSqlTuple 24)
$(deriveToSqlTuple 25)