PureCSV icon indicating copy to clipboard operation
PureCSV copied to clipboard

Error when Converting CSV to a Specific format

Open joesan opened this issue 7 years ago • 1 comments

I first have to thank you for this awesome library. I read through the shapeless guide and got to understand HList. I however want to try out this library for a specific use case where the csv fields look like this:

MeterId,Date,00:30,01:00,01:30,02:00,02:30,03:00,03:30,04:00
8814791409,08/02/2017,0,0,0,0,0,0,170.153

I want to parse this into a case class like:

class MeterData(meterId: String, dateTime: DateTime, meterReadings: Map[String, Double])

where meterReadings are 00:30 -> 0, 01:00 -> 0, 01:30 -> 0 and so on...

I just tried doing this bluntly with the PureCSV library and as expected it fails

scala> CSVReader[MeterData].readCSVFromFile("meter.csv")
<console>:16: error: could not find implicit value for parameter rfcImp: purecsv.unsafe.converter.RawFieldsConverter[MeterData]
       CSVReader[MeterData].readCSVFromFile("meter.csv")

I guess I need to spin up my own implicit converter, but I could not figure out how. Would you mind throwing some light on this?

joesan avatar May 06 '17 05:05 joesan

I assume you are using Joda, my example will use java.time but you can adapt it. Here what I would do:

import pureconfig.unsafe.convert._

import java.time.ZonedDateTime
import java.time.format.DateTimeFormatter.ISO_ZONED_DATE_TIME

case class MeterData(meterId: String, date: ZonedDateTime, meterReadings: Map[String, Double])


implicit val meterDataRFC =
  new RawFieldsConverter[MeterData] {

    def intervals: Seq[String] =
      Seq("00:30", "01:00", "01:30", "02:00", "02:30", "03:00", "03:30", "04:00")
  
    def from(line: Seq[String]): MeterData = {
      val Seq(meterId, rawDate, rawMeterReadings@_*) = line
      val date = ZonedDateTime.parse(rawDate, ISO_ZONED_DATE_TIME)
      val meterReadings = intervals.zip(rawMeterReadings.map(StringConverter[Double].from)).toMap
      new MeterData(meterId, date, meterReadings)
    }
    
    def to(meterData: MeterData): Seq[String] =
      Seq(meterData.meterId, meterData.date.toString) ++ meterData.meterReadings.values.map(StringConverter[Double].to)
  }
```

melrief avatar May 07 '17 21:05 melrief