BrianHicks / elm-csv

Decode CSV in the most boring way possible.

Home Page:https://package.elm-lang.org/packages/BrianHicks/elm-csv/latest/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Optional columns

gampleman opened this issue · comments

In our application there are some required columns the user submit and some are optional.

At the moment I encode this like this:

optional :Decoder a -> Decoder (Maybe a -> b) -> Decoder b
optional default childDecoder =
    pipeline (Csv.oneOf (Csv.map Just childDecoder) [ Csv.succeed Nothing ])

decoder =
    Csv.into Tuple.pair 
         |> pipeline (Csv.field "requiredColumn" Csv.float)
         |> optional (Csv.field "optionalColumn" Csv.float)

This sort of works, but has some subtle behavioural gotchas:

requiredColumn optionalColumn
1 2
2 four
3 6

would successfully decode into:

[ ( 1, Just 2 ), ( 2, Nothing ), (3, Just 6) ]

which is not what I want. In this case I'd like to flag the error to the user, but I'd still like to mark some columns as optional. I can't really see a way to achieve this with the current API. So I'd propose something like

optionalField : String -> Decoder a -> Decoder (Maybe a)

which would only go to the Nothing case iff the column was not present at all in the CSV.

Hmm, that's an interesting question. It probably makes sense to do this and to rename pipeline to required. Would these be the semantics?

input required (field "a" int) optional (field "a" int)
"0" Ok 0 Ok (Just 0)
"a" Err ... Err ...
"" Err ... Ok Nothing

Would these be the semantics?

That's not really what I'm after. You can already achieve that with the existing API:

emptyString : Decoder String
emptyString =
    Decode.string 
        |> Decode.andThen (\str ->
            case str of
                 "" -> Decode.succeed ""
                 _ -> Decode.fail "Expected empty string"
        )

optionalField : String -> Decoder a -> Decoder (Maybe a )
optionalField key default childDecoder =
    Csv.oneOf (Csv.map Just childDecoder) [ Csv.map (always Nothing) emptyString  ]

Here I'd like the optionalField to succeed with Nothing only if the field is actually not present in the file.

oh, oops, the third row there is mean to be missing, not blank. I think we're saying the same thing.

if you want to make that happen, go for it—but let's change pipeline to required at the same time for symmetry.