packages feed

pa-field-parser 0.2.0.1 → 0.3.0.0

raw patch · 3 files changed

+44/−14 lines, 3 filesdep ~pa-preludePVP ok

version bump matches the API change (PVP)

Dependency ranges changed: pa-prelude

API changes (from Hackage documentation)

- FieldParser: jsonParser :: Monad m => FieldParser' err Value to -> ParseT err m to
+ FieldParser: toJsonParser :: Monad m => FieldParser' err Value to -> ParseT err m to
+ FieldParser: utcTimeLenient :: FieldParser Text UTCTime

Files

CHANGELOG.md view
@@ -1,5 +1,10 @@ # Revision history for pa-field-parser +## 0.3.0.0 -- 2023-10-15++- rename `jsonParser` to `toJsonParser`+- add `utcTimeLenient`+ ## 0.2.0.0 -- 2023-07-28  - Add a few parsers
pa-field-parser.cabal view
@@ -1,7 +1,7 @@ cabal-version:      3.0 -- !!! ATTN: file autogenerated from pa-template.cabal.mustache on toplevel !!! name:               pa-field-parser-version:            0.2.0.1+version:            0.3.0.0 synopsis:           “Vertical” parsing of values description:         license:            BSD-3-Clause@@ -72,7 +72,7 @@     hs-source-dirs:   src     build-depends:       base <5,-      pa-prelude,+      pa-prelude >= 0.2.0.0,       pa-error-tree,       aeson-better-errors,       aeson,
src/FieldParser.hs view
@@ -17,7 +17,6 @@ import Data.Fixed qualified as Fixed import Data.List.NonEmpty qualified as NonEmpty import Data.Map.Strict qualified as Map-import Data.Scientific (Scientific) import Data.Scientific qualified as Scientific import Data.Semigroup.Foldable (Foldable1 (toNonEmpty)) import Data.Semigroupoid qualified as Semigroupoid@@ -83,7 +82,7 @@ toParseJSON parser =   Json.toAesonParser     prettyError-    (jsonParser parser)+    (toJsonParser parser)  -- | Turn a @FieldParser' ErrorTree Value@ directly into a valid 'parseJSON` implementation. --@@ -95,7 +94,7 @@ toParseJSONErrorTree parser =   Json.toAesonParser     prettyErrorTree-    (jsonParser parser)+    (toJsonParser parser)  toReadPrec ::   -- | ReadPrec to base this parser on (e.g. use @readPrec \@Text@@ to parse the same as Text)@@ -109,8 +108,8 @@     Right a -> pure a  -- | Turn a @FieldParser Value@ into an 'Json.ParseT` which parses this value.-jsonParser :: Monad m => FieldParser' err Json.Value to -> Json.ParseT err m to-jsonParser parser =+toJsonParser :: (Monad m) => FieldParser' err Json.Value to -> Json.ParseT err m to+toJsonParser parser =   ( Json.asValue       >>= ( \from ->               runFieldParser parser from & \case@@ -191,12 +190,12 @@     Cat.>>> integralToNatural @Integer  -- | Parse any integral into a natural number, fails if the integral is negative.-integralToNatural :: Integral i => FieldParser i Natural+integralToNatural :: (Integral i) => FieldParser i Natural integralToNatural =   FieldParser (\i -> i & intToNatural & annotate [fmt|Number must be 0 or positive, but was negative: {toInteger i}|])  -- | Parse any integral to an 'Integer'. This can never fail, but is here to mirror 'integralToNatural'.-integralToInteger :: Integral i => FieldParser' err i Integer+integralToInteger :: (Integral i) => FieldParser' err i Integer integralToInteger = lmap (fromIntegral @_ @Integer) Cat.id  -- | An arbitrary-precision number in scientific notation.@@ -227,7 +226,7 @@ -- * don’t wrap around the bound -- * don’t fill up all our memory -- * Fit into the available floating point representation space-boundedScientificRealFloat :: RealFloat d => FieldParser Scientific d+boundedScientificRealFloat :: (RealFloat d) => FieldParser Scientific d boundedScientificRealFloat = FieldParser $ \s ->   Scientific.toBoundedRealFloat s     & first@@ -269,7 +268,8 @@         & textToString         & Time.Format.ISO.iso8601ParseM @Maybe @Time.Day --- | @yyyy-mm-ddThh:mm:ss[.sss]Z@ (ISO 8601:2004(E) sec. 4.3.2 extended format)+-- | Parse a timestamp into a UTC time, accepting only UTC timestamps like+-- @yyyy-mm-ddThh:mm:ss[.sss]Z@ (ISO 8601:2004(E) sec. 4.3.2 extended format) utcTime :: FieldParser Text Time.UTCTime utcTime =   FieldParser $ \t ->@@ -283,6 +283,31 @@         & textToString         & Time.Format.ISO.iso8601ParseM @Maybe @Time.UTCTime +-- | Parse a timestamp into a UTC time, accepting multiple timezone formats.+-- Do not use this if you can force the input to use the `Z` UTC notation (e.g. in a CSV), use 'utcTime' instead.+--+-- Accepts+--+-- * UTC timestamps: @yyyy-mm-ddThh:mm:ss[.sss]Z@+-- * timestamps with time zone: @yyyy-mm-ddThh:mm:ss[.sss]±hh:mm@+--+-- ( both ISO 8601:2004(E) sec. 4.3.2 extended format)+--+-- The time zone of the second kind of timestamp is taken into account, but normalized to UTC (it’s not preserved what the original time zone was)+utcTimeLenient :: FieldParser Text Time.UTCTime+utcTimeLenient =+  FieldParser $ \t ->+    case (t & parseTime @Time.UTCTime)+      <|> (t & parseTime @Time.ZonedTime <&> Time.zonedTimeToUTC) of+      Nothing -> Left $ [fmt|Not a valid date of format `yyyy-mm-ddThh:mm:ss[.sss]Z` or `@yyyy-mm-ddThh:mm:ss[.sss]±hh:mm@` (ISO 8601:2004(E) sec. 4.3.2 extended format): "{t}"|]+      Just day -> Right day+  where+    parseTime :: (Time.Format.ISO.ISO8601 t) => Text -> Maybe t+    parseTime t =+      t+        & textToString+        & Time.Format.ISO.iso8601ParseM+ -- | Example of how to create a more “complicated” parser that checks whether a value -- is between two other values. clamped ::@@ -307,7 +332,7 @@ -- If you want to match on an 'Enum'-like type, -- you should probably use 'invertPretty' or 'invertPrettyCaseInsensitive' instead, -- which allows for exhaustiveness checks.-oneOf :: Ord from => (from -> Text) -> [(from, to)] -> FieldParser from to+oneOf :: (Ord from) => (from -> Text) -> [(from, to)] -> FieldParser from to oneOf errDisplay m =   -- This doesn’t strictly need an 'Ord' instance, it can also use `findMaybe` with `==` instead of going through a map.   oneOfMap errDisplay (Map.fromList m)@@ -398,7 +423,7 @@     & lmap CaseInsensitive.mk  -- | 'oneOf' but only one value possible-exactly :: Eq from => (from -> Text) -> from -> FieldParser from from+exactly :: (Eq from) => (from -> Text) -> from -> FieldParser from from exactly errDisplay from = FieldParser $ \from' ->   if from == from'     then Right from'@@ -534,7 +559,7 @@ -- ATTN: This needs an instance of the 'TH.Lift' class for the output type. -- Many library types don’t yet implement this class, so we have to provide the instances ourselves. -- See NOTE: Lift for library types-literal :: forall from to. TH.Lift to => FieldParser from to -> from -> TH.Code TH.Q to+literal :: forall from to. (TH.Lift to) => FieldParser from to -> from -> TH.Code TH.Q to literal parser s = do   case runFieldParser parser s of     Right a -> [||a||]