{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE ScopedTypeVariables #-}

module DSV.Parsing
  ( dsvRowAtto
  , dsvRowPipe, csvRowPipe
  , handleCsvRowProducer, handleDsvRowProducer
  ) where

import DSV.AttoParser
import DSV.AttoPipe
import DSV.ByteString
import DSV.CommonDelimiters
import DSV.IO
import DSV.ParseError
import DSV.ParseStop
import DSV.Pipes
import DSV.Prelude
import DSV.Vector

-- attoparsec
import Data.Attoparsec.ByteString.Char8 (endOfLine)

-- cassava
import qualified Data.Csv.Parser as Cassava

dsvRowAtto ::
    Delimiter  -- ^ What character separates input values, e.g. 'comma' or 'tab'
    -> AttoParser (Vector ByteString)

dsvRowAtto :: Delimiter -> AttoParser (Vector ByteString)
dsvRowAtto Delimiter
d =
    Word8 -> AttoParser (Vector ByteString)
Cassava.record (Delimiter -> Word8
delimiterWord8 Delimiter
d) AttoParser (Vector ByteString)
-> Parser ByteString () -> AttoParser (Vector ByteString)
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* Parser ByteString ()
endOfLine

-- | Like 'csvRowPipe', but allows customizing the delimiter.

dsvRowPipe ::
    forall m .
    Monad m
    => Delimiter  -- ^ What character separates input values, e.g. 'comma' or 'tab'
    -> Pipe ByteString (Vector ByteString) m ParseError

dsvRowPipe :: Delimiter -> Pipe ByteString (Vector ByteString) m ParseError
dsvRowPipe Delimiter
d =
    AttoParser (Vector ByteString)
-> Pipe ByteString (Vector ByteString) m ParseError
forall a (m :: * -> *).
Monad m =>
AttoParser a -> Pipe ByteString a m ParseError
attoPipe (Delimiter -> AttoParser (Vector ByteString)
dsvRowAtto Delimiter
d)

-- | This pipe 'await's @ByteString@ input read from a CSV file, parses the input, and 'yield's a @'Vector' 'ByteString'@ for each row in the CSV file. If this pipe reaches some portion of the input that is not formatted correctly and cannot parse any further, the pipe terminates and 'return's a 'ParseError'.

csvRowPipe ::
    forall m .
    Monad m
    => Pipe ByteString (Vector ByteString) m ParseError

csvRowPipe :: Pipe ByteString (Vector ByteString) m ParseError
csvRowPipe =
    AttoParser (Vector ByteString)
-> Pipe ByteString (Vector ByteString) m ParseError
forall a (m :: * -> *).
Monad m =>
AttoParser a -> Pipe ByteString a m ParseError
attoPipe (Delimiter -> AttoParser (Vector ByteString)
dsvRowAtto Delimiter
comma)

handleCsvRowProducer ::
    forall m .
    MonadIO m
    => Handle     -- ^ File handle to read CSV data from
    -> Producer (Vector ByteString) m ParseStop

handleCsvRowProducer :: Handle -> Producer (Vector ByteString) m ParseStop
handleCsvRowProducer Handle
h =
    Delimiter -> Handle -> Producer (Vector ByteString) m ParseStop
forall (m :: * -> *).
MonadIO m =>
Delimiter -> Handle -> Producer (Vector ByteString) m ParseStop
handleDsvRowProducer Delimiter
comma Handle
h

handleDsvRowProducer ::
    forall m .
    MonadIO m
    => Delimiter  -- ^ What character separates input values, e.g. 'comma' or 'tab'
    -> Handle     -- ^ File handle to read DSV data from
    -> Producer (Vector ByteString) m ParseStop

handleDsvRowProducer :: Delimiter -> Handle -> Producer (Vector ByteString) m ParseStop
handleDsvRowProducer Delimiter
d Handle
h =
    AttoParser (Vector ByteString)
-> Handle -> Producer (Vector ByteString) m ParseStop
forall a (m :: * -> *).
MonadIO m =>
AttoParser a -> Handle -> Producer a m ParseStop
handleAttoProducer (Delimiter -> AttoParser (Vector ByteString)
dsvRowAtto Delimiter
d) Handle
h