hw-json 1.3.2.0 → 1.3.2.1
raw patch · 8 files changed
+187/−5 lines, 8 filesdep ~aesondep ~optparse-applicativePVP ok
version bump matches the API change (PVP)
Dependency ranges changed: aeson, optparse-applicative
API changes (from Hackage documentation)
Files
- README.md +10/−0
- examples/Example1.hs +17/−0
- examples/Example2.hs +17/−0
- examples/Example3.hs +24/−0
- examples/Example4.hs +53/−0
- hw-json.cabal +22/−5
- src/HaskellWorks/Data/Json/PartialValue.hs +22/−0
- src/HaskellWorks/Data/Json/Value.hs +22/−0
README.md view
@@ -11,8 +11,18 @@ ## Prerequisites * `cabal` version `2.2` or later+* Depending on your use case you may need additional package dependencies. These can be found in the library dependencies of the examples+ library component in the cabal file. ## Memory benchmark++If you need a repl to run any of the Haskell examples in this README, please run the command:++```bash+cabal v2-repl lib:examples+```++For rexamples these examples are also found in Haskell modules under the `examples` directory. ### Parsing large Json files in Scala with Argonaut
+ examples/Example1.hs view
@@ -0,0 +1,17 @@+{-# LANGUAGE BangPatterns #-}++{-# OPTIONS_GHC -fno-warn-unused-matches #-}+{-# OPTIONS_GHC -fno-warn-name-shadowing #-}+{-# OPTIONS_GHC -fno-warn-unused-local-binds #-}++module Example1 where++import Data.Aeson++import qualified Data.ByteString.Lazy as LBS++example :: IO ()+example = do+ !bs <- LBS.readFile "corpus/bench/hospitalisation.json"+ let !y = decode bs :: Maybe Value+ return ()
+ examples/Example2.hs view
@@ -0,0 +1,17 @@+{-# LANGUAGE BangPatterns #-}++{-# OPTIONS_GHC -fno-warn-unused-matches #-}+{-# OPTIONS_GHC -fno-warn-name-shadowing #-}+{-# OPTIONS_GHC -fno-warn-unused-local-binds #-}++module Example2 where++import qualified HaskellWorks.Data.ByteString as BS+import qualified HaskellWorks.Data.Json.Standard.Cursor.Fast as JCF++example :: IO ()+example = do+ !jsonBs <- BS.mmap "corpus/bench/hospitalisation.json"+ let !ibip = JCF.simdToIbBp jsonBs+ let !c = JCF.fromBsIbBp jsonBs ibip+ return ()
+ examples/Example3.hs view
@@ -0,0 +1,24 @@+{-# LANGUAGE OverloadedStrings #-}++{-# OPTIONS_GHC -fno-warn-unused-matches #-}+{-# OPTIONS_GHC -fno-warn-name-shadowing #-}+{-# OPTIONS_GHC -fno-warn-unused-local-binds #-}++module Example3 where++import Control.Monad++import qualified Data.ByteString as BS+import qualified HaskellWorks.Data.Json.Standard.Cursor.Fast as JCF+import qualified HaskellWorks.Data.TreeCursor as TC++example :: IO ()+example = do+ let fc = TC.firstChild+ let ns = TC.nextSibling+ let jsonBs = "[null, {\"field\": 1}]" :: BS.ByteString+ let ibip = JCF.simdToIbBp jsonBs+ let cursor = JCF.fromBsIbBp jsonBs ibip+ let _ = fc cursor+ let _ = (fc >=> ns) cursor+ return ()
+ examples/Example4.hs view
@@ -0,0 +1,53 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE OverloadedStrings #-}++{-# OPTIONS_GHC -fno-warn-unused-matches #-}+{-# OPTIONS_GHC -fno-warn-name-shadowing #-}+{-# OPTIONS_GHC -fno-warn-unused-local-binds #-}++module Example4 where++import Control.Monad+import Data.Function+import Data.List+import HaskellWorks.Data.Json.PartialValue+import HaskellWorks.Data.Json.Standard.Cursor.Load.Cursor+import HaskellWorks.Data.Json.Standard.Load.Partial+import HaskellWorks.Data.MQuery+import HaskellWorks.Data.MQuery.Micro++import qualified Data.DList as DL++example :: IO ()+example = do+ !cursor <- loadPartial "corpus/bench/78mb.json"+ !cursor <- loadCursorWithIndex "corpus/bench/78mb.json"+ !cursor <- loadCursor "corpus/bench/78mb.json"+ !cursor <- loadCursorWithCsPoppyIndex "corpus/bench/78mb.json"+ let !json = jsonPartialJsonValueAt cursor+ let q = MQuery (DL.singleton json)++ putPretty $ q >>= item & limit 10+ putPretty $ q >>= item & page 10 1+ putPretty $ q >>= item >>= hasKV "founded_year" (JsonPartialNumber 2005) & limit 10+ putPretty $ q >>= item >>= entry+ putPretty $ q >>= item >>= entry >>= named "name" & limit 10+ putPretty $ q >>= (item >=> entry >=> named "acquisition" >=> entry >=> named "price_currency_code")+ putPretty $ q >>= (item >=> entry >=> named "acquisition" >=> entry >=> named "price_currency_code") & onList (uniq . sort)+ putPretty $ q >>= (item >=> entry >=> named "acquisition" >=> entry >=> named "price_currency_code" >=> asString >=> valueOf "USD") & limit 10+ putPretty $ q >>= (item >=> entry >=> named "acquisition" >=> having (entry >=> named "price_currency_code" >=> asString >=> valueOf "USD") >=> entry >=> named "price_amount") & limit 10+ putPretty $ q >>= (item >=> entry >=> named "acquisition" >=> having (entry >=> named "price_currency_code" >=> asString >=> valueOf "USD") >=> entry >=> named "price_amount" >=> castAsInteger ) & limit 10+ putPretty $ q >>= (item >=> entry >=> named "acquisition" >=> having (entry >=> named "price_currency_code" >=> asString >=> valueOf "USD") >=> entry >=> named "price_amount" >=> castAsInteger ) & aggregate sum++ putPretty $ q >>= item & limit 10+ putPretty $ q >>= item & page 10 1+ putPretty $ q >>= item >>= entry+ putPretty $ q >>= item >>= entry >>= named "name" & limit 10+ putPretty $ q >>= (item >=> entry >=> named "acquisition" >=> entry >=> named "price_currency_code" >=> asString)+ putPretty $ q >>= (item >=> entry >=> named "acquisition" >=> entry >=> named "price_currency_code" >=> asString) & onList (uniq . sort)+ putPretty $ q >>= (item >=> entry >=> named "acquisition" >=> entry >=> named "price_currency_code" >=> asString >=> valueOf "USD") & limit 10+ putPretty $ q >>= (item >=> entry >=> named "acquisition" >=> having (entry >=> named "price_currency_code" >=> asString >=> valueOf "USD") >=> entry >=> named "price_amount") & limit 10+ putPretty $ q >>= (item >=> entry >=> named "acquisition" >=> having (entry >=> named "price_currency_code" >=> asString >=> valueOf "USD") >=> entry >=> named "price_amount" >=> castAsInteger ) & limit 10+ putPretty $ q >>= (item >=> entry >=> named "acquisition" >=> having (entry >=> named "price_currency_code" >=> asString >=> valueOf "USD") >=> entry >=> named "price_amount" >=> castAsInteger ) & aggregate sum++ return ()
hw-json.cabal view
@@ -1,7 +1,7 @@ cabal-version: 2.2 name: hw-json-version: 1.3.2.0+version: 1.3.2.1 synopsis: Memory efficient JSON parser description: Memory efficient JSON parser. Please see README.md category: Data@@ -50,10 +50,10 @@ common dlist { build-depends: dlist >= 0.8 && < 0.9 } common doctest { build-depends: doctest >= 0.16.2 && < 0.17 } common doctest-discover { build-depends: doctest-discover >= 0.2 && < 0.3 }-common generic-lens { build-depends: generic-lens >= 1.2.0.1 && < 1.3 }+common generic-lens { build-depends: generic-lens >= 1.2.0.1 && < 2.1 } common hedgehog { build-depends: hedgehog >= 0.6 && < 1.1 } common hspec { build-depends: hspec >= 2.4 && < 3 }-common hw-balancedparens { build-depends: hw-balancedparens >= 0.3.0.0 && < 0.4 }+common hw-balancedparens { build-depends: hw-balancedparens >= 0.3.0.0 && < 0.5 } common hw-bits { build-depends: hw-bits >= 0.7.0.5 && < 0.8 } common hw-hspec-hedgehog { build-depends: hw-hspec-hedgehog >= 0.1.0.4 && < 0.2 } common hw-json-simd { build-depends: hw-json-simd >= 0.1.0.2 && < 0.2 }@@ -169,6 +169,7 @@ , aeson , attoparsec , bytestring+ , dlist , hedgehog , hspec , hw-balancedparens@@ -177,6 +178,7 @@ , hw-json , hw-json-simple-cursor , hw-json-standard-cursor+ , hw-mquery , hw-prim , hw-rankselect , hw-rankselect-base@@ -197,6 +199,21 @@ HaskellWorks.Data.Json.TypeSpec HaskellWorks.Data.Json.ValueSpec +library examples+ import: base, config+ , aeson+ , bytestring+ , dlist+ , hw-json+ , hw-json-standard-cursor+ , hw-mquery+ , hw-prim+ hs-source-dirs: examples+ other-modules: Example1+ Example2+ Example3+ Example4+ benchmark bench import: base, config , bytestring@@ -209,14 +226,14 @@ main-is: Main.hs hs-source-dirs: bench -test-suite hw-json-doctest+test-suite doctest import: base, config , doctest , doctest-discover , hw-json default-language: Haskell2010 type: exitcode-stdio-1.0- ghc-options: -threaded+ ghc-options: -threaded -rtsopts -with-rtsopts=-N main-is: DoctestDriver.hs HS-Source-Dirs: doctest build-tool-depends: doctest-discover:doctest-discover
src/HaskellWorks/Data/Json/PartialValue.hs view
@@ -48,6 +48,19 @@ import qualified Data.Text as T import qualified HaskellWorks.Data.BalancedParens as BP +-- | Partial JSON type.+--+-- This data type has an additional 'JsonPartialError' data constructor to indicate parsing+-- errors. This allows parsing to be more lazy because parsing errors may now be expressed+-- anywhere in the parsed document so the parser no longer needs to make a verdict about whether+-- there are any parsing errors in the entire document.+--+-- See 'jsonPartialJsonValueAt' on how to parse JSON text into this datatype.+--+-- Although this data type allows for lazier parsing it doesn't allow for sub-trees to be+-- garbage collected if a reference to an ancestor node is held. To avoid holding onto+-- sub-trees that are no longer needed without having to drop references to ancestors use+-- 'HaskellWorks.Data.Json.LightJson.LightJson' instead. data JsonPartialValue = JsonPartialString Text | JsonPartialNumber Double@@ -59,6 +72,15 @@ deriving (Eq, Show, Ord) class JsonPartialValueAt a where+ -- | Get a JSON partial value from another type+ --+ -- This function can always "succeed" because the data type it returns allows for the document value+ -- to contain an arbitrary number of errors. This means errors can be reported in document nodes+ -- as parsing occurs lazily.+ --+ -- There are garbage collection implementations you may want to consider. If you would like to be+ -- able to hold onto ancestor nodes and still be able to garbage collect visited sub-trees, then+ -- consider using 'HaskellWorks.Data.Json.LightJson.lightJsonAt' instead. jsonPartialJsonValueAt :: a -> JsonPartialValue data JsonPartialField = JsonPartialField Text JsonPartialValue
src/HaskellWorks/Data/Json/Value.hs view
@@ -15,6 +15,17 @@ import qualified Data.ByteString as BS import qualified Data.Text as T +-- | Traditional JSON type.+--+-- This type has the a constructor per JSON data type as is typical for JSON in most libraries.+--+-- See 'jsonValueAt' on how to parse JSON text into this datatype.+--+-- Although Haskell data types are lazy by default, you will not get a fully lazy data structure+-- when parsing to this type because there is no way to express parsing errors in this datatype.+--+-- For a data type that gives you lazier behaviour, see other alternatives such as+-- 'HaskellWorks.Data.Json.PartialValue.JsonPartialValue' or 'HaskellWorks.Data.Json.LightJson.LightJson'. data JsonValue = JsonString Text | JsonNumber Double@@ -25,6 +36,17 @@ deriving (Eq, Show) class JsonValueAt a where+ -- | Get a JSON value from another type+ --+ -- The @hw-json@ library does not do full JSON validation for efficiency reasons, but parsing can+ -- fail if the JSON is malformed. When parsing fails, then 'Left' will be returned.+ --+ -- If 'Right' is returned then that means there are no parsing failures, which implies "knowing"+ -- that there parsing failures in the entire document, which implies that pattern matching on+ -- 'Right' evaluates the entire document.+ --+ -- This limits the laziness of the JSON parsing. For lazier alternatives, see+ -- 'HaskellWorks.Data.Json.PartialValue.jsonPartialJsonValueAt' or 'HaskellWorks.Data.Json.LightJson.lightJsonAt'. jsonValueAt :: a -> Either DecodeError JsonValue instance JsonValueAt JsonIndex where