Struggling with Brian Hicks' elm-csv Decode

elm-csv 4.0.1

I have a CSV file with fields that sometimes don’t exist that I’m trying to import using the Decode module.

I have tried optionalField, and I’ve tried blank. In each case I get an error message saying “I couldn’t find the xxx field“ .

I’ve also tried oneOf (optionalField...) [blank...] , and I get erroneous output.

Minimal example:

Input CSV:

AlwaysThere,SometimesThere 
a,b 
c, 
d

Attempt 1

type alias Test = {alwaysThere : String, sometimesThere : String}

            decodedCSVresult =
               decodeCsv FieldNamesFromFirstRow
                  (into Test
                     |> pipeline (field "AlwaysThere" string)
                     |> pipeline (field "SometimesThere" string)
                  )
                  csvString

There was a problem on rows 3 and 4, in the SometimesThere field (column 1): I couldn’t find the SometimesThere column.

Attempt 2

type alias Test ={alwaysThere : String, sometimesThere : Maybe String}

decodedCSVresult =
   decodeCsv FieldNamesFromFirstRow
      (into Test
         |> pipeline (field "AlwaysThere" string)
         |> pipeline (optionalField "SometimesThere" string)
      )
      csvString

There was a problem on rows 3 and 4, in the SometimesThere field (column 1): I couldn’t find the SometimesThere column.

Attempt 3

decodedCSVresult =
   decodeCsv FieldNamesFromFirstRow
      (into Test
         |> pipeline (field "AlwaysThere" string)
         |> pipeline (blank string)
      )
      csvString

There was a problem on rows 1 and 2, column 0 (the only column present): I expected exactly one column, but there were 2.

Attempt 4

decodedCSVresult =
   decodeCsv FieldNamesFromFirstRow
      (into Test
         |> pipeline (  field "AlwaysThere" string )
         |> pipeline (  oneOf
                              (optionalField "SometimesThere" string)
                              [blank string]
                        )
       )
       csvString

[ { alwaysThere = “a”, sometimesThere = Just “b” }

, { alwaysThere = “c”, sometimesThere = Just “” }

, { alwaysThere = “d”, sometimesThere = Just “d” }

, { alwaysThere = “”, sometimesThere = Nothing }

]

So close. There is a blank line at the end of the input file, so the 4th line is correct. But the 3rd line should be d, Nothing – seems it’s reading the first field twice.

What should I try next…?


Edit 1

Summary

This text will be hidden

This text will be hidde

Attempt 5

Perhaps andThen …?

Input CSV:

RecordType,AlwaysThere,SometimesThere
Both,a,b
One,c,
One,d

decodedCSVresult =
   CD.decodeCsv CD.FieldNamesFromFirstRow
      (CD.into (\recordType -> recordType)
         |> CD.pipeline (CD.field "RecordType" CD.string)
         |> CD.andThen
            (\recordType ->
                case recordType of
                   "One" ->
                      (CD.into Test
                         |> CD.pipeline (CD.field "AlwaysThere" CD.string)
                         |> CD.pipeline (CD.blank CD.string)
                      )
                   "Both" ->
                      (CD.into Test
                         |> CD.pipeline (CD.field "AlwaysThere" CD.string)
                         |> CD.pipeline (CD.optionalField "SometimesThere" CD.string)
                      )
                   _ ->
                      CD.succeed <| Test "" Nothing
            )
      )
      csvString

I saw 2 problems while decoding this CSV:\n\nThere was a problem on row 2, column 0 (the only column present): I expected exactly one column, but there were 3.\n\nThere was a problem on row 3, column 0 (the only column present): I expected exactly one column, but there were 2.


Try this:

csvString =
    "AlwaysThere,SometimesThere\na,b\nc,\nd"


type alias Test =
    { alwaysThere : String
    , sometimesThere : Maybe String
    }



-- Custom decoder that treats empty strings as Nothing


emptyStringAsNothing : Decoder String -> Decoder (Maybe String)
emptyStringAsNothing decoder =
    map
        (\v ->
            if String.isEmpty (String.trim v) then
                Nothing

            else
                Just v
        )
        decoder


decodedCSVresult : Result Error (List Test)
decodedCSVresult =
    decodeCsv FieldNamesFromFirstRow
        (into Test
            |> pipeline (field "AlwaysThere" string)
            |> pipeline
                (map
                    (Maybe.andThen
                        (\v ->
                            if String.isEmpty (String.trim v) then
                                Nothing

                            else
                                Just v
                        )
                    )
                    (optionalColumn 1 string)
                )
        )
        csvString

Thank you, Dirk @dirkbj

Have had to switch to other stuff but will play with your code when time permits… :slight_smile:

That’s brilliant, Dirk. Many thanks for working that out for me.
I forget to map in functions from other parts of Elm.

1 Like

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.