packages feed

json-stream 0.4.5.0 → 0.4.5.1

raw patch · 5 files changed

+72/−24 lines, 5 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

Files

Data/JsonStream/Parser.hs view
@@ -92,7 +92,7 @@   , objectFound ) where -import Control.Applicative ( Alternative(..), optional )+import Control.Applicative ( Alternative(..), optional, Applicative (liftA2) ) import qualified Data.Aeson                  as AE import qualified Data.Aeson.Types            as AE import qualified Data.ByteString.Char8       as BS@@ -863,37 +863,30 @@   (Map.Map T.Text [()] -> [f]) -- ^ How to generate results from already parsed fields   deriving (Functor) --- We use unsafeCoerce to convert to () and back; we guarantee that there exists only--- one key to the map and so the original Parser will get the right type of value.--- This allows to drop the Typeable constraint, but the code better be OK here.+-- | Helper function for some parser combining operators+joinObjectFieldWith ::([a] -> [b] -> [c]) -> Object a -> Object b -> Object c+joinObjectFieldWith joinFunc (Object amap adata) (Object bmap bdata) =+  -- We MUST disallow duplicate field access as we do unsafeCoerce and that could lead to mixing types+  let dmap = Map.unionWithKey (\k _ _ -> error ("JStream Object - duplicate field access: " <> T.unpack k)) amap bmap+  in dmap `seq` Object dmap (\inp -> joinFunc (adata inp) (bdata inp))  instance Applicative Object where   pure f = Object mempty (const (pure f))-  (Object amap adata) <*> (Object bmap bdata) =-      let dmap = Map.unionWithKey (\k _ _ -> error ("JStream Object - duplicate field access: " <> T.unpack k)) amap bmap-      in dmap `seq` Object dmap dfunc-    where-      dfunc dmap = ($) <$> adata dmap <*> bdata dmap+  (<*>) = joinObjectFieldWith (liftA2 ($))  instance Alternative Object where   empty = Object mempty (const [])-  (Object amap adata) <|> (Object bmap bdata) =-      let dmap = Map.unionWithKey (\k _ _ -> error ("JStream Object - duplicate field access: " <> T.unpack k)) amap bmap-      in dmap `seq` Object dmap dfunc+  (<|>) = joinObjectFieldWith dfunc     where-      -- Return second one if first one generates nothing-      dfunc dmap =-        case adata dmap of-          [] -> bdata dmap-          lst -> lst+      dfunc [] bdata = bdata+      dfunc adata _ = adata  instance Semigroup (Object a) where-  (Object amap adata) <> (Object bmap bdata) =-      let dmap = Map.unionWithKey (\k _ _ -> error ("JStream Object - duplicate field access: " <> T.unpack k)) amap bmap-      in dmap `seq` Object dmap dfunc-    where-      -- Return second one if first one generates nothing-      dfunc dmap = adata dmap <> bdata dmap+  (<>) = joinObjectFieldWith (<>)++-- We use unsafeCoerce to convert to () and back; we guarantee that there exists only+-- one key to the map and so the original Parser will get the right type of value.+-- This allows to drop the Typeable constraint, but the code better be OK here.  -- | Similar to 'objectWithKey', generates a field-accessor in JSON object fastObjectWithKey :: forall a. T.Text -> Parser a -> Object a
Data/JsonStream/Unescape.hs view
@@ -2,6 +2,9 @@ {-# LANGUAGE ForeignFunctionInterface #-} {-# LANGUAGE MagicHash                #-} {-# LANGUAGE UnliftedFFITypes         #-}+{-# LANGUAGE BangPatterns         #-}+{-# LANGUAGE MultiWayIf         #-}+ {-# OPTIONS_GHC -Wno-unused-imports #-}  module Data.JsonStream.Unescape (
changelog.md view
@@ -1,3 +1,7 @@+# 0.4.5.1++- fixed testing suite+ # 0.4.5.0  - objectOf parser for faster one-pass JSON object parsing
json-stream.cabal view
@@ -1,5 +1,5 @@ name:                json-stream-version:             0.4.5.0+version:             0.4.5.1 synopsis:            Incremental applicative JSON parser description:         Easy to use JSON parser fully supporting incremental parsing.                      Parsing grammar in applicative form.@@ -77,6 +77,7 @@                        , text                        , aeson                        , vector+                       , containers                        , unordered-containers                        , hspec                        , scientific@@ -105,6 +106,7 @@                        , text                        , aeson                        , vector+                       , containers                        , unordered-containers                        , hspec                        , scientific
test/ParserSpec.hs view
@@ -119,6 +119,20 @@         msg = parseLazyByteString parser (BL.fromChunks test) :: [Int]     msg `shouldBe` [1] +  it "objectOf <|> returns first items even if second is in previous chunk" $ do+    let test = ["{\"error\":1, ", "\"values\":[2,3,4]}"]+        parser =  objectOf $ "values" .: arrayOf integer+                            <|> "error" .: integer+        msg = parseLazyByteString parser (BL.fromChunks test) :: [Int]+    msg `shouldBe` [2,3,4]+  it "objectOf <|> returns second item if first does not match" $ do+    let test = ["{\"error\":1, ", "\"values\":[true,null,false]}"]+        parser =  objectOf $ "values" .: arrayOf integer+                            <|> ("error" .: integer)+        msg = parseLazyByteString parser (BL.fromChunks test) :: [Int]+    msg `shouldBe` [1]++   it "arrayFound generates events" $ do     let test = ["[[1,2,3],true,[],false,{\"key\":1}]"]         parser = arrayOf (arrayFound 10 20 (1 .! integer))@@ -131,6 +145,12 @@         msg = parseLazyByteString parser (BL.fromChunks test) :: [Int]     msg `shouldBe` [10,1,20] +  it "objectOf objectFound generates events" $ do+    let test = ["[[1,2,3],true,[],false,{\"key\":1}]"]+        parser = arrayOf (objectFound 10 20 (objectOf $ "key" .: integer))+        msg = parseLazyByteString parser (BL.fromChunks test) :: [Int]+    msg `shouldBe` [10,1,20]+   it "Has working byteString parser" $ do     let test = ["[\"abcd\\n\\rxyz\"]"]         parser = arrayOf byteString :: Parser BS.ByteString@@ -282,6 +302,13 @@         res = parse parser test1 :: [(T.Text, Int)]     res `shouldBe` [("test1",1),("test2",-1),("test3",-1),("test4",-1)] +  it "objectOf $ binds correctly convenience operators" $ do+    let test1 = "[{\"name\": \"test1\", \"value\": 1}, {\"name\": \"test2\", \"value\": null}, {\"name\": \"test3\"}, {\"name\": \"test4\", \"value\": true}]"+        parser = arrayOf $ objectOf $ (,) <$> "name" .: string+                                          <*> "value" .: integer .| (-1)+        res = parse parser test1 :: [(T.Text, Int)]+    res `shouldBe` [("test1",1),("test2",-1),("test3",-1),("test4",-1)]+   it "binds correctly convenience operators 2" $ do     let test1 = "{\"key\":[{\"key2\":13}]}"         parser = "key" .: 0 .! "key2" .: integer@@ -298,6 +325,18 @@         res = parse parser test1 :: [Int]     res `shouldBe` [2] ++  it "objectOf $ binds correctly .| at the last moment" $ do+    let test1 = "{\"key3\":{}}"+        parser = objectOf $ "key-none" .: "key2" .: integer .| 2+        res = parse parser test1 :: [Int]+    res `shouldBe` [2]+  it "objectOf $ binds correct .| 2" $ do+    let test1 = "{\"key3\":{\"key2\": null}}"+        parser = objectOf $ "key-none" .: "key2" .: integer .| 2+        res = parse parser test1 :: [Int]+    res `shouldBe` [2]+   it "Parses correctly empty arrays:" $ do     let test1 = "[]"         parser = arrayOf $ many ("keys" .: arrayOf integer)@@ -308,6 +347,13 @@     let test1 = "[{\"name\":\"x\",\"key\":20}]"         onechar = BL.fromChunks $ map BS.singleton $ BS.unpack test1         parser = arrayOf $ "key" .: integer+        res = parseLazyByteString parser onechar :: [Int]+    res `shouldBe` [20]++  it "objectOf $ Parses correctly runs ignore parser on array:" $ do+    let test1 = "[{\"name\":\"x\",\"key\":20}]"+        onechar = BL.fromChunks $ map BS.singleton $ BS.unpack test1+        parser = arrayOf $ objectOf $ "key" .: integer         res = parseLazyByteString parser onechar :: [Int]     res `shouldBe` [20]