@@ -44,6 +44,9 @@ import TextShow (TextShow, showt)
46-- | Convert value to HTTP API data.
46-- | Convert value to HTTP API data.
48+-- __WARNING__: Do not derive this using @DeriveAnyClass@ as the generated
49+-- instance will loop indefinitely.
47class ToHttpApiData a where
50class ToHttpApiData a where
48 {-# MINIMAL toUrlPiece | toQueryParam #-}
51 {-# MINIMAL toUrlPiece | toQueryParam #-}
49 -- | Convert to URL path piece.
52 -- | Convert to URL path piece.
@@ -59,6 +62,9 @@ class ToHttpApiData a where
59 toQueryParam = toUrlPiece
62 toQueryParam = toUrlPiece
61-- | Parse value from HTTP API data.
64-- | Parse value from HTTP API data.
66+-- __WARNING__: Do not derive this using @DeriveAnyClass@ as the generated
67+-- instance will loop indefinitely.
62class FromHttpApiData a where
68class FromHttpApiData a where
63 {-# MINIMAL parseUrlPiece | parseQueryParam #-}
69 {-# MINIMAL parseUrlPiece | parseQueryParam #-}
64 -- | Parse URL path piece.
70 -- | Parse URL path piece.
@@ -280,9 +286,53 @@ parseBoundedTextData :: (TextShow a, Bounded a, Enum a) => Text -> Either Text a
280-- Right Foo
286-- Right Foo
281parseBoundedTextData :: (Show a, Bounded a, Enum a) => Text -> Either Text a
287parseBoundedTextData :: (Show a, Bounded a, Enum a) => Text -> Either Text a
283−parseBoundedTextData = parseMaybeTextData (flip lookup values . T.toLower)
289+parseBoundedTextData = parseBoundedEnumOfI showTextData
291+-- | Lookup values based on a precalculated mapping of their representations.
292+lookupBoundedEnumOf :: (Bounded a, Enum a, Eq b) => (a -> b) -> b -> Maybe a
285− values = map (showTextData &&& id) [minBound..maxBound]
293+lookupBoundedEnumOf f = flip lookup (map (f &&& id) [minBound..maxBound])
295+-- | Parse values based on a precalculated mapping of their @'Text'@ representation.
297+-- >>> parseBoundedEnumOf toUrlPiece "true" :: Either Text Bool
300+-- For case sensitive parser see 'parseBoundedEnumOfI'.
301+parseBoundedEnumOf :: (Bounded a, Enum a) => (a -> Text) -> Text -> Either Text a
302+parseBoundedEnumOf = parseMaybeTextData . lookupBoundedEnumOf
304+-- | /Case insensitive/.
306+-- Parse values case insensitively based on a precalculated mapping
307+-- of their @'Text'@ representations.
309+-- >>> parseBoundedEnumOfI toUrlPiece "FALSE" :: Either Text Bool
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
316+-- | /Case insensitive/.
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
323+-- | /Case insensitive/.
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
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)
287-- | Parse URL piece using @'Read'@ instance.
337-- | Parse URL piece using @'Read'@ instance.
@@ -442,8 +492,8 @@ instance FromHttpApiData Void where
442 parseUrlPiece _ = Left "Void cannot be parsed!"
492 parseUrlPiece _ = Left "Void cannot be parsed!"
445−instance FromHttpApiData Bool where parseUrlPiece = parseBoundedTextData
495+instance FromHttpApiData Bool where parseUrlPiece = parseBoundedUrlPiece
446−instance FromHttpApiData Ordering where parseUrlPiece = parseBoundedTextData
496+instance FromHttpApiData Ordering where parseUrlPiece = parseBoundedUrlPiece
447instance FromHttpApiData Double where parseUrlPiece = runReader rational
497instance FromHttpApiData Double where parseUrlPiece = runReader rational
448instance FromHttpApiData Float where parseUrlPiece = runReader rational
498instance FromHttpApiData Float where parseUrlPiece = runReader rational
449instance FromHttpApiData Int where parseUrlPiece = parseBounded (signed decimal)
499instance FromHttpApiData Int where parseUrlPiece = parseBounded (signed decimal)