git.iko.soy/typeable/http-api-data
on master help sign in
Merge branch 'fierce-katie-bounded-data-#28'
commit1a961e73f166d83c796562dc9b72084af96d7358 authorNickolay Kudasov <nickolay.kudasov@gmail.com> dateFri 10 Jun 2016, 02:42 (10 years ago) parent028550b57bf0a3
2 files changed+63−6
Web/HttpApiData.hs+8−1 Web/HttpApiData/Internal.hs+55−5
Web/HttpApiData.hs+8−1
@@ -27,10 +27,17 @@ module Web.HttpApiData (
2727 toQueryParams,
2828 parseQueryParams,
2929
30+ -- * Parsers for @'Bounded'@ @'Enum'@s
31+ parseBoundedUrlPiece,
32+ parseBoundedQueryParam,
33+ parseBoundedHeader,
34+ parseBoundedEnumOf,
35+ parseBoundedEnumOfI,
36+ parseBoundedTextData,
37+
3038 -- * Other helpers
3139 showTextData,
3240 readTextData,
33− parseBoundedTextData,
3441) where
3542
3643import Web.HttpApiData.Internal
Web/HttpApiData/Internal.hs+55−5
@@ -44,6 +44,9 @@ import TextShow (TextShow, showt)
4444#endif
4545
4646-- | Convert value to HTTP API data.
47+--
48+-- __WARNING__: Do not derive this using @DeriveAnyClass@ as the generated
49+-- instance will loop indefinitely.
4750class ToHttpApiData a where
4851 {-# MINIMAL toUrlPiece | toQueryParam #-}
4952 -- | Convert to URL path piece.
@@ -59,6 +62,9 @@ class ToHttpApiData a where
5962 toQueryParam = toUrlPiece
6063
6164-- | Parse value from HTTP API data.
65+--
66+-- __WARNING__: Do not derive this using @DeriveAnyClass@ as the generated
67+-- instance will loop indefinitely.
6268class FromHttpApiData a where
6369 {-# MINIMAL parseUrlPiece | parseQueryParam #-}
6470 -- | Parse URL path piece.
@@ -280,9 +286,53 @@ parseBoundedTextData :: (TextShow a, Bounded a, Enum a) => Text -> Either Text a
280286-- Right Foo
281287parseBoundedTextData :: (Show a, Bounded a, Enum a) => Text -> Either Text a
282288#endif
283−parseBoundedTextData = parseMaybeTextData (flip lookup values . T.toLower)
284− where
285− values = map (showTextData &&& id) [minBound..maxBound]
289+parseBoundedTextData = parseBoundedEnumOfI showTextData
290+
291+-- | Lookup values based on a precalculated mapping of their representations.
292+lookupBoundedEnumOf :: (Bounded a, Enum a, Eq b) => (a -> b) -> b -> Maybe a
293+lookupBoundedEnumOf f = flip lookup (map (f &&& id) [minBound..maxBound])
294+
295+-- | Parse values based on a precalculated mapping of their @'Text'@ representation.
296+--
297+-- >>> parseBoundedEnumOf toUrlPiece "true" :: Either Text Bool
298+-- Right True
299+--
300+-- For case sensitive parser see 'parseBoundedEnumOfI'.
301+parseBoundedEnumOf :: (Bounded a, Enum a) => (a -> Text) -> Text -> Either Text a
302+parseBoundedEnumOf = parseMaybeTextData . lookupBoundedEnumOf
303+
304+-- | /Case insensitive/.
305+--
306+-- Parse values case insensitively based on a precalculated mapping
307+-- of their @'Text'@ representations.
308+--
309+-- >>> parseBoundedEnumOfI toUrlPiece "FALSE" :: Either Text Bool
310+-- Right False
311+--
312+-- For case sensitive parser see 'parseBoundedEnumOf'.
313+parseBoundedEnumOfI :: (Bounded a, Enum a) => (a -> Text) -> Text -> Either Text a
314+parseBoundedEnumOfI f = parseBoundedEnumOf (T.toLower . f) . T.toLower
315+
316+-- | /Case insensitive/.
317+--
318+-- Parse values case insensitively based on @'ToHttpApiData'@ instance.
319+-- Uses @'toUrlPiece'@ to get possible values.
320+parseBoundedUrlPiece :: (ToHttpApiData a, Bounded a, Enum a) => Text -> Either Text a
321+parseBoundedUrlPiece = parseBoundedEnumOfI toUrlPiece
322+
323+-- | /Case insensitive/.
324+--
325+-- Parse values case insensitively based on @'ToHttpApiData'@ instance.
326+-- Uses @'toQueryParam'@ to get possible values.
327+parseBoundedQueryParam :: (ToHttpApiData a, Bounded a, Enum a) => Text -> Either Text a
328+parseBoundedQueryParam = parseBoundedEnumOfI toQueryParam
329+
330+-- | Parse values based on @'ToHttpApiData'@ instance.
331+-- Uses @'toHeader'@ to get possible values.
332+parseBoundedHeader :: (ToHttpApiData a, Bounded a, Enum a) => ByteString -> Either Text a
333+parseBoundedHeader bs = case lookupBoundedEnumOf toHeader bs of
334+ Nothing -> defaultParseError (decodeUtf8 bs)
335+ Just x -> return x
286336
287337-- | Parse URL piece using @'Read'@ instance.
288338--
@@ -442,8 +492,8 @@ instance FromHttpApiData Void where
442492 parseUrlPiece _ = Left "Void cannot be parsed!"
443493#endif
444494
445−instance FromHttpApiData Bool where parseUrlPiece = parseBoundedTextData
446−instance FromHttpApiData Ordering where parseUrlPiece = parseBoundedTextData
495+instance FromHttpApiData Bool where parseUrlPiece = parseBoundedUrlPiece
496+instance FromHttpApiData Ordering where parseUrlPiece = parseBoundedUrlPiece
447497instance FromHttpApiData Double where parseUrlPiece = runReader rational
448498instance FromHttpApiData Float where parseUrlPiece = runReader rational
449499instance FromHttpApiData Int where parseUrlPiece = parseBounded (signed decimal)