@@ -24,7 +24,9 @@ module Data.Csv.Encoding
2424 , DecodeOptions (.. )
2525 , defaultDecodeOptions
2626 , decodeWith
27+ , decodeWithP
2728 , decodeByNameWith
29+ , decodeByNameWithP
2830 , EncodeOptions (.. )
2931 , defaultEncodeOptions
3032 , encodeWith
@@ -117,7 +119,7 @@ decodeWith :: FromRecord a
117119 -- skipped
118120 -> L. ByteString -- ^ CSV data
119121 -> Either String (Vector a )
120- decodeWith = decodeWithC csv
122+ decodeWith = decodeWithC ( csv parseRecord)
121123{-# INLINE [1] decodeWith #-}
122124
123125{-# RULES
@@ -130,12 +132,25 @@ idDecodeWith :: DecodeOptions -> HasHeader -> L.ByteString
130132 -> Either String (Vector (Vector B. ByteString ))
131133idDecodeWith = decodeWithC Parser. csv
132134
135+ -- | Like 'decodeWith'', but lets you specify a parser function.
136+ --
137+ -- @since 0.5.2.0
138+ decodeWithP :: (Record -> Conversion. Parser a )
139+ -- ^ Custom parser function
140+ -> DecodeOptions -- ^ Decoding options
141+ -> HasHeader -- ^ Data contains header that should be
142+ -- skipped
143+ -> L. ByteString -- ^ CSV data
144+ -> Either String (Vector a )
145+ decodeWithP _parseRecord = decodeWithC (csv _parseRecord)
146+ {-# INLINE [1] decodeWithP #-}
147+
133148-- | Decode CSV data using the provided parser, skipping a leading
134149-- header if 'hasHeader' is 'HasHeader'. Returns 'Left' @errMsg@ on
135150-- failure.
136151decodeWithC :: (DecodeOptions -> AL. Parser a ) -> DecodeOptions -> HasHeader
137152 -> BL8. ByteString -> Either String a
138- decodeWithC p ! opts hasHeader = decodeWithP parser
153+ decodeWithC p ! opts hasHeader = decodeWithP' parser
139154 where parser = case hasHeader of
140155 HasHeader -> header (decDelimiter opts) *> p opts
141156 NoHeader -> p opts
@@ -147,7 +162,18 @@ decodeByNameWith :: FromNamedRecord a
147162 => DecodeOptions -- ^ Decoding options
148163 -> L. ByteString -- ^ CSV data
149164 -> Either String (Header , Vector a )
150- decodeByNameWith ! opts = decodeWithP (csvWithHeader opts)
165+ decodeByNameWith ! opts = decodeWithP' (csvWithHeader parseNamedRecord opts)
166+
167+ -- | Like 'decodeByNameWith', but lets you specify a parser function.
168+ --
169+ -- @since 0.5.2.0
170+ decodeByNameWithP :: (NamedRecord -> Conversion. Parser a )
171+ -- ^ Custom parser function
172+ -> DecodeOptions -- ^ Decoding options
173+ -> L. ByteString -- ^ CSV data
174+ -> Either String (Header , Vector a )
175+ decodeByNameWithP _parseNamedRecord ! opts =
176+ decodeWithP' (csvWithHeader _parseNamedRecord opts)
151177
152178-- | Should quoting be applied to fields, and at which level?
153179data Quoting
@@ -328,8 +354,8 @@ prependToAll :: Builder -> [Builder] -> [Builder]
328354prependToAll _ [] = []
329355prependToAll sep (x: xs) = sep <> x : prependToAll sep xs
330356
331- decodeWithP :: AL. Parser a -> L. ByteString -> Either String a
332- decodeWithP p s =
357+ decodeWithP' :: AL. Parser a -> L. ByteString -> Either String a
358+ decodeWithP' p s =
333359 case AL. parse p s of
334360 AL. Done _ v -> Right v
335361 AL. Fail left _ msg -> Left errMsg
@@ -338,7 +364,7 @@ decodeWithP p s =
338364 (if BL8. length left > 100
339365 then (take 100 $ BL8. unpack left) ++ " (truncated)"
340366 else show (BL8. unpack left))
341- {-# INLINE decodeWithP #-}
367+ {-# INLINE decodeWithP' #-}
342368
343369-- These alternative implementation of the 'csv' and 'csvWithHeader'
344370-- parsers from the 'Parser' module performs the
@@ -351,26 +377,27 @@ decodeWithP p s =
351377-- "parse error: conversion error: ...".
352378
353379-- | Parse a CSV file that does not include a header.
354- csv :: FromRecord a => DecodeOptions -> AL. Parser (V. Vector a )
355- csv ! opts = do
380+ csv :: (Record -> Conversion. Parser a ) -> DecodeOptions
381+ -> AL. Parser (V. Vector a )
382+ csv _parseRecord ! opts = do
356383 vals <- records
357384 return $! V. fromList vals
358385 where
359386 records = do
360387 ! r <- record (decDelimiter opts)
361388 if blankLine r
362389 then (endOfInput *> pure [] ) <|> (endOfLine *> records)
363- else case runParser (parseRecord r) of
390+ else case runParser (_parseRecord r) of
364391 Left msg -> fail $ " conversion error: " ++ msg
365392 Right val -> do
366393 ! vals <- (endOfInput *> AP. pure [] ) <|> (endOfLine *> records)
367394 return (val : vals)
368395{-# INLINE csv #-}
369396
370397-- | Parse a CSV file that includes a header.
371- csvWithHeader :: FromNamedRecord a = > DecodeOptions
398+ csvWithHeader :: ( NamedRecord -> Conversion. Parser a ) - > DecodeOptions
372399 -> AL. Parser (Header , V. Vector a )
373- csvWithHeader ! opts = do
400+ csvWithHeader _parseNamedRecord ! opts = do
374401 ! hdr <- header (decDelimiter opts)
375402 vals <- records hdr
376403 let ! v = V. fromList vals
@@ -386,4 +413,4 @@ csvWithHeader !opts = do
386413 ! vals <- (endOfInput *> pure [] ) <|> (endOfLine *> records hdr)
387414 return (val : vals)
388415
389- convert hdr = parseNamedRecord . Types. toNamedRecord hdr
416+ convert hdr = _parseNamedRecord . Types. toNamedRecord hdr
0 commit comments