I currently have code that accumulates errors across rows, but reports only one error (for instance a missing field) per row. Is it somehow possible to list all missing fields when decoding a named record?
Below the current code for reference, as well as how it behaves:
parseFromFile :: forall a. (FromNamedRecord a) => FilePath -> Char -> IO [Either String a]
parseFromFile filepath delimiter = withFile filepath ReadMode $ \csvFile -> do
let options = defaultDecodeOptions {decDelimiter = fromIntegral (ord delimiter)}
loopHeader :: HeaderParser (Parser a) -> IO [Either String a]
loopHeader (FailH _ errMsg) = pure [Left errMsg]
loopHeader (PartialH contP) = feed contP >>= loopHeader
loopHeader (DoneH _header parser) = loop [] parser
loop :: [Either String a] -> Parser a -> IO [Either String a]
loop !acc (Fail _ errMsg) = pure $ acc ++ [Left errMsg]
loop !acc (Many result contP) = feed contP >>= loop (acc ++ result)
loop !acc (Done result) = pure (acc ++ result)
feed :: (ByteString -> f p) -> IO (f p)
feed cont = do
isEof <- hIsEOF csvFile
if isEof
then pure $ cont empty
else cont <$> hGetSome csvFile 4096
loopHeader (Csv.Inc.decodeByNameWith options)
Running it against the following sample csv, yields the message as below:
# persons.csv
name,age,yearsOfExperience
John Doe,,
Smith,20,4
# result
[Left "in named field \"age\": expected Int, got \"\" (not enough input)",Right (Person {name = "Smith", age = 20, yearsOfExperience = 4})]
Ideally, the message would include the missing ageand the missing yearsOfExperience fields. Is it possible to achieve it?
I currently have code that accumulates errors across rows, but reports only one error (for instance a missing field) per row. Is it somehow possible to list all missing fields when decoding a named record?
Below the current code for reference, as well as how it behaves:
Running it against the following sample csv, yields the message as below:
Ideally, the message would include the missing
age
and the missingyearsOfExperience
fields. Is it possible to achieve it?