on ef91171 help sign in
rel8/src/Rel8/Type/Information.hs
67 lines 2.1 kB history raw
1{-# language GADTs #-}
2{-# language NamedFieldPuns #-}
3{-# language StandaloneKindSignatures #-}
5module Rel8.Type.Information
6 ( TypeInformation(..)
7 , mapTypeInformation
8 , parseTypeInformation
9 )
10where
12-- base
13import Data.Bifunctor ( first )
14import Data.Kind ( Type )
15import Prelude
17-- hasql
18import qualified Hasql.Decoders as Hasql
20-- opaleye
21import qualified Opaleye.Internal.HaskellDB.PrimQuery as Opaleye
23-- text
24import qualified Data.Text as Text
27-- | @TypeInformation@ describes how to encode and decode a Haskell type to and
28-- from database queries. The @typeName@ is the name of the type in the
29-- database, which is used to accurately type literals.
30type TypeInformation :: Type -> Type
31data TypeInformation a = TypeInformation
32 { encode :: a -> Opaleye.PrimExpr
33 -- ^ How to encode a single Haskell value as a SQL expression.
34 , decode :: Hasql.Value a
35 -- ^ How to deserialize a single result back to Haskell.
36 , typeName :: String
37 -- ^ The name of the SQL type.
38 }
41-- | Simultaneously map over how a type is both encoded and decoded, while
42-- retaining the name of the type. This operation is useful if you want to
43-- essentially @newtype@ another 'Rel8.DBType'.
44--
45-- The mapping is required to be total. If you have a partial mapping, see
46-- 'parseTypeInformation'.
47mapTypeInformation :: ()
48 => (a -> b) -> (b -> a)
49 -> TypeInformation a -> TypeInformation b
50mapTypeInformation = parseTypeInformation . fmap pure
53-- | Apply a parser to 'TypeInformation'.
54--
55-- This can be used if the data stored in the database should only be subset of
56-- a given 'TypeInformation'. The parser is applied when deserializing rows
57-- returned - the encoder assumes that the input data is already in the
58-- appropriate form.
59parseTypeInformation :: ()
60 => (a -> Either String b) -> (b -> a)
61 -> TypeInformation a -> TypeInformation b
62parseTypeInformation to from TypeInformation {encode, decode, typeName} =
63 TypeInformation
64 { encode = encode . from
65 , decode = Hasql.refine (first Text.pack . to) decode
66 , typeName
67 }