Using Kantan in Scala, I want to create a RowDecoder[Combined]
for a Combined
case class that has more than 22 fields. I have created RowDecoder[PartA]
, RowDecoder[PartB]
, RowDecoder[PartC]
, and a method ((PartA, PartB, PartC) => Combined
. Does Kantan provide a way to declare the RowDecoder[Combined]
?
Ideally the decoder handles the input only once (String containing row => Seq[String] with fields). I have created a RowDecoder[Combined] like this:
implicit val rowDecoder: RowDecoder[Combined] = RowDecoder.from { elems =>
val line = elems.mkString(",")
val (a, b, c) = (partA(line), partB(line), partC(line)) // partA/B/C have a `RowDecoder[PartX]` and do a line.readCsvRow()
(a, b, c) match {
case (Left(e), _, _) => Left(TypeError(e.getMessage))
case (_, Left(e), _) => Left(TypeError(e.getMessage))
case (_, _, Left(e)) => Left(TypeError(e.getMessage))
case (Right(a), Right(b), Right(c)) => Right(Combined.fromParts(a, b, c))
}
}
But that performs multiple String -> Seq[String] -> seq.mkString -> Seq[String] transformations that can hopefully be prevented.
Thanks @MartinHH for pointing me to that issue, I've created the RowDecoder based on the suggestions there:
implicit val partADecoder: RowDecoder[PartA] = RowDecoder.decoder(0, 1, 3)(PartA.apply)
implicit val partBDecoder: RowDecoder[PartB] = RowDecoder.decoder(2, 4, 5)(PartB.apply)
implicit val rowDecoder: RowDecoder[Combined] = RowDecoder.from { elems =>
for {
a <- partADecoder.decode(elems)
b <- partBDecoder.decode(elems)
} yield Combined(b.colA, a.col1, b.colB, a.col2, b.colC, a.col3)
}
def combined(in: String): ReadResult[Combined] = in.readCsvRow(rfc)