module Store.CSV ( buildCSV ) where import qualified Data.ByteString as BS import qualified Data.ByteString.Builder as B import qualified Data.ByteString.Builder.Prim as BP import qualified Data.ByteString.Char8 as BSC import Data.ByteString.Internal (c2w) import Data.Monoid ((<>)) inter :: B.Builder -> [B.Builder] -> B.Builder inter _ [] = mempty inter d (x:l) = x <> mconcat (map (d <>) l) csvCell :: BS.ByteString -> B.Builder csvCell t | BSC.any (`elem` "\",\r\n") t = q <> BP.primMapByteStringBounded quote t <> q | otherwise = B.byteString t where qw = c2w '"' q = B.word8 qw quote = BP.condB (== qw) (BP.liftFixedToBounded $ const (qw, qw) BP.>$< BP.word8 BP.>*< BP.word8) (BP.liftFixedToBounded BP.word8) csvRow :: [BS.ByteString] -> B.Builder csvRow r = inter (B.char8 ',') (map csvCell r) <> B.char8 '\n' buildCSV :: [[BS.ByteString]] -> B.Builder buildCSV = mconcat . map csvRow