{-# LANGUAGE
AllowAmbiguousTypes
, DeriveFoldable
, DeriveFunctor
, DeriveGeneric
, DeriveTraversable
, DefaultSignatures
, FlexibleContexts
, FlexibleInstances
, FunctionalDependencies
, GADTs
, LambdaCase
, OverloadedStrings
, MultiParamTypeClasses
, ScopedTypeVariables
, TypeApplications
, TypeFamilies
, TypeInType
, TypeOperators
, UndecidableInstances
, UndecidableSuperClasses
#-}
module Squeal.PostgreSQL.PG
(
PG
, NullPG
, TuplePG
, RowPG
, Money (..)
, Json (..)
, Jsonb (..)
, Composite (..)
, Enumerated (..)
, VarArray (..)
, FixArray (..)
, LabelsPG
, DimPG
, FixPG
, TupleOf
, TupleCodeOf
, RowOf
, ConstructorsOf
, ConstructorNameOf
, ConstructorNamesOf
) where
import Data.Aeson (Value)
import Data.Kind (Type)
import Data.Int (Int16, Int32, Int64)
import Data.Scientific (Scientific)
import Data.Time (Day, DiffTime, LocalTime, TimeOfDay, TimeZone, UTCTime)
import Data.Vector (Vector)
import Data.Word (Word16, Word32, Word64)
import Data.UUID.Types (UUID)
import GHC.TypeLits
import Network.IP.Addr (NetAddr, IP)
import qualified Data.ByteString.Lazy as Lazy (ByteString)
import qualified Data.ByteString as Strict (ByteString)
import qualified Data.Text.Lazy as Lazy (Text)
import qualified Data.Text as Strict (Text)
import qualified GHC.Generics as GHC
import qualified Generics.SOP as SOP
import qualified Generics.SOP.Record as SOP
import qualified Generics.SOP.Type.Metadata as Type
import Squeal.PostgreSQL.Alias
import Squeal.PostgreSQL.Schema
type family PG (hask :: Type) :: PGType
type instance PG Bool = 'PGbool
type instance PG Int16 = 'PGint2
type instance PG Int32 = 'PGint4
type instance PG Int64 = 'PGint8
type instance PG Word16 = 'PGint2
type instance PG Word32 = 'PGint4
type instance PG Word64 = 'PGint8
type instance PG Scientific = 'PGnumeric
type instance PG Float = 'PGfloat4
type instance PG Double = 'PGfloat8
type instance PG Char = 'PGchar 1
type instance PG Strict.Text = 'PGtext
type instance PG Lazy.Text = 'PGtext
type instance PG String = 'PGtext
type instance PG Strict.ByteString = 'PGbytea
type instance PG Lazy.ByteString = 'PGbytea
type instance PG LocalTime = 'PGtimestamp
type instance PG UTCTime = 'PGtimestamptz
type instance PG Day = 'PGdate
type instance PG TimeOfDay = 'PGtime
type instance PG (TimeOfDay, TimeZone) = 'PGtimetz
type instance PG DiffTime = 'PGinterval
type instance PG UUID = 'PGuuid
type instance PG (NetAddr IP) = 'PGinet
type instance PG Value = 'PGjson
type family LabelsPG (hask :: Type) :: [Type.ConstructorName] where
LabelsPG hask =
ConstructorNamesOf (ConstructorsOf (SOP.DatatypeInfoOf hask))
type family RowPG (hask :: Type) :: RowType where
RowPG hask = RowOf (SOP.RecordCodeOf hask)
type family RowOf (record :: [(Symbol, Type)]) :: RowType where
RowOf '[] = '[]
RowOf (col ::: ty ': record) = col ::: NullPG ty ': RowOf record
type family NullPG (hask :: Type) :: NullityType where
NullPG (Maybe hask) = 'Null (PG hask)
NullPG hask = 'NotNull (PG hask)
type family TuplePG (hask :: Type) :: [NullityType] where
TuplePG hask = TupleOf (TupleCodeOf hask (SOP.Code hask))
type family TupleOf (tuple :: [Type]) :: [NullityType] where
TupleOf '[] = '[]
TupleOf (hask ': tuple) = NullPG hask ': TupleOf tuple
type family TupleCodeOf (hask :: Type) (code :: [[Type]]) :: [Type] where
TupleCodeOf hask '[tuple] = tuple
TupleCodeOf hask '[] =
TypeError
( 'Text "The type `" ':<>: 'ShowType hask ':<>: 'Text "' is not a tuple type."
':$$: 'Text "It is a void type with no constructors."
)
TupleCodeOf hask (_ ': _ ': _) =
TypeError
( 'Text "The type `" ':<>: 'ShowType hask ':<>: 'Text "' is not a tuple type."
':$$: 'Text "It is a sum type with more than one constructor."
)
type family ConstructorsOf (datatype :: Type.DatatypeInfo)
:: [Type.ConstructorInfo] where
ConstructorsOf ('Type.ADT _module _datatype constructors) =
constructors
ConstructorsOf ('Type.Newtype _module _datatype constructor) =
'[constructor]
type family ConstructorNameOf (constructor :: Type.ConstructorInfo)
:: Type.ConstructorName where
ConstructorNameOf ('Type.Constructor name) = name
ConstructorNameOf ('Type.Infix name _assoc _fix) = TypeError
('Text "ConstructorNameOf error: non-nullary constructor "
':<>: 'Text name)
ConstructorNameOf ('Type.Record name _fields) = TypeError
('Text "ConstructorNameOf error: non-nullary constructor "
':<>: 'Text name)
type family ConstructorNamesOf (constructors :: [Type.ConstructorInfo])
:: [Type.ConstructorName] where
ConstructorNamesOf '[] = '[]
ConstructorNamesOf (constructor ': constructors) =
ConstructorNameOf constructor ': ConstructorNamesOf constructors
type family DimPG (hask :: Type) :: [Nat] where
DimPG (x,x) = 2 ': DimPG x
DimPG (x,x,x) = 3 ': DimPG x
DimPG (x,x,x,x) = 4 ': DimPG x
DimPG (x,x,x,x,x) = 5 ': DimPG x
DimPG (x,x,x,x,x,x) = 6 ': DimPG x
DimPG (x,x,x,x,x,x,x) = 7 ': DimPG x
DimPG (x,x,x,x,x,x,x,x) = 8 ': DimPG x
DimPG (x,x,x,x,x,x,x,x,x) = 9 ': DimPG x
DimPG (x,x,x,x,x,x,x,x,x,x) = 10 ': DimPG x
DimPG x = '[]
type family FixPG (hask :: Type) :: NullityType where
FixPG (x,x) = FixPG x
FixPG (x,x,x) = FixPG x
FixPG (x,x,x,x) = FixPG x
FixPG (x,x,x,x,x) = FixPG x
FixPG (x,x,x,x,x,x) = FixPG x
FixPG (x,x,x,x,x,x,x) = FixPG x
FixPG (x,x,x,x,x,x,x,x) = FixPG x
FixPG (x,x,x,x,x,x,x,x,x) = FixPG x
FixPG (x,x,x,x,x,x,x,x,x,x) = FixPG x
FixPG (x,x,x,x,x,x,x,x,x,x,x) = FixPG x
FixPG x = NullPG x
newtype Money = Money { cents :: Int64 }
deriving (Eq, Ord, Show, Read, GHC.Generic)
type instance PG Money = 'PGmoney
newtype Json hask = Json {getJson :: hask}
deriving (Eq, Ord, Show, Read, GHC.Generic)
type instance PG (Json hask) = 'PGjson
newtype Jsonb hask = Jsonb {getJsonb :: hask}
deriving (Eq, Ord, Show, Read, GHC.Generic)
type instance PG (Jsonb hask) = 'PGjsonb
newtype Composite record = Composite {getComposite :: record}
deriving (Eq, Ord, Show, Read, GHC.Generic)
type instance PG (Composite hask) = 'PGcomposite (RowPG hask)
newtype Enumerated enum = Enumerated {getEnumerated :: enum}
deriving (Eq, Ord, Show, Read, GHC.Generic)
type instance PG (Enumerated hask) = 'PGenum (LabelsPG hask)
newtype VarArray arr = VarArray {getVarArray :: arr}
deriving (Eq, Ord, Show, Read, GHC.Generic)
type instance PG (VarArray (Vector hask)) = 'PGvararray (NullPG hask)
type instance PG (VarArray [hask]) = 'PGvararray (NullPG hask)
newtype FixArray arr = FixArray {getFixArray :: arr}
deriving (Eq, Ord, Show, Read, GHC.Generic)
type instance PG (FixArray hask) = 'PGfixarray (DimPG hask) (FixPG hask)