Wrapper around the Haskell library cassava for processing CSV data in constant space via io-streams.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

Encode.hs 4.2KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. {-
  2. This file is part of the Haskell package cassava-streams. It is
  3. subject to the license terms in the LICENSE file found in the
  4. top-level directory of this distribution and at
  5. git://pmade.com/cassava-streams/LICENSE. No part of cassava-streams
  6. package, including this file, may be copied, modified, propagated, or
  7. distributed except according to the terms contained in the LICENSE
  8. file.
  9. -}
  10. --------------------------------------------------------------------------------
  11. module System.IO.Streams.Csv.Encode
  12. ( encodeStream
  13. , encodeStreamWith
  14. , encodeStreamByName
  15. , encodeStreamByNameWith
  16. ) where
  17. --------------------------------------------------------------------------------
  18. import Control.Monad (when)
  19. import Data.ByteString (ByteString)
  20. import qualified Data.ByteString.Lazy as BL
  21. import Data.Csv
  22. import Data.IORef
  23. import System.IO.Streams (OutputStream, makeOutputStream)
  24. import qualified System.IO.Streams as Streams
  25. --------------------------------------------------------------------------------
  26. -- | Create a new @OutputStream@ that can be fed @ToRecord@ values
  27. -- which are converted to CSV. The records are encoded into
  28. -- @ByteString@s and passed on to the given downstream @OutputStream@.
  29. --
  30. -- Equivalent to @encodeStreamWith defaultEncodeOptions@.
  31. encodeStream :: ToRecord a
  32. => OutputStream ByteString -- ^ Downstream.
  33. -> IO (OutputStream a) -- ^ New @OutputStream@.
  34. encodeStream = encodeStreamWith defaultEncodeOptions
  35. --------------------------------------------------------------------------------
  36. -- | Create a new @OutputStream@ that can be fed @ToRecord@ values
  37. -- which are converted to CSV. The records are encoded into
  38. -- @ByteString@s and passed on to the given downstream @OutputStream@.
  39. encodeStreamWith :: ToRecord a
  40. => EncodeOptions -- ^ Encoding options.
  41. -> OutputStream ByteString -- ^ Downstream.
  42. -> IO (OutputStream a) -- ^ New @OutputStream@.
  43. encodeStreamWith opts output = do
  44. ref <- newIORef opts
  45. makeOutputStream (dispatch encodeWith ref output)
  46. --------------------------------------------------------------------------------
  47. -- | Create a new @OutputStream@ which can be fed @ToNamedRecord@
  48. -- values that will be converted into CSV. The records are encoded
  49. -- into @ByteString@s and passed on to the given downstream
  50. -- @OutputStream@.
  51. --
  52. -- Equivalent to @encodeStreamByNameWith defaultEncodeOptions@.
  53. encodeStreamByName :: ToNamedRecord a
  54. => Header -- ^ CSV Header.
  55. -> OutputStream ByteString -- ^ Downstream.
  56. -> IO (OutputStream a) -- ^ New @OutputStream@.
  57. encodeStreamByName = encodeStreamByNameWith defaultEncodeOptions
  58. --------------------------------------------------------------------------------
  59. -- | Create a new @OutputStream@ which can be fed @ToNamedRecord@
  60. -- values that will be converted into CSV. The records are encoded
  61. -- into @ByteString@s and passed on to the given downstream
  62. -- @OutputStream@.
  63. encodeStreamByNameWith :: ToNamedRecord a
  64. => EncodeOptions -- ^ Encoding options.
  65. -> Header -- ^ CSV Header.
  66. -> OutputStream ByteString -- ^ Downstream.
  67. -> IO (OutputStream a) -- ^ New @OutputStream@.
  68. encodeStreamByNameWith opts hdr output = do
  69. ref <- newIORef opts
  70. makeOutputStream $ dispatch (`encodeByNameWith` hdr) ref output
  71. --------------------------------------------------------------------------------
  72. -- | Encode records, ensuring that the header is written no more than once.
  73. dispatch :: (EncodeOptions -> [a] -> BL.ByteString) -- ^ Encoding function.
  74. -> IORef EncodeOptions -- ^ Encoding options.
  75. -> OutputStream ByteString -- ^ Downstream.
  76. -> Maybe a -- ^ Record to write.
  77. -> IO ()
  78. dispatch _ _ output Nothing = Streams.write Nothing output
  79. dispatch enc ref output (Just x) = do
  80. opts <- readIORef ref
  81. when (encIncludeHeader opts) $ writeIORef ref (opts {encIncludeHeader = False})
  82. Streams.writeLazyByteString (enc opts [x]) output