{-| Module : Pipes.KeyValueCsv.KeyValue Copyright : (c) Marcin Mrotek, 2015 License : BSD3 Maintainer : marcin.jan.mrotek@gmail.com Stability : experimental Parse key-value pairs. -} {-# LANGUAGE DataKinds , ExplicitForAll , FlexibleContexts , GADTs , PolyKinds , TypeOperators #-} module Pipes.KeyValueCsv.KeyValue ( module Pipes.KeyValueCsv.KeyValue , Record , KeyValueError(..) ) where import Pipes.KeyValueCsv.Internal.KeyValue import Pipes.KeyValueCsv.Internal.Types import Pipes.KeyValueCsv.Types.KeyValue import Control.Lens import Data.Reflection import qualified Data.Set as Set import Data.Validation import Data.Vinyl import Data.Vinyl.Functor import Pipes import qualified Pipes.Prelude as Pipes import qualified Pipes.Group as Group parseKeyValues :: forall (m :: * -> *) (f :: k -> *) (rs :: [k]) (r :: *) . ( Given Delimiter , Monad m , Record rs ) => KeyValueOptions m f rs -- ^Options -> Lines m r -- ^Stream of lines -> m (Rec (WithKeyValueError :. f) rs, r) -- ^Parse lines into a stream of records with at most one 'Success' field. parseKeyValues options = foldHeader . Group.concats . Group.maps (parseKeyValue (options^.kvParser) names names'set) . unLines where names = options^.keyNames names'set = Set.fromList $ recordToList names foldHeader :: ( Monad m , Record rs ) => Producer (Rec (WithKeyValueError :. f) rs) m r -> m (Rec (WithKeyValueError :. f) rs, r) -- ^Fold a stream of key-value records into a single record. foldHeader = Pipes.fold' joinRecs missing id joinRecs :: Rec (WithKeyValueError :. f) rs -> Rec (WithKeyValueError :. f) rs -> Rec (WithKeyValueError :. f) rs -- ^Join two 'Rec's, replacing missing values with successes and accumulating failures. joinRecs RNil RNil = RNil joinRecs (Compose va :& as) (Compose vb :& bs) = Compose new :& joinRecs as bs where new = case (va, vb) of (Success a, Failure [MissingValue]) -> Success a (Failure [MissingValue], Success b) -> Success b (Success _, Success _) -> Failure [MultipleValues] (Success _, Failure f) -> Failure f (Failure f, Success _) -> Failure f (Failure [MissingValue], Failure f) -> Failure f (Failure f, Failure [MissingValue]) -> Failure f (Failure f1, Failure f2) -> Failure $ MultipleValues : (f1++f2)