Releases: BrianHicks/elm-csv
4.0.0 – Optional fields
Thanks to @gampleman's hard work, elm-csv
now has:
- Optional fields and columns with
optionalField
andoptionalColumn
- Dynamic decoding with
availableFields
- Improved error handling (specifically with less repetition when the same error occurs on multiple rows.)
Full Diff: 3.0.3...4.0.0
3.0.0 – Encoding and better errors
Csv.Encode
You can now encode CSVs using this package:
import Csv.Encode as Encode
Encode.encode
{ encoder =
Encode.withFieldNames
(\(r, g, b) ->
[ ( "red", r )
, ( "green", g )
, ( "blue", b )
]
)
, fieldSeparator = ','
}
[ ( "FF", "FF", "FF" )
, ( "00", "00", "00" )
]
--> "red,green,blue\r\nFF,FF,FF\r\n00,00,00"
Fields will be properly quoted and escaped. In addition, withFieldNames
will always produce aligned CSVs, even in cases where the provided function does not provide all the fields every time.
Better Error Messages
Error messages are greatly improved.
- Row numbers are never negative.
- Errors now specify which column they came frome.
- You now get all the problems in a decoding run in a single error, instead of having to re-run to discover further problems.
- Message strings and constructors are streamlined and clarified.
These changes are why this release is numbered 3.0.0 instead of 2.1.0—the internal custom types representing errors changed. However, unless you were doing your own message-to-string encoding, this release is unlikely to have broken your code. (decodeCsv
produces the error that errorToString
takes, just like before. If you were using that, you can upgrade safely!)
End-of-line Quotes Bug Fix
There was a bug (#15) where quoted fields at the end of a line would combine adjacent lines into one. This release fixes that!
2.0.1 – Trailing newlines
2.0.0 – API improvements and faster parser
This upgrade makes a few tweaks to the API to make creating decoders easier.
API Changes
Pipeline renaming
pipeline
is now into
, and required
is now pipeline
. This makes pipeline code nicer:
decoder : Decoder Pet
decoder =
Decode.into Pet
|> Decode.pipeline (Decode.field "id" Decode.int)
|> Decode.pipeline (Decode.field "name" Decode.string)
|> Decode.pipeline (Decode.field "species" Decode.string)
|> Decode.pipeline (Decode.field "weight" (Decode.blank Decode.float))
fromResult
fromResult
now just takes a Result String a
instead of a function that produces a Result String a
. This is to make scenarios like this possible:
Decode.string
|> Decode.map String.toLower
|> Decode.andThen (Decode.fromResult << Hex.fromString)
This was previously impossible—the design of fromResult
made it so that you could not do any pre-processing to your strings before your conversion function got them. You have to do a little more work now, but in exchange you get a lot more flexibility.
API Additions
To make up for breaking your code, I also added fromMaybe : String -> Result String a
. It does the same thing as fromResult
(fails when it doesn't get a value) but asks you to provide an error message for the failure since Nothing
has no info for us to use.
Faster Parser
This release switches to a hand-rolled parser, which is faster than the one released in 1.0.0. It's 25 times faster for "normal" CSVs—that is, those delimited with ,
or ;
. If you use other characters to delimit your fields, it's a little slower but still something like 24 times faster than the 1.0.0 parser. Thank you to @w0rm for advice on squeezing every last bit of performance out of the code.
As a consequence of the upgrade, this package no longer depends on elm/parser
. If you added it to your transitive dependencies when you installed this package, you can remove it on upgrade.
Look out for some blog posts from @BrianHicks soon on how he achieved this speedup!
Upgrade Instructions
- Replace
Decode.pipeline
withDecode.into
, and thenDecode.required
withDecode.pipeline
. If you do it in that order, it should be safe to run a global find/replace on your code! - Lift any instances of
fromResult
: where you previously would have hadfromResult Hex.fromString
you now will havestring |> andThen (fromResult << Hex.fromString)
. - If you were case-matching on any problems in
Csv.Parser
, you'll have to read the code to figure out what's wrong. Fortunately, it should actually be giving more descriptive error messages now—previously they were justParser.DeadEnd
s, now they have meaning specific to CSVs!