hasql-1.10.3.5: src/library/Hasql/Codecs/Encoders/Composite.hs
module Hasql.Codecs.Encoders.Composite where
import Data.HashMap.Strict qualified as HashMap
import Data.HashSet qualified as HashSet
import Hasql.Codecs.Encoders.NullableOrNot qualified as NullableOrNot
import Hasql.Codecs.Encoders.Value qualified as Value
import Hasql.Codecs.Vocab qualified as Vocab
import Hasql.Codecs.Vocab.QualifiedTypeName qualified as Vocab.QualifiedTypeName
import Hasql.Codecs.Vocab.TypeInfo qualified as Vocab.TypeInfo
import Hasql.Platform.Prelude hiding (bool)
import PostgreSQL.Binary.Encoding qualified as Binary
import TextBuilder qualified
-- |
-- Composite or row-types encoder.
data Composite a
= Composite
-- | Names of types that are not known statically and must be looked up at runtime collected from the nested composite and array encoders.
(HashSet Vocab.QualifiedTypeName)
-- | Serialization function given the dictionary of resolved OIDs.
(HashMap Vocab.QualifiedTypeName Vocab.TypeInfo -> a -> Binary.Composite)
-- | Render function for error messages.
(a -> [TextBuilder.TextBuilder])
instance Contravariant Composite where
contramap f (Composite unknownTypes encode print) =
Composite unknownTypes (\oidCache -> encode oidCache . f) (print . f)
instance Divisible Composite where
divide f (Composite unknownTypesL encodeL printL) (Composite unknownTypesR encodeR printR) =
Composite
(unknownTypesL <> unknownTypesR)
(\oidCache val -> case f val of (lVal, rVal) -> encodeL oidCache lVal <> encodeR oidCache rVal)
(\val -> case f val of (lVal, rVal) -> printL lVal <> printR rVal)
conquer = mempty
instance Semigroup (Composite a) where
Composite unknownTypesL encodeL printL <> Composite unknownTypesR encodeR printR =
Composite
(unknownTypesL <> unknownTypesR)
(\oidCache val -> encodeL oidCache val <> encodeR oidCache val)
(\val -> printL val <> printR val)
instance Monoid (Composite a) where
mempty = Composite mempty mempty mempty
-- | Single field of a row-type.
field :: NullableOrNot.NullableOrNot Value.Value a -> Composite a
field = \case
NullableOrNot.NonNullable (Value.Value schemaName typeName scalarOid arrayOid dimensionality _ unknownTypes encode print) ->
let staticOid = if dimensionality == 0 then scalarOid else arrayOid
in case staticOid of
Just oid ->
Composite
unknownTypes
(\oidCache val -> Binary.field oid (encode oidCache val))
(\val -> [print val])
Nothing ->
Composite
(HashSet.insert (Vocab.QualifiedTypeName.QualifiedTypeName schemaName typeName) unknownTypes)
( \oidCache val ->
let typeInfo = HashMap.lookup (Vocab.QualifiedTypeName.QualifiedTypeName schemaName typeName) oidCache
oid = if dimensionality == 0 then maybe 0 Vocab.TypeInfo.toBaseOid typeInfo else maybe 0 Vocab.TypeInfo.toArrayOid typeInfo
in Binary.field oid (encode oidCache val)
)
(\val -> [print val])
NullableOrNot.Nullable (Value.Value schemaName typeName scalarOid arrayOid dimensionality _ unknownTypes encode print) ->
let staticOid = if dimensionality == 0 then scalarOid else arrayOid
in case staticOid of
Just oid ->
Composite
unknownTypes
( \oidCache -> \case
Nothing -> Binary.nullField oid
Just val -> Binary.field oid (encode oidCache val)
)
( \case
Nothing -> ["NULL"]
Just val -> [print val]
)
Nothing ->
Composite
(HashSet.insert (Vocab.QualifiedTypeName.QualifiedTypeName schemaName typeName) unknownTypes)
( \oidCache -> \case
Nothing ->
let typeInfo = HashMap.lookup (Vocab.QualifiedTypeName.QualifiedTypeName schemaName typeName) oidCache
oid = if dimensionality == 0 then maybe 0 Vocab.TypeInfo.toBaseOid typeInfo else maybe 0 Vocab.TypeInfo.toArrayOid typeInfo
in Binary.nullField oid
Just val ->
let typeInfo = HashMap.lookup (Vocab.QualifiedTypeName.QualifiedTypeName schemaName typeName) oidCache
oid = if dimensionality == 0 then maybe 0 Vocab.TypeInfo.toBaseOid typeInfo else maybe 0 Vocab.TypeInfo.toArrayOid typeInfo
in Binary.field oid (encode oidCache val)
)
( \case
Nothing -> ["NULL"]
Just val -> [print val]
)