http-api-data 0.3.6 → 0.3.7
raw patch · 4 files changed
+63/−22 lines, 4 filesdep +attoparsecdep +attoparsec-iso8601dep ~bytestring
Dependencies added: attoparsec, attoparsec-iso8601
Dependency ranges changed: bytestring
Files
- CHANGELOG.md +11/−0
- http-api-data.cabal +4/−2
- src/Web/Internal/HttpApiData.hs +39/−17
- test/Web/Internal/HttpApiDataSpec.hs +9/−3
CHANGELOG.md view
@@ -1,3 +1,14 @@+0.3.7+---++* Minor changes:+ * Use [`attoparsec-iso8601`](http://hackage.haskell.org/package/attoparsec-iso8601)+ for parsing of time types. Now the accepted formats are the same as by `aeson`,+ i.e. parsers are more lenient+ (see [#41](https://github.com/fizruk/http-api-data/pull/41));+ * Preserve fractions of a second in `ToHttpApiData` instances (see [#53](https://github.com/fizruk/http-api-data/pull/53));+ * Add `ToHttpApiData` and `FromHttpApiData` instances for `TimeOfDay` (see [#53](https://github.com/fizruk/http-api-data/pull/53)).+ 0.3.6 ---
http-api-data.cabal view
@@ -1,5 +1,5 @@ name: http-api-data-version: 0.3.6+version: 0.3.7 license: BSD3 license-file: LICENSE author: Nickolay Kudasov <nickolay.kudasov@gmail.com>@@ -37,7 +37,9 @@ library hs-source-dirs: src/ include-dirs: include/- build-depends: base >= 4.7 && < 4.10+ build-depends: base >= 4.7 && < 4.10+ , attoparsec >= 0.13.0.1 && < 0.14+ , attoparsec-iso8601 >= 1.0.0.0 && < 1.1 , bytestring , containers , hashable
src/Web/Internal/HttpApiData.hs view
@@ -58,7 +58,10 @@ import qualified Data.ByteString.Builder as BS import qualified Network.HTTP.Types as H +import qualified Data.Attoparsec.Text as Atto+import qualified Data.Attoparsec.Time as Atto + -- $setup -- >>> data BasicAuthToken = BasicAuthToken Text deriving (Show) -- >>> instance FromHttpApiData BasicAuthToken where parseHeader h = BasicAuthToken <$> parseHeaderWithPrefix "Basic " h; parseQueryParam p = BasicAuthToken <$> parseQueryParam p@@ -453,24 +456,31 @@ timeToUrlPiece fmt = T.pack . formatTime defaultTimeLocale (iso8601DateFormat (Just fmt)) -- |--- >>> toUrlPiece $ LocalTime (fromGregorian 2015 10 03) (TimeOfDay 14 55 01)--- "2015-10-03T14:55:01"+-- >>> toUrlPiece $ TimeOfDay 14 55 23.1+-- "14:55:23.1"+instance ToHttpApiData TimeOfDay where+ toUrlPiece = T.pack . formatTime defaultTimeLocale "%H:%M:%S%Q"+ toEncodedUrlPiece = unsafeToEncodedUrlPiece++-- |+-- >>> toUrlPiece $ LocalTime (fromGregorian 2015 10 03) (TimeOfDay 14 55 21.687)+-- "2015-10-03T14:55:21.687" instance ToHttpApiData LocalTime where- toUrlPiece = timeToUrlPiece "%H:%M:%S"+ toUrlPiece = timeToUrlPiece "%H:%M:%S%Q" toEncodedUrlPiece = unsafeToEncodedUrlPiece -- |--- >>> toUrlPiece $ ZonedTime (LocalTime (fromGregorian 2015 10 03) (TimeOfDay 14 55 01)) utc--- "2015-10-03T14:55:01+0000"+-- >>> toUrlPiece $ ZonedTime (LocalTime (fromGregorian 2015 10 03) (TimeOfDay 14 55 51.001)) utc+-- "2015-10-03T14:55:51.001+0000" instance ToHttpApiData ZonedTime where- toUrlPiece = timeToUrlPiece "%H:%M:%S%z"+ toUrlPiece = timeToUrlPiece "%H:%M:%S%Q%z" toEncodedUrlPiece = unsafeToEncodedUrlPiece -- |--- >>> toUrlPiece $ UTCTime (fromGregorian 2015 10 03) 864--- "2015-10-03T00:14:24Z"+-- >>> toUrlPiece $ UTCTime (fromGregorian 2015 10 03) 864.5+-- "2015-10-03T00:14:24.5Z" instance ToHttpApiData UTCTime where- toUrlPiece = timeToUrlPiece "%H:%M:%SZ"+ toUrlPiece = timeToUrlPiece "%H:%M:%S%QZ" toEncodedUrlPiece = unsafeToEncodedUrlPiece instance ToHttpApiData NominalDiffTime where@@ -577,27 +587,30 @@ -- | -- >>> toGregorian <$> parseUrlPiece "2016-12-01" -- Right (2016,12,1)-instance FromHttpApiData Day where parseUrlPiece = readTextData+instance FromHttpApiData Day where parseUrlPiece = runAtto Atto.day -timeParseUrlPiece :: ParseTime t => String -> Text -> Either Text t-timeParseUrlPiece fmt = parseMaybeTextData (timeParseUrlPieceMaybe . T.unpack)- where- timeParseUrlPieceMaybe = parseTime defaultTimeLocale (iso8601DateFormat (Just fmt))+-- |+-- >>> parseUrlPiece "14:55:01.333" :: Either Text TimeOfDay+-- Right 14:55:01.333+instance FromHttpApiData TimeOfDay where parseUrlPiece = runAtto Atto.timeOfDay -- | -- >>> parseUrlPiece "2015-10-03T14:55:01" :: Either Text LocalTime -- Right 2015-10-03 14:55:01-instance FromHttpApiData LocalTime where parseUrlPiece = timeParseUrlPiece "%H:%M:%S"+instance FromHttpApiData LocalTime where parseUrlPiece = runAtto Atto.localTime -- | -- >>> parseUrlPiece "2015-10-03T14:55:01+0000" :: Either Text ZonedTime -- Right 2015-10-03 14:55:01 +0000-instance FromHttpApiData ZonedTime where parseUrlPiece = timeParseUrlPiece "%H:%M:%S%z"+--+-- >>> parseQueryParam "2016-12-31T01:00:00Z" :: Either Text ZonedTime+-- Right 2016-12-31 01:00:00 +0000+instance FromHttpApiData ZonedTime where parseUrlPiece = runAtto Atto.zonedTime -- | -- >>> parseUrlPiece "2015-10-03T00:14:24Z" :: Either Text UTCTime -- Right 2015-10-03 00:14:24 UTC-instance FromHttpApiData UTCTime where parseUrlPiece = timeParseUrlPiece "%H:%M:%SZ"+instance FromHttpApiData UTCTime where parseUrlPiece = runAtto Atto.utcTime instance FromHttpApiData NominalDiffTime where parseUrlPiece = fmap fromInteger . parseUrlPiece @@ -650,3 +663,12 @@ parseUrlPiece = Right . LenientData . parseUrlPiece parseHeader = Right . LenientData . parseHeader parseQueryParam = Right . LenientData . parseQueryParam++-------------------------------------------------------------------------------+-- Attoparsec helpers+-------------------------------------------------------------------------------++runAtto :: Atto.Parser a -> Text -> Either Text a+runAtto p t = case Atto.parseOnly (p <* Atto.endOfInput) t of+ Left err -> Left (T.pack err)+ Right x -> Right x
test/Web/Internal/HttpApiDataSpec.hs view
@@ -76,6 +76,7 @@ checkUrlPiece (Proxy :: Proxy T.Text) "Text.Strict" checkUrlPiece (Proxy :: Proxy L.Text) "Text.Lazy" checkUrlPiece (Proxy :: Proxy Day) "Day"+ checkUrlPiece' timeOfDayGen "TimeOfDay" checkUrlPiece' localTimeGen "LocalTime" checkUrlPiece' zonedTimeGen "ZonedTime" checkUrlPiece' utcTimeGen "UTCTime"@@ -112,6 +113,7 @@ checkEncodedUrlPiece (Proxy :: Proxy T.Text) "Text.Strict" checkEncodedUrlPiece (Proxy :: Proxy L.Text) "Text.Lazy" checkEncodedUrlPiece (Proxy :: Proxy Day) "Day"+ checkEncodedUrlPiece' timeOfDayGen "TimeOfDay" checkEncodedUrlPiece' localTimeGen "LocalTime" checkEncodedUrlPiece' zonedTimeGen "ZonedTime" checkEncodedUrlPiece' utcTimeGen "UTCTime"@@ -144,9 +146,13 @@ -- TODO: this generators don't generate full range items localTimeGen :: Gen LocalTime-localTimeGen = LocalTime- <$> arbitrary- <*> liftA3 TimeOfDay (choose (0, 23)) (choose (0, 59)) (fromInteger <$> choose (0, 60))+localTimeGen = LocalTime <$> arbitrary <*> timeOfDayGen++timeOfDayGen :: Gen TimeOfDay+timeOfDayGen = TimeOfDay+ <$> choose (0, 23)+ <*> choose (0, 59)+ <*> fmap (\x -> 0.1 * fromInteger x) (choose (0, 600)) zonedTimeGen :: Gen ZonedTime zonedTimeGen = ZonedTime