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

module DSV.ZipViewPipe
  ( zipViewPipe
  , zipViewPipeIgnoringAllErrors
  , zipViewPipeThrowFirstError
  ) where

import DSV.ByteString
import DSV.IO
import DSV.Pipes
import DSV.Position
import DSV.Prelude
import DSV.Validation
import DSV.Vector
import DSV.ViewType
import DSV.ZipViewType

-- pipes
import qualified Pipes.Prelude as P

zipViewPipe ::
    forall m headerError rowError row .
    Monad m
    => ZipView headerError rowError row
      -- ^ A specification of how to interpret the header and rows
    -> Pipe (Vector ByteString) (Validation rowError row) m headerError
      -- ^ The first vector that this pipe 'await's is the header. If the header is invalid, the pipe closes and 'return's the @headerError@. Otherwise, the pipe continues indefinitely; for each subsequent @'Vector' 'ByteString'@, it 'yield's one @'Validation' rowError row@.

zipViewPipe :: ZipView headerError rowError row
-> Pipe (Vector ByteString) (Validation rowError row) m headerError
zipViewPipe (ZipView (View Vector ByteString
-> Validation headerError (View rowError (Vector ByteString) row)
f)) =
  do
    Vector ByteString
header <- Proxy
  ()
  (Vector ByteString)
  ()
  (Validation rowError row)
  m
  (Vector ByteString)
forall (m :: * -> *) a. Functor m => Consumer' a m a
await
    case (Vector ByteString
-> Validation headerError (View rowError (Vector ByteString) row)
f Vector ByteString
header) of
        Failure headerError
err -> headerError
-> Pipe (Vector ByteString) (Validation rowError row) m headerError
forall (m :: * -> *) a. Monad m => a -> m a
return headerError
err
        Success (View Vector ByteString -> Validation rowError row
g) -> (Vector ByteString -> Validation rowError row)
-> Pipe (Vector ByteString) (Validation rowError row) m headerError
forall (m :: * -> *) a b r. Functor m => (a -> b) -> Pipe a b m r
P.map Vector ByteString -> Validation rowError row
g

zipViewPipeIgnoringAllErrors ::
    forall m headerError rowError row .
    Monad m
    => ZipView headerError rowError row
      -- ^ A specification of how to interpret the header and rows
    -> Pipe (Vector ByteString) row m ()
      -- ^ The first vector that this pipe 'await's is the header. If the header is invalid, the pipe closes and 'return's @()@. Otherwise, the pipe continues indefinitely; for each subsequent @'Vector' 'ByteString'@, it 'yield's a @row@ if the row is valid, or otherwise does nothing if the row is malformed.

zipViewPipeIgnoringAllErrors :: ZipView headerError rowError row
-> Pipe (Vector ByteString) row m ()
zipViewPipeIgnoringAllErrors (ZipView (View Vector ByteString
-> Validation headerError (View rowError (Vector ByteString) row)
f)) =
  do
    Vector ByteString
header <- Proxy () (Vector ByteString) () row m (Vector ByteString)
forall (m :: * -> *) a. Functor m => Consumer' a m a
await
    case (Vector ByteString
-> Validation headerError (View rowError (Vector ByteString) row)
f Vector ByteString
header) of
        Failure headerError
_ -> () -> Pipe (Vector ByteString) row m ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
        Success (View Vector ByteString -> Validation rowError row
g) -> (Vector ByteString -> Validation rowError row)
-> Pipe (Vector ByteString) row m ()
forall (m :: * -> *) (t :: * -> *) a b r.
(Functor m, Foldable t) =>
(a -> t b) -> Pipe a b m r
P.mapFoldable Vector ByteString -> Validation rowError row
g

zipViewPipeThrowFirstError ::
    forall m headerError rowError row r .
    ( Monad m, MonadThrow m
    , Exception headerError
    , Show rowError, Typeable rowError
    )
    => ZipView headerError rowError row
      -- ^ A specification of how to interpret the header and rows
    -> Pipe (Vector ByteString) row m r
      -- ^ The first vector that this pipe 'await's is the header. If the header is invalid, the pipe throws the @headerError@ as an exception in @m@. For each subsequent @'Vector' 'ByteString'@, the pipe 'yield's a @row@ if the row is valid, or otherwise throws the @rowError@ as an exception in @m@.

zipViewPipeThrowFirstError :: ZipView headerError rowError row
-> Pipe (Vector ByteString) row m r
zipViewPipeThrowFirstError (ZipView (View Vector ByteString
-> Validation headerError (View rowError (Vector ByteString) row)
f)) =
  do
    Vector ByteString
header <- Proxy () (Vector ByteString) () row m (Vector ByteString)
forall (m :: * -> *) a. Functor m => Consumer' a m a
await
    case (Vector ByteString
-> Validation headerError (View rowError (Vector ByteString) row)
f Vector ByteString
header) of
        Failure headerError
e -> headerError -> Pipe (Vector ByteString) row m r
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throwM headerError
e
        Success View rowError (Vector ByteString) row
v -> View rowError (Vector ByteString) row
-> RowNumber -> Pipe (Vector ByteString) row m r
forall (m :: * -> *) a a y b.
(MonadThrow m, Typeable a, Show a) =>
View a a y -> RowNumber -> Proxy () a () y m b
go View rowError (Vector ByteString) row
v (Positive -> RowNumber
RowNumber Positive
1)
  where
    go :: View a a y -> RowNumber -> Proxy () a () y m b
go View a a y
v (RowNumber Positive
n) =
      do
        a
x <- Proxy () a () y m a
forall (m :: * -> *) a. Functor m => Consumer' a m a
await
        case View a a y -> a -> Validation a y
forall e a b. View e a b -> a -> Validation e b
applyView View a a y
v a
x of
            Failure a
e -> At RowNumber a -> Proxy () a () y m b
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throwM (RowNumber -> a -> At RowNumber a
forall p a. p -> a -> At p a
At (Positive -> RowNumber
RowNumber Positive
n) a
e)
            Success y
row ->
              do
                y -> Proxy () a () y m ()
forall (m :: * -> *) a x' x. Functor m => a -> Proxy x' x () a m ()
yield y
row
                View a a y -> RowNumber -> Proxy () a () y m b
go View a a y
v (Positive -> RowNumber
RowNumber (Positive
n Positive -> Positive -> Positive
forall a. Num a => a -> a -> a
+ Positive
1))