@@ -14,6 +14,8 @@ Portability: portable
15The 'FromField' typeclass, for converting a single value in a row
15The 'FromField' typeclass, for converting a single value in a row
16returned by a SQL query into a more useful Haskell representation.
16returned by a SQL query into a more useful Haskell representation.
17+Note that each instance of 'FromField' is documented by a list of
18+compatible postgresql types.
18A Haskell numeric type is considered to be compatible with all
20A Haskell numeric type is considered to be compatible with all
19PostgreSQL numeric types that are less accurate than it. For instance,
21PostgreSQL numeric types that are less accurate than it. For instance,
@@ -225,14 +227,20 @@ tableColumn Field{..} = fromCol (unsafeDupablePerformIO (PQ.ftablecol result col
225format :: Field -> PQ.Format
227format :: Field -> PQ.Format
226format Field{..} = unsafeDupablePerformIO (PQ.fformat result column)
228format Field{..} = unsafeDupablePerformIO (PQ.fformat result column)
230+-- | For dealing with null values. Compatible with any postgresql type
231+-- compatible with type @a@. Note that the type is not checked if
232+-- the value is null, although it is inadvisable to rely on this
228instance (FromField a) => FromField (Maybe a) where
234instance (FromField a) => FromField (Maybe a) where
229 fromField _ Nothing = pure Nothing
235 fromField _ Nothing = pure Nothing
230 fromField f bs = Just <$> fromField f bs
236 fromField f bs = Just <$> fromField f bs
238+-- | compatible with any data type, but the value must be null
232instance FromField Null where
239instance FromField Null where
233 fromField _ Nothing = pure Null
240 fromField _ Nothing = pure Null
234 fromField f (Just _) = returnError ConversionFailed f "data is not null"
241 fromField f (Just _) = returnError ConversionFailed f "data is not null"
236instance FromField Bool where
244instance FromField Bool where
237 fromField f bs
245 fromField f bs
238 | typeOid f /= typoid (TypeInfo.bool) = returnError Incompatible f ""
246 | typeOid f /= typoid (TypeInfo.bool) = returnError Incompatible f ""
@@ -241,6 +249,7 @@ instance FromField Bool where
241 | bs == Just "f" = pure False
249 | bs == Just "f" = pure False
242 | otherwise = returnError ConversionFailed f ""
250 | otherwise = returnError ConversionFailed f ""
244instance FromField Char where
253instance FromField Char where
245 fromField f bs =
254 fromField f bs =
246 if typeOid f /= typoid (TypeInfo.char)
255 if typeOid f /= typoid (TypeInfo.char)
@@ -251,29 +260,43 @@ instance FromField Char where
251 then returnError ConversionFailed f "length not 1"
260 then returnError ConversionFailed f "length not 1"
252 else return $! (B.head bs)
261 else return $! (B.head bs)
254instance FromField Int16 where
264instance FromField Int16 where
255 fromField = atto ok16 $ signed decimal
265 fromField = atto ok16 $ signed decimal
257instance FromField Int32 where
268instance FromField Int32 where
258 fromField = atto ok32 $ signed decimal
269 fromField = atto ok32 $ signed decimal
271+#if WORD_SIZE_IN_BITS < 64
272+-- | int2, int4, and if compiled as 64-bit code, int8 as well.
273+-- This library was compiled as 32-bit code.
275+-- | int2, int4, and if compiled as 64-bit code, int8 as well.
276+-- This library was compiled as 64-bit code.
260instance FromField Int where
278instance FromField Int where
261 fromField = atto okInt $ signed decimal
279 fromField = atto okInt $ signed decimal
281+-- | int2, int4, int8
263instance FromField Int64 where
282instance FromField Int64 where
264 fromField = atto ok64 $ signed decimal
283 fromField = atto ok64 $ signed decimal
285+-- | int2, int4, int8
266instance FromField Integer where
286instance FromField Integer where
267 fromField = atto ok64 $ signed decimal
287 fromField = atto ok64 $ signed decimal
269instance FromField Float where
290instance FromField Float where
270 fromField = atto ok (realToFrac <$> double)
291 fromField = atto ok (realToFrac <$> double)
271 where ok = mkCompats [Float4,Int2]
292 where ok = mkCompats [Float4,Int2]
294+-- | int2, int4, float4, float8
273instance FromField Double where
295instance FromField Double where
274 fromField = atto ok double
296 fromField = atto ok double
275 where ok = mkCompats [Float4,Float8,Int2,Int4]
297 where ok = mkCompats [Float4,Float8,Int2,Int4]
299+-- | int2, int4, float4, float8, numeric
277instance FromField (Ratio Integer) where
300instance FromField (Ratio Integer) where
278 fromField = atto ok rational
301 fromField = atto ok rational
279 where ok = mkCompats [Float4,Float8,Int2,Int4,Numeric]
302 where ok = mkCompats [Float4,Float8,Int2,Int4,Numeric]
@@ -281,14 +304,17 @@ instance FromField (Ratio Integer) where
281unBinary :: Binary t -> t
304unBinary :: Binary t -> t
282unBinary (Binary x) = x
305unBinary (Binary x) = x
307+-- | bytea, name, text, \"char\", bpchar, varchar, unknown
284instance FromField SB.ByteString where
308instance FromField SB.ByteString where
285 fromField f dat = if typeOid f == typoid TypeInfo.bytea
309 fromField f dat = if typeOid f == typoid TypeInfo.bytea
286 then unBinary <$> fromField f dat
310 then unBinary <$> fromField f dat
287 else doFromField f okText' (pure . B.copy) dat
311 else doFromField f okText' (pure . B.copy) dat
289instance FromField PQ.Oid where
314instance FromField PQ.Oid where
290 fromField f dat = PQ.Oid <$> atto (mkCompat Oid) decimal f dat
315 fromField f dat = PQ.Oid <$> atto (mkCompat Oid) decimal f dat
317+-- | bytea, name, text, \"char\", bpchar, varchar, unknown
292instance FromField LB.ByteString where
318instance FromField LB.ByteString where
293 fromField f dat = LB.fromChunks . (:[]) <$> fromField f dat
319 fromField f dat = LB.fromChunks . (:[]) <$> fromField f dat
@@ -298,48 +324,62 @@ unescapeBytea f str = case unsafeDupablePerformIO (PQ.unescapeBytea str) of
298 Nothing -> returnError ConversionFailed f "unescapeBytea failed"
324 Nothing -> returnError ConversionFailed f "unescapeBytea failed"
299 Just str -> pure (Binary str)
325 Just str -> pure (Binary str)
301instance FromField (Binary SB.ByteString) where
328instance FromField (Binary SB.ByteString) where
302 fromField f dat = case format f of
329 fromField f dat = case format f of
303 PQ.Text -> doFromField f okBinary (unescapeBytea f) dat
330 PQ.Text -> doFromField f okBinary (unescapeBytea f) dat
304 PQ.Binary -> doFromField f okBinary (pure . Binary . B.copy) dat
331 PQ.Binary -> doFromField f okBinary (pure . Binary . B.copy) dat
306instance FromField (Binary LB.ByteString) where
334instance FromField (Binary LB.ByteString) where
307 fromField f dat = Binary . LB.fromChunks . (:[]) . unBinary <$> fromField f dat
335 fromField f dat = Binary . LB.fromChunks . (:[]) . unBinary <$> fromField f dat
337+-- | name, text, \"char\", bpchar, varchar
309instance FromField ST.Text where
338instance FromField ST.Text where
310 fromField f = doFromField f okText $ (either left pure . ST.decodeUtf8')
339 fromField f = doFromField f okText $ (either left pure . ST.decodeUtf8')
311 -- FIXME: check character encoding
340 -- FIXME: check character encoding
342+-- | name, text, \"char\", bpchar, varchar
313instance FromField LT.Text where
343instance FromField LT.Text where
314 fromField f dat = LT.fromStrict <$> fromField f dat
344 fromField f dat = LT.fromStrict <$> fromField f dat
346+-- | name, text, \"char\", bpchar, varchar
316instance FromField [Char] where
347instance FromField [Char] where
317 fromField f dat = ST.unpack <$> fromField f dat
348 fromField f dat = ST.unpack <$> fromField f dat
319instance FromField UTCTime where
351instance FromField UTCTime where
320 fromField = ff TypeInfo.timestamptz "UTCTime" parseUTCTime
352 fromField = ff TypeInfo.timestamptz "UTCTime" parseUTCTime
322instance FromField ZonedTime where
355instance FromField ZonedTime where
323 fromField = ff TypeInfo.timestamptz "ZonedTime" parseZonedTime
356 fromField = ff TypeInfo.timestamptz "ZonedTime" parseZonedTime
325instance FromField LocalTime where
359instance FromField LocalTime where
326 fromField = ff TypeInfo.timestamp "LocalTime" parseLocalTime
360 fromField = ff TypeInfo.timestamp "LocalTime" parseLocalTime
328instance FromField Day where
363instance FromField Day where
329 fromField = ff TypeInfo.date "Day" parseDay
364 fromField = ff TypeInfo.date "Day" parseDay
331instance FromField TimeOfDay where
367instance FromField TimeOfDay where
332 fromField = ff TypeInfo.time "TimeOfDay" parseTimeOfDay
368 fromField = ff TypeInfo.time "TimeOfDay" parseTimeOfDay
334instance FromField UTCTimestamp where
371instance FromField UTCTimestamp where
335 fromField = ff TypeInfo.timestamptz "UTCTimestamp" parseUTCTimestamp
372 fromField = ff TypeInfo.timestamptz "UTCTimestamp" parseUTCTimestamp
337instance FromField ZonedTimestamp where
375instance FromField ZonedTimestamp where
338 fromField = ff TypeInfo.timestamptz "ZonedTimestamp" parseZonedTimestamp
376 fromField = ff TypeInfo.timestamptz "ZonedTimestamp" parseZonedTimestamp
340instance FromField LocalTimestamp where
379instance FromField LocalTimestamp where
341 fromField = ff TypeInfo.timestamp "LocalTimestamp" parseLocalTimestamp
380 fromField = ff TypeInfo.timestamp "LocalTimestamp" parseLocalTimestamp
343instance FromField Date where
383instance FromField Date where
344 fromField = ff TypeInfo.date "Date" parseDate
384 fromField = ff TypeInfo.date "Date" parseDate
@@ -367,6 +407,7 @@ instance (FromField a, FromField b) => FromField (Either a b) where
367 fromField f dat = (Right <$> fromField f dat)
407 fromField f dat = (Right <$> fromField f dat)
368 <|> (Left <$> fromField f dat)
408 <|> (Left <$> fromField f dat)
410+-- | any postgresql array whose elements are compatible with type @a@
370instance (FromField a, Typeable a) => FromField (Vector a) where
411instance (FromField a, Typeable a) => FromField (Vector a) where
371 fromField f mdat = do
412 fromField f mdat = do
372 info <- typeInfo f
413 info <- typeInfo f