packages feed

csv-enumerator 0.8.2 → 0.9.0

raw patch · 3 files changed

+97/−47 lines, 3 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

+ Data.CSV.Enumerator: mapIntoHandle :: CSVeable r => CSVSettings -> Bool -> Handle -> (r -> IO [r]) -> Iteratee ByteString IO Int

Files

README.markdown view
@@ -81,11 +81,14 @@  ### TODO - Next Steps +* Refactor all operations to use iterCSV as the basic building block --+  in progress.+* The CSVeable typeclass can be refactored to have a more minimal definition.+* Get mapCSVFiles out of the typeclass if possible. * Need to think about specializing an Exception type for the library and   properly notifying the user when parsing-related problems occur. * Some operations can be further broken down to their atoms, increasing the   flexibility of the library.-* The CSVeable typeclass can be refactored to have a more minimal definition. * Operating on Text in addition to ByteString would be phenomenal. * A test-suite needs to be added. * Some benchmarking would be nice.
csv-enumerator.cabal view
@@ -1,5 +1,5 @@ Name:                csv-enumerator-Version:             0.8.2+Version:             0.9.0 Synopsis:            A flexible, fast, enumerator-based CSV parser library for Haskell.   Homepage:            http://github.com/ozataman/csv-enumerator License:             BSD3
src/Data/CSV/Enumerator.hs view
@@ -10,7 +10,6 @@   , MapRow      , CSVeable(..)-   , ParsedRow(..)     -- * CSV Setttings@@ -18,16 +17,23 @@   , defCSVSettings    -- * Reading / Writing CSV Files+  -- | These are some simple file-related operations for basic use cases.   , readCSVFile   , writeCSVFile   , appendCSVFile -  -- * Folding Over CSV Files -  -- | These enumerators generalize the map* family of functions with a running accumulator.+  -- * Generic Folds Over CSV Files+  -- | These operations enable you to do whatever you want with CSV files;+  -- including interleaved IO, etc.+  , foldCSVFile   , CSVAction   , funToIter   , funToIterIO +  -- * Mapping Over CSV Files+  , mapCSVFile+  , mapIntoHandle+   -- * Primitive Iteratees   , collectRows   , outputRowIter@@ -44,7 +50,7 @@  import Control.Applicative hiding (many) import Control.Exception (bracket, SomeException)-import Control.Monad (mzero, mplus, foldM, when)+import Control.Monad (mzero, mplus, foldM, when, liftM) import Control.Monad.IO.Class (liftIO, MonadIO) import qualified Data.ByteString as B import qualified Data.ByteString.Char8 as B8@@ -57,7 +63,6 @@  import Data.Attoparsec as P hiding (take) import qualified Data.Attoparsec.Char8 as C8--- import Data.Attoparsec.Enum import Data.Attoparsec.Enumerator import qualified Data.Enumerator as E import Data.Enumerator (($$), yield, continue)@@ -81,40 +86,14 @@           -> a           -> E.Iteratee B.ByteString IO a -  -- | Iteratee to push rows into a given file-  fileSink :: CSVSettings-           -> FilePath-           -> (Maybe Handle, Int)-           -> ParsedRow r-           -> E.Iteratee B.ByteString IO (Maybe Handle, Int) -  -- | Open & fold over the CSV file.  Processing starts on row 2 for MapRow-  -- instance to use first row as column headers.-  foldCSVFile :: FilePath -- ^ File to open as a CSV file-              -> CSVSettings -- ^ CSV settings to use on the input file-              -> CSVAction r a -- ^ Fold action-              -> a  -- ^ Initial accumulator-              -> IO (Either SomeException a) -- ^ Error or the resulting accumulator--  -- | Take a CSV file, apply function to each of its rows and save the-  -- resulting rows into a new file.-  ---  -- Each row is simply a list of fields.-  mapCSVFile :: FilePath         -- ^ Input file-             -> CSVSettings      -- ^ CSV Settings-             -> (r -> [r])       -- ^ A function to map a row onto rows-             -> FilePath         -- ^ Output file-             -> IO (Either SomeException Int)    -- ^ Number of rows processed -  mapCSVFile fi s f fo = do-    res <- foldCSVFile fi s iter (Nothing, 0)-    return $ snd `fmap` res-    where-      iter !acc (ParsedRow (Just !r)) = foldM chain acc (f r) -      iter !acc x = fileSink s fo acc x--      chain !acc !r = singleSink r acc--      singleSink !x !acc = fileSink s fo acc (ParsedRow (Just x))+  -- | Iteratee to push rows into a given file+  fileSink +    :: CSVSettings+    -> FilePath+    -> (Maybe Handle, Int)+    -> ParsedRow r+    -> E.Iteratee B.ByteString IO (Maybe Handle, Int)     ----------------------------------------------------------------------------@@ -152,11 +131,6 @@       comboIter acc' = procRow acc' >>= loop        -  foldCSVFile fp csvs f acc = E.run iter -    where-      iter = enumFile fp $$ iterCSV csvs f acc--   fileSink csvs fo = iter      where       iter :: (Maybe Handle, Int) @@ -237,9 +211,7 @@        toMapCSV !headers !fs = yield (fs >>= (Just . M.fromList . zip headers)) (E.Chunks []) -  foldCSVFile fp csvs f !acc = E.run (enumFile fp $$ iterCSV csvs f acc) -   fileSink s fo = mapIter     where       mapIter :: (Maybe Handle, Int) @@ -299,6 +271,42 @@   ------------------------------------------------------------------------------+-- | Open & fold over the CSV file.  +--+-- Processing starts on row 2 for MapRow instance to use first row as column+-- headers.+foldCSVFile +  :: (CSVeable r)+  => FilePath -- ^ File to open as a CSV file+  -> CSVSettings -- ^ CSV settings to use on the input file+  -> CSVAction r a -- ^ Fold action+  -> a  -- ^ Initial accumulator+  -> IO (Either SomeException a) -- ^ Error or the resulting accumulator+foldCSVFile fp csvs f acc = E.run (enumFile fp $$ iterCSV csvs f acc)+++------------------------------------------------------------------------------+-- | Take a CSV file, apply function to each of its rows and save the+-- resulting rows into a new file.+--+-- Each row is simply a list of fields.+mapCSVFile +  :: (CSVeable r)+  => FilePath         -- ^ Input file+  -> CSVSettings      -- ^ CSV Settings+  -> (r -> [r])       -- ^ A function to map a row onto rows+  -> FilePath         -- ^ Output file+  -> IO (Either SomeException Int)    -- ^ Number of rows processed +mapCSVFile fi s f fo = do+  res <- foldCSVFile fi s iter (Nothing, 0)+  return $ snd `fmap` res+  where+    iter !acc (ParsedRow (Just !r)) = foldM chain acc (f r) +    iter !acc x = fileSink s fo acc x+    chain !acc !r = fileSink s fo acc (ParsedRow (Just r))+++------------------------------------------------------------------------------ readCSVFile :: (CSVeable r) => CSVSettings  -- ^ CSV settings             -> FilePath   -- ^ FilePath             -> IO (Either SomeException [r])  -- ^ Collected data@@ -429,6 +437,45 @@   where     iterf !acc EOF = yield (f acc EOF) E.EOF     iterf !acc r = yield (f acc r) (E.Chunks [])++++------------------------------------------------------------------------------+-- | Create an iteratee that can map over a CSV stream and output results to+-- a handle in an interleaved fashion. +--+-- Example use: Let's map over a CSV file coming in through 'stdin' and push+-- results to 'stdout'.+--+-- > f r = return [r] -- a function that just returns the given row+--+-- > E.run (E.enumHandle 4096 stdin $$ mapIntoHandle defCSVSettings True stdout f)+--+-- This nicely allows us to do things like (assuming you have pv installed):+--+-- > pv inputFile.csv | myApp > output.CSV+--+-- And monitor the ongoing progress of processing.+mapIntoHandle +  :: (CSVeable r)+  => CSVSettings                  -- ^ 'CSVSettings'+  -> Bool                         -- ^ Whether to write headers+  -> Handle                       -- ^ Handle to stream results+  -> (r -> IO [r])                -- ^ Map function+  -> E.Iteratee ByteString IO Int -- ^ Resulting Iteratee+mapIntoHandle csvs outh h f = do+  snd `liftM` iterCSV csvs (funToIterIO f') (False,0)+  where+    f' acc EOF = return acc+    f' acc (ParsedRow Nothing) = return acc+    f' (False, _) r'@(ParsedRow (Just r)) = do+      rs <- f r+      when outh $ writeHeaders csvs h rs+      f' (True, 0) r'+    f' (True, !i) (ParsedRow (Just r)) = do+      rs <- f r+      outputRows csvs h rs+      return (True, i+1)   ------------------------------------------------------------------------------