rel8-1.0.0.0: src/Rel8/Type/Array.hs
{-# language GADTs #-}
{-# language LambdaCase #-}
{-# language NamedFieldPuns #-}
{-# language OverloadedStrings #-}
{-# language ViewPatterns #-}
module Rel8.Type.Array
( array, encodeArrayElement, extractArrayElement
, listTypeInformation
, nonEmptyTypeInformation
)
where
-- base
import Data.Foldable ( toList )
import Data.List.NonEmpty ( NonEmpty, nonEmpty )
import Prelude hiding ( null, repeat, zipWith )
-- hasql
import qualified Hasql.Decoders as Hasql
-- opaleye
import qualified Opaleye.Internal.HaskellDB.PrimQuery as Opaleye
-- rel8
import Rel8.Schema.Null ( Unnullify, Nullity( Null, NotNull ) )
import Rel8.Type.Information ( TypeInformation(..), parseTypeInformation )
array :: Foldable f
=> TypeInformation a -> f Opaleye.PrimExpr -> Opaleye.PrimExpr
array info =
Opaleye.CastExpr (arrayType info <> "[]") .
Opaleye.ArrayExpr . map (encodeArrayElement info) . toList
{-# INLINABLE array #-}
listTypeInformation :: ()
=> Nullity a
-> TypeInformation (Unnullify a)
-> TypeInformation [a]
listTypeInformation nullity info@TypeInformation {encode, decode} =
TypeInformation
{ decode = case nullity of
Null ->
Hasql.listArray (decodeArrayElement info (Hasql.nullable decode))
NotNull ->
Hasql.listArray (decodeArrayElement info (Hasql.nonNullable decode))
, encode = case nullity of
Null ->
Opaleye.ArrayExpr .
fmap (encodeArrayElement info . maybe null encode)
NotNull ->
Opaleye.ArrayExpr .
fmap (encodeArrayElement info . encode)
, typeName = arrayType info <> "[]"
}
where
null = Opaleye.ConstExpr Opaleye.NullLit
nonEmptyTypeInformation :: ()
=> Nullity a
-> TypeInformation (Unnullify a)
-> TypeInformation (NonEmpty a)
nonEmptyTypeInformation nullity =
parseTypeInformation parse toList . listTypeInformation nullity
where
parse = maybe (Left message) Right . nonEmpty
message = "failed to decode NonEmptyList: got empty list"
isArray :: TypeInformation a -> Bool
isArray = \case
(reverse . typeName -> ']' : '[' : _) -> True
_ -> False
arrayType :: TypeInformation a -> String
arrayType info
| isArray info = "record"
| otherwise = typeName info
decodeArrayElement :: TypeInformation a -> Hasql.NullableOrNot Hasql.Value x -> Hasql.NullableOrNot Hasql.Value x
decodeArrayElement info
| isArray info = Hasql.nonNullable . Hasql.composite . Hasql.field
| otherwise = id
encodeArrayElement :: TypeInformation a -> Opaleye.PrimExpr -> Opaleye.PrimExpr
encodeArrayElement info
| isArray info = Opaleye.UnExpr (Opaleye.UnOpOther "ROW")
| otherwise = id
extractArrayElement :: TypeInformation a -> Opaleye.PrimExpr -> Opaleye.PrimExpr
extractArrayElement info
| isArray info = flip Opaleye.CompositeExpr "f1"
| otherwise = id