squeal-postgresql-0.9.2.0: src/Squeal/PostgreSQL/Type.hs
{-|
Module: Squeal.PostgreSQL.Type
Description: types
Copyright: (c) Eitan Chatav, 2010
Maintainer: eitan@morphism.tech
Stability: experimental
storage newtypes
-}
{-# LANGUAGE
AllowAmbiguousTypes
, DeriveAnyClass
, DeriveFoldable
, DeriveFunctor
, DeriveGeneric
, DeriveTraversable
, DerivingStrategies
, DefaultSignatures
, FlexibleContexts
, FlexibleInstances
, FunctionalDependencies
, GADTs
, LambdaCase
, MultiParamTypeClasses
, OverloadedStrings
, ScopedTypeVariables
, TypeApplications
, TypeFamilies
, DataKinds
, PolyKinds
, TypeOperators
, UndecidableInstances
, UndecidableSuperClasses
#-}
module Squeal.PostgreSQL.Type
( -- * Storage newtypes
Money (..)
, Json (..)
, Jsonb (..)
, Composite (..)
, Enumerated (..)
, VarArray (..)
, FixArray (..)
, VarChar, varChar, getVarChar
, FixChar, fixChar, getFixChar
, Only (..)
) where
import Data.Proxy
import Data.Int (Int64)
import GHC.TypeLits
import qualified Data.Text as Strict (Text)
import qualified Data.Text as Strict.Text
import qualified GHC.Generics as GHC
import qualified Generics.SOP as SOP
-- $setup
-- >>> import Squeal.PostgreSQL
{- | The `Money` newtype stores a monetary value in terms
of the number of cents, i.e. @$2,000.20@ would be expressed as
@Money { cents = 200020 }@.
>>> :kind! PG Money
PG Money :: PGType
= 'PGmoney
-}
newtype Money = Money { cents :: Int64 }
deriving stock (Eq, Ord, Show, Read, GHC.Generic)
deriving anyclass (SOP.HasDatatypeInfo, SOP.Generic)
{- | The `Json` newtype is an indication that the Haskell
type it's applied to should be stored as a
`Squeal.PostgreSQL.Type.Schema.PGjson`.
>>> :kind! PG (Json [String])
PG (Json [String]) :: PGType
= 'PGjson
-}
newtype Json hask = Json {getJson :: hask}
deriving stock (Eq, Ord, Show, Read, GHC.Generic)
deriving anyclass (SOP.HasDatatypeInfo, SOP.Generic)
{- | The `Jsonb` newtype is an indication that the Haskell
type it's applied to should be stored as a
`Squeal.PostgreSQL.Type.Schema.PGjsonb`.
>>> :kind! PG (Jsonb [String])
PG (Jsonb [String]) :: PGType
= 'PGjsonb
-}
newtype Jsonb hask = Jsonb {getJsonb :: hask}
deriving stock (Eq, Ord, Show, Read, GHC.Generic)
deriving anyclass (SOP.HasDatatypeInfo, SOP.Generic)
{- | The `Composite` newtype is an indication that the Haskell
type it's applied to should be stored as a
`Squeal.PostgreSQL.Type.Schema.PGcomposite`.
>>> :{
data Complex = Complex
{ real :: Double
, imaginary :: Double
} deriving stock GHC.Generic
deriving anyclass (SOP.Generic, SOP.HasDatatypeInfo)
:}
>>> :kind! PG (Composite Complex)
PG (Composite Complex) :: PGType
= 'PGcomposite
'["real" ::: 'NotNull 'PGfloat8,
"imaginary" ::: 'NotNull 'PGfloat8]
-}
newtype Composite record = Composite {getComposite :: record}
deriving stock (Eq, Ord, Show, Read, GHC.Generic)
deriving anyclass (SOP.HasDatatypeInfo, SOP.Generic)
{- | The `Enumerated` newtype is an indication that the Haskell
type it's applied to should be stored as a
`Squeal.PostgreSQL.Type.Schema.PGenum`.
>>> :kind! PG (Enumerated Ordering)
PG (Enumerated Ordering) :: PGType
= 'PGenum '["LT", "EQ", "GT"]
-}
newtype Enumerated enum = Enumerated {getEnumerated :: enum}
deriving stock (Eq, Ord, Show, Read, GHC.Generic)
deriving anyclass (SOP.HasDatatypeInfo, SOP.Generic)
{- | The `VarArray` newtype is an indication that the Haskell
type it's applied to should be stored as a
`Squeal.PostgreSQL.Type.Schema.PGvararray`.
>>> import Data.Vector
>>> :kind! PG (VarArray (Vector Double))
PG (VarArray (Vector Double)) :: PGType
= 'PGvararray ('NotNull 'PGfloat8)
-}
newtype VarArray arr
= VarArray {getVarArray :: arr}
deriving stock (Eq, Ord, Show, Read, GHC.Generic)
deriving anyclass (SOP.HasDatatypeInfo, SOP.Generic)
{- | The `FixArray` newtype is an indication that the Haskell
type it's applied to should be stored as a
`Squeal.PostgreSQL.Type.Schema.PGfixarray`.
>>> :kind! PG (FixArray ((Double, Double), (Double, Double)))
PG (FixArray ((Double, Double), (Double, Double))) :: PGType
= 'PGfixarray '[2, 2] ('NotNull 'PGfloat8)
-}
newtype FixArray arr = FixArray {getFixArray :: arr}
deriving stock (Eq, Ord, Show, Read, GHC.Generic)
deriving anyclass (SOP.HasDatatypeInfo, SOP.Generic)
-- | `Only` is a 1-tuple type, useful for encoding or decoding a singleton
newtype Only x = Only { fromOnly :: x }
deriving (Functor,Foldable,Traversable,Eq,Ord,Read,Show,GHC.Generic)
instance SOP.Generic (Only x)
instance SOP.HasDatatypeInfo (Only x)
{- | Variable-length text type with limit
>>> :kind! PG (VarChar 4)
PG (VarChar 4) :: PGType
= 'PGvarchar 4
-}
newtype VarChar (n :: Nat) = VarChar Strict.Text
deriving (Eq,Ord,Read,Show)
-- | Constructor for `VarChar`
varChar :: forall n . KnownNat n => Strict.Text -> Maybe (VarChar n)
varChar t =
if Strict.Text.length t <= fromIntegral (natVal @n Proxy)
then Just $ VarChar t
else Nothing
-- | Access the `Strict.Text` of a `VarChar`
getVarChar :: VarChar n -> Strict.Text
getVarChar (VarChar t) = t
{- | Fixed-length, blank padded
>>> :kind! PG (FixChar 4)
PG (FixChar 4) :: PGType
= 'PGchar 4
-}
newtype FixChar (n :: Nat) = FixChar Strict.Text
deriving (Eq,Ord,Read,Show)
-- | Constructor for `FixChar`
fixChar :: forall n . KnownNat n => Strict.Text -> Maybe (FixChar n)
fixChar t =
if Strict.Text.length t == fromIntegral (natVal @n Proxy)
then Just $ FixChar t
else Nothing
-- | Access the `Strict.Text` of a `FixChar`
getFixChar :: FixChar n -> Strict.Text
getFixChar (FixChar t) = t