@@ -24,22 +24,60 @@ import qualified Opaleye.Internal.HaskellDB.PrimQuery as Opaleye
2424import qualified Data.Text as Text
2525
2626
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.
2730type TypeInformation :: Type -> Type
2831data TypeInformation a where
2932 TypeInformation ::
3033 { encode :: a -> Opaleye.PrimExpr
34+ -- ^ How to encode a single Haskell value as a SQL expression.
3135 , decode :: Hasql.Value x
36+ -- ^ How to deserialize a single result back to Haskell.
3237 , typeName :: String
38+ -- ^ The name of the SQL type.
3339 , out :: x -> a
40+ -- ^ A final output function - usually this will just be 'id'. This is
41+ -- needed to allow @TypeInformation@s to be coerced.
3442 } -> TypeInformation a
3543
3644
45+-- | Simultaneously map over how a type is both encoded and decoded, while
46+-- retaining the name of the type. This operation is useful if you want to
47+-- essentially @newtype@ another 'DBType'.
48+--
49+-- The mapping is required to be total. If you have a partial mapping, see
50+-- 'parseTypeInformation'.
3751mapTypeInformation :: ()
3852 => (a -> b) -> (b -> a)
3953 -> TypeInformation a -> TypeInformation b
4054mapTypeInformation = parseTypeInformation . fmap pure
4155
4256
57+-- | Apply a parser to 'TypeInformation'.
58+--
59+-- This can be used if the data stored in the database should only be subset of
60+-- a given 'TypeInformation'. The parser is applied when deserializing rows
61+-- returned - the encoder assumes that the input data is already in the
62+-- appropriate form.
63+--
64+-- One example where this may be useful is with a database that stores data in
65+-- some legacy encoding:
66+--
67+-- >>> import Data.Text (Text)
68+--
69+-- >>> data Color = Red | Green | Blue
70+-- >>> :{
71+-- instance DBType Color where
72+-- typeInformation = parseTypeInformation parseLegacy toLegacy typeInformation
73+-- where
74+-- parseLegacy :: Text -> Either String Color
75+-- parseLegacy "red" = Right Red
76+-- parseLegacy "green" = Right Green
77+-- parseLegacy _ = Left "Unexpected Color"
78+-- toLegacy Red = "red"
79+-- toLegacy Green = "green"
80+-- :}
4381parseTypeInformation :: ()
4482 => (a -> Either String b) -> (b -> a)
4583 -> TypeInformation a -> TypeInformation b