pipes-csv (empty) → 1.0.0
raw patch · 4 files changed
+155/−0 lines, 4 filesdep +basedep +bytestringdep +cassavasetup-changed
Dependencies added: base, bytestring, cassava, pipes, text
Files
- LICENSE +21/−0
- Pipes/Csv.hs +105/−0
- Setup.hs +2/−0
- pipes-csv.cabal +27/−0
+ LICENSE view
@@ -0,0 +1,21 @@+The MIT License (MIT)++Copyright (c) 2013 William Casarin++Permission is hereby granted, free of charge, to any person obtaining a copy+of this software and associated documentation files (the "Software"), to deal+in the Software without restriction, including without limitation the rights+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+copies of the Software, and to permit persons to whom the Software is+furnished to do so, subject to the following conditions:++The above copyright notice and this permission notice shall be included in+all copies or substantial portions of the Software.++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN+THE SOFTWARE.
+ Pipes/Csv.hs view
@@ -0,0 +1,105 @@+{-| This module allows constant-space CSV parsing.++ It feeds 'ByteString's into cassavas incremental CSV parser to attain true+ constant-space record streaming.+-}++{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE OverloadedStrings #-}++module Pipes.Csv (+ feedParser,+ feedHeaderParser,+ decode,+ decodeWith,+ decodeByName,+ decodeByNameWith+) where++import qualified Data.Csv.Incremental as CI+import qualified Data.ByteString as B++import Data.Csv.Incremental (Parser(..), HeaderParser(..))+import Data.Csv (DecodeOptions, FromRecord,+ FromNamedRecord, defaultDecodeOptions)+import Data.ByteString (ByteString)+import Pipes++-- | Create a Record 'Producer' by feeding 'ByteString's into a 'Parser'+feedParser :: Monad m+ => Parser a+ -> Producer ByteString m ()+ -> Producer (Either String a) m ()+feedParser parser source = case parser of+ Fail _ e -> yield (Left e)+ Done es -> each es+ Some es k -> each es >> cont k source+ Partial k -> cont k source+ where+ cont = continue feedParser+++-- | Create a NamedRecord 'Producer' by feeding 'ByteString's into a 'Parser'+feedHeaderParser :: (Monad m, FromNamedRecord a)+ => HeaderParser (Parser a)+ -> Producer ByteString m ()+ -> Producer (Either String a) m ()+feedHeaderParser headerParser source = case headerParser of+ FailH bs e -> yield (Left e)+ PartialH k -> cont k source+ DoneH _ p -> feedParser p source+ where+ cont = continue feedHeaderParser+++-- | Handle continuations properly within a Producer+continue :: (Monad (t m), Monad m, MonadTrans t)+ => (a -> Producer ByteString m () -> t m b)+ -> (ByteString -> a)+ -> Producer ByteString m ()+ -> t m b+continue feed k producer = do+ x <- lift (next producer)+ case x of+ Left () -> feed (k B.empty) (return ())+ Right (bs, producer') ->+ if (B.null bs)+ then continue feed k producer'+ else feed (k bs) producer'++++-- | Equivalent to @'decodeWith' 'defaultDecodeOptions'@.+decode :: (Monad m, FromRecord a)+ => Bool+ -> Producer ByteString m ()+ -> Producer (Either String a) m ()+decode = decodeWith defaultDecodeOptions+++-- | Create a 'Producer' that takes a 'ByteString' 'Producer' as input,+-- producing either errors or 'FromRecord's.+decodeWith :: (Monad m, FromRecord a)+ => DecodeOptions+ -> Bool+ -> Producer ByteString m ()+ -> Producer (Either String a) m ()+decodeWith opts skipHeader src = feedParser (CI.decodeWith opts skipHeader) src+++-- | Equivalent to @'decodeByNameWith' 'defaultDecodeOptions'@.+decodeByName :: (Monad m, FromNamedRecord a)+ => Producer ByteString m ()+ => Producer (Either String a) m ()+decodeByName = decodeByNameWith defaultDecodeOptions+++-- | Create a 'Producer' that takes a 'ByteString' 'Producer' as input,+-- producing either errors or 'FromNamedRecord's.+decodeByNameWith :: (Monad m, FromNamedRecord a)+ => DecodeOptions+ -> Producer ByteString m ()+ -> Producer (Either String a) m ()+decodeByNameWith opts src = feedHeaderParser (CI.decodeByNameWith opts) src++
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ pipes-csv.cabal view
@@ -0,0 +1,27 @@+name: pipes-csv+version: 1.0.0+synopsis: Fast, streaming csv parser+license: MIT+license-file: LICENSE+author: William Casarin+maintainer: will@casarin.me+category: Pipes, CSV+build-type: Simple+cabal-version: >=1.10+Description:+ `pipes-csv` is a streaming csv parser built on top of `cassava` and `pipes`++source-repository head+ type: git+ location: https://github.com/jb55/pipes-csv++library+ ghc-options: -Wall -O2+ exposed-modules: Pipes.Csv+ build-depends: base >= 4.6 && < 4.7+ , text >= 0.11 && < 0.12+ , bytestring >= 0.10 && < 0.11+ , cassava >= 0.2 && < 0.3+ , pipes >= 4 && < 5+ default-language: Haskell2010+