packages feed

sv-cassava (empty) → 0.1

raw patch · 6 files changed

+241/−0 lines, 6 filesdep +HUnitdep +attoparsecdep +basesetup-changed

Dependencies added: HUnit, attoparsec, base, bytestring, cassava, sv, sv-cassava, text, utf8-string, validation, vector

Files

+ LICENCE view
@@ -0,0 +1,31 @@+Copyright (c) 2017-2018, Commonwealth Scientific and Industrial Research Organisation+(CSIRO) ABN 41 687 119 230.++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++    * Redistributions of source code must retain the above copyright+      notice, this list of conditions and the following disclaimer.++    * Redistributions in binary form must reproduce the above+      copyright notice, this list of conditions and the following+      disclaimer in the documentation and/or other materials provided+      with the distribution.++    * Neither the name of QFPL nor the names of other+      contributors may be used to endorse or promote products derived+      from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ changelog.md view
@@ -0,0 +1,5 @@+# Revision history for sv-cassava++## 0.1  -- 2018-03-14++* First version. Released on an unsuspecting world.
+ src/Data/Sv/Cassava.hs view
@@ -0,0 +1,73 @@+{-|+Module      : Data.Sv.Cassava+Copyright   : (C) CSIRO 2017-2018+License     : BSD3+Maintainer  : George Wilson <george.wilson@data61.csiro.au>+Stability   : experimental+Portability : non-portable++This module provides integration between sv and cassava.+It lets you plug cassava's (very fast!) parser into sv's decoding layer.++Our benchmarking indicates that parsing is very expensive,+while decoding is comparatively less performance-sensitive.+So if performance matters to you, and cassava's parser is sufficient for+your needs, you might as well use it!++sv's own parser is much slower than cassava's right now, but aims to have+better error messages and keep more information for you to work with, such as+spacing, quoting, and newline information.+-}++module Data.Sv.Cassava (+  parseDecodeFromCassava+, parseCassava+, decodeFromCassava+) where++import Data.Attoparsec.ByteString (parseOnly)+import Data.ByteString (ByteString)+import Data.ByteString.UTF8 as UTF8+import qualified Data.Csv as Cassava+import qualified Data.Csv.Parser as Cassava+import Data.Maybe (mapMaybe)+import Data.Sv+import qualified Data.Sv.Decode as D+import Data.Vector (Vector, (!?))+import Data.Vector.NonEmpty (NonEmptyVector (NonEmptyVector))+import qualified Data.Vector as V+import Text.Escape (Unescaped (Unescaped))+import Text.Space (unspaced)+import Text.Quote (Quote (DoubleQuote))++-- | Use an sv 'Decode' to decode from cassava's 'Cassava.Csv' type.+decodeFromCassava :: Decode' ByteString a -> Cassava.Csv -> DecodeValidation ByteString [a]+decodeFromCassava d =+  traverse (D.promote d) . fs2r . V.toList+    where+      fs2r :: [Vector Cassava.Field] -> [Record ByteString]+      fs2r = mapMaybe (fmap (Record . fmap (unspaced . Quoted DoubleQuote . Unescaped)) . vec2nev)+      vec2nev :: Vector b -> Maybe (NonEmptyVector b)+      vec2nev v = NonEmptyVector <$> v !? 0 <*> pure (V.drop 1 v)++-- | Parse a 'Cassava.Csv' from a 'ByteString' using cassava's parser+--+-- This returns its result in a 'DecodeValidation', so that it's compatible+-- with the rest of sv.+parseCassava :: Cassava.DecodeOptions -> ByteString -> DecodeValidation ByteString Cassava.Csv+parseCassava opts =+  D.validateEither' (BadParse . UTF8.fromString) . parseOnly (Cassava.csv opts)++-- | Parse a 'Cassava.Csv' from a 'ByteString' using cassava's parser, then+-- decode it using the given 'Decode'.+--+-- This has the benefit of letting you use cassava's parser, which is very fast,+-- with sv's decoding.+parseDecodeFromCassava :: Decode' ByteString a -> Headedness -> Cassava.DecodeOptions -> ByteString -> DecodeValidation ByteString [a]+parseDecodeFromCassava d h opts bs =+  (chompFirst h <$> parseCassava opts bs) `bindValidation` decodeFromCassava d+    where+      -- The csv returned from cassava's parser may include a header row.+      -- If it does, we want to skip that row.+      chompFirst Headed   = V.drop 1+      chompFirst Unheaded = id
+ sv-cassava.cabal view
@@ -0,0 +1,58 @@+-- Initial sv-cassava.cabal generated by cabal init.  For further +-- documentation, see http://haskell.org/cabal/users-guide/++name:                sv-cassava+version:             0.1+synopsis:            Integration to use sv with cassava's parser+description:+  This package provides functions allowing you to use cassava's parser+  together with sv's decoding. You might prefer this to using sv's own+  parser if speed is a significant concern.+homepage:            https://github.com/qfpl/sv+license:             BSD3+license-file:        LICENCE+author:              George Wilson+maintainer:          george@wils.online+copyright:           Copyright (c) 2017-2018, Commonwealth Scientific and Industrial Research Organisation (CSIRO) ABN 41 687 119 230.+category:            CSV, Text, Web+build-type:          Simple+extra-source-files:  changelog.md+cabal-version:       >=1.10++library+  exposed-modules:+    Data.Sv.Cassava+  build-depends:+    attoparsec >= 0.12.1.4 && < 0.14+    , base >=4.8 && <5+    , bytestring >= 0.9.1.10 && < 0.11+    , cassava >= 0.4.1 && < 0.6+    , sv >= 0.1 && < 0.2+    , utf8-string >= 1 && < 1.1+    , vector >= 0.10 && < 0.13+  hs-source-dirs:+    src+  default-language:+    Haskell2010++test-suite hunit+  type:+    exitcode-stdio-1.0+  main-is:+    tests.hs+  default-language:+    Haskell2010+  build-depends:+    base >=4.8 && <5+    , bytestring >= 0.9.1.10 && < 0.11+    , cassava >= 0.4.1 && < 0.6+    , sv >= 0.1 && < 0.2+    , sv-cassava+    , HUnit >= 1.4 && < 1.7+    , text >= 1.0 && < 1.3+    , validation >= 1 && < 1.1+    , vector >= 0.10 && < 0.13+  ghc-options:+    -Wall+  hs-source-dirs:+    tests
+ tests/tests.hs view
@@ -0,0 +1,72 @@+{-# LANGUAGE OverloadedStrings #-}++module Main (main) where++import Control.Monad (when)+import Data.ByteString (ByteString)+import qualified Data.Csv as Cassava+import Data.Sv+import Data.Sv.Cassava+import qualified Data.Sv.Decode as D+import Data.Text (Text)+import qualified Data.Vector as V+import System.Exit (exitFailure)+import Test.HUnit++data TestRow = TestRow Int Double Text deriving (Eq, Show)++testRowDec :: Decode' ByteString TestRow+testRowDec = TestRow <$> D.int <*> D.double <*> D.utf8++bs1 :: ByteString+bs1 = mconcat+  [ "1,5.5,hello\n"+  , "2,-3.54,\n"+  , "3,42.0,\"Text in quotes\"\n"+  ]++bs2 :: ByteString+bs2 = hdr `mappend` bs1+  where+    hdr = "id, number, name\n"++csv1 :: Cassava.Csv+csv1 = V.fromList . fmap V.fromList $+  [ ["1","5.5","hello"]+  , ["2","-3.54", ""]+  , ["3", "42.0", "Text in quotes"]+  ]++decoded1 :: [TestRow]+decoded1 =+  [ TestRow 1 5.5 "hello"+  , TestRow 2 (-3.54) ""+  , TestRow 3 42 "Text in quotes"+  ]++parseTest :: Test+parseTest = TestLabel "parse" . TestCase $+  parseCassava Cassava.defaultDecodeOptions bs1 @?= pure csv1++decodeTest :: Test+decodeTest = TestLabel "decode" . TestCase $+  decodeFromCassava testRowDec csv1 @?= pure decoded1++parseDecodeTest :: Test+parseDecodeTest = TestLabel "parse+decode" . TestList $+  [ TestLabel "unheaded" . TestCase $+      parseDecodeFromCassava testRowDec Unheaded Cassava.defaultDecodeOptions bs1 @?=+        pure decoded1+  , TestLabel "headed" . TestCase $+      parseDecodeFromCassava testRowDec Headed Cassava.defaultDecodeOptions bs2 @?=+        pure decoded1+  ]++tests :: Test+tests = TestList [parseTest, decodeTest, parseDecodeTest]++main :: IO ()+main = do+  cs <- runTestTT tests+  when (errors cs > 0 || failures cs > 0)+    exitFailure