Turn CSV Values into Elm values. Inspired by elm/json, so make sure to check out this intro to
JSON decoders to get a feel for how this library works!
Note this library does not include an underlying CSV parser. It assumes you are using something like periodic/elm-csv to get from String to Csv, where Csv is:
type alias Csv =
{ headers : List String
, records : List (List String)
}This library gets you the rest of the way, to a list of your own types.
In the examples we make use of a decodeString function. Which is defined as
decodeString : Decoder a -> String -> Result Error (List a)
decodeString decoder input =
input
|> (++) "\n"
|> Csv.parse
|> Result.mapError (\_ -> CsvParseError)
|> Result.andThen (decode decoder)The raw CSV data structure.
A structured error describing exactly how the decoder failed. You can use this to create more elaborate visualizations of a decoder problem. For example, you could show the entire CSV record and show the part causing the failure in red.
Kind determines what type a decoder expects. Used in combination with the Not error.
Decode a CSV string into an Elm String.
decodeString string "true" == Ok [ "true" ]
decodeString string "42" == Ok [ "42" ]
decodeString string "3.14" == Ok [ "3.14" ]
decodeString string "hello" == Ok [ "hello" ]Decode a CSV number into an Elm Int.
decodeString int "true" == Err ...
decodeString int "42" == Ok [ 42 ]
decodeString int "3.14" == Err ...
decodeString int "hello" == Err ...Decode a CSV number into an Elm Float.
decodeString float "true" == Err ..
decodeString float "42" == Ok [ 42 ]
decodeString float "3.14" == Ok [ 3.14 ]
decodeString float "hello" == Err ...Decode a CSV boolean into an Elm Bool.
decodeString bool "true" == Ok [ True ]
decodeString bool "42" == Err ...
decodeString bool "3.14" == Err ...
decodeString bool "hello" == Err ...Decode the given Csv into a list of custom value by running Decoder on it.
This will fail if any of the records can not be decoded by the Decoder for some reason.
Transform a decoder. Maybe you just want to know the length of a string:
import String
stringLength : Decoder Int
stringLength =
map String.length stringIt is often helpful to use map with oneOf, like when defining maybe:
maybe : Decoder a -> Decoder (Maybe a)
maybe decoder =
oneOf
[ map Just decoder
, succeed Nothing
]Try two decoders and then combine the result. We can use this to decode objects with many fields:
type alias Point =
{ x : Float, y : Float }
point : Decoder Point
point =
map2 Point
float
float
-- decodeString point "3,4" == Ok { x = 3, y = 4 }It tries each individual decoder and puts the result together with the Point
constructor.
Try three decoders and then combine the result. We can use this to decode objects with many fields:
type alias Person =
{ name : String, age : Int, height : Float }
person : Decoder Person
person =
map3 Person
string
int
float
-- csv = "tom,42,1.8"
-- decodeString person csv == Ok { name = "tom", age = 42, height = 1.8 }Like map2 it tries each decoder in order and then give the results to the
Person constructor. That can be any function though!
Ignore the CSV and produce a certain Elm value.
decodeString (succeed 42) "true" == Ok [ 42 ]
decodeString (succeed 42) "1,2,3" == Ok [ 42 ]
decodeString (succeed 42) "hello" == Ok [ 42 ]This is handy when used with oneOf.
Ignore the CSV and make the decoder fail. This is handy when used with
oneOf where you want to give a custom error message in some
case.
Helpful for dealing with optional fields. Here are a few slightly different examples:
decodeString (maybe int) "42" == Ok [ Just 42 ]
decodeString (maybe int) ",42" == Ok [ Nothing ]Try a bunch of different decoders. This can be useful if the CSV may come
in a couple different formats. For example, say you want to read an array of
numbers, but some of them are null.
import String
badInt : Decoder Int
badInt =
oneOf [ int, null 0 ]
-- decodeString (list badInt) "[1,2,null,4]" == Ok [1,2,0,4]Why would someone generate CSV like this? Questions like this are not good
for your health. The point is that you can use oneOf to handle situations
like this!
A value that knows how to decode CSV values.