From 5c74085ada3723fdadcf7ef27ab51ccfbb8d88b1 Mon Sep 17 00:00:00 2001 From: Jonathan Lamothe Date: Sun, 24 Apr 2022 16:04:10 -0400 Subject: [PATCH] implemented encodeCSV and encodeRawCSV --- src/Data/CSV/Sip.hs | 20 +++++++++++++++++++- test/Data/CSV/SipSpec.hs | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 1 deletion(-) diff --git a/src/Data/CSV/Sip.hs b/src/Data/CSV/Sip.hs index 09b9a23..7d1ab07 100644 --- a/src/Data/CSV/Sip.hs +++ b/src/Data/CSV/Sip.hs @@ -33,6 +33,8 @@ module Data.CSV.Sip ( slurpRawLabelledCSV, -- * Conduits -- ** Encoding + encodeCSV, + encodeRawCSV, encodeRows, encodeRawRows, -- ** Decoding @@ -57,7 +59,7 @@ import Control.Monad (unless) import Control.Monad.Trans.Class (lift) import Control.Monad.Trans.State (StateT, evalStateT, get, gets, modify) import qualified Data.ByteString as BS -import Data.Conduit.List (consume) +import Data.Conduit.List (consume, sourceList) import qualified Data.Map as M import Data.Maybe (fromMaybe) import qualified Data.Text as T @@ -98,6 +100,22 @@ slurpRawLabelledCSV slurpRawLabelledCSV file = runConduit $ sourceFile file .| decodeRawRows .| labelFields .|consume +-- | encode an entire CSV file +encodeCSV + :: Monad m + => [[T.Text]] + -- ^ the data being encoded, organized into rows and fields + -> ConduitT () BS.ByteString m () +encodeCSV csv = sourceList csv .| encodeRows + +-- | encode an entire CSV file +encodeRawCSV + :: Monad m + => [[BS.ByteString]] + -- ^ the data being encoded, organized into rows and fields + -> ConduitT () BS.ByteString m () +encodeRawCSV csv = sourceList csv .| encodeRawRows + -- | encode a CSV stream row by row, each element in the list read -- represents a field, with the entire list representing a row encodeRows :: Monad m => ConduitT [T.Text] BS.ByteString m () diff --git a/test/Data/CSV/SipSpec.hs b/test/Data/CSV/SipSpec.hs index 02f69b1..ad396e7 100644 --- a/test/Data/CSV/SipSpec.hs +++ b/test/Data/CSV/SipSpec.hs @@ -33,6 +33,8 @@ import Data.CSV.Sip spec :: Spec spec = describe "Data.CSV.Sip" $ do + encodeCSVSpec + encodeRawCSVSpec encodeRowsSpec encodeRawRowsSpec labelFieldsSpec @@ -41,6 +43,42 @@ spec = describe "Data.CSV.Sip" $ do decodeUTF8Spec toBytesSpec +encodeCSVSpec :: Spec +encodeCSVSpec = describe "encodeCSV" $ do + result <- BS.concat <$> runConduit + (encodeCSV input .| consume) + it ("shouldBe " ++ show expected) $ + result `shouldBe` expected + where + + input = + [ [ "foo", "a\"b" ] + , [ "a\rb", "a\nb" ] + ] + + expected = BS.concat + [ "\"foo\",\"a\"\"b\"\r\n" + , "\"a\rb\",\"a\nb\"\r\n" + ] + +encodeRawCSVSpec :: Spec +encodeRawCSVSpec = describe "encodeRawCSV" $ do + result <- BS.concat <$> runConduit + (encodeRawCSV input .| consume) + it ("shouldBe " ++ show expected) $ + result `shouldBe` expected + where + + input = + [ [ "foo", "a\"b" ] + , [ "a\rb", "a\nb" ] + ] + + expected = BS.concat + [ "\"foo\",\"a\"\"b\"\r\n" + , "\"a\rb\",\"a\nb\"\r\n" + ] + encodeRowsSpec :: Spec encodeRowsSpec = describe "encodeRows" $ do result <- BS.concat <$> runConduit