We’ve seen in a previous post how to encode collections as CSV rows. Exactly how that happened and how individual elements of the collection were turned into CSV cells was sort of glossed over, though. In this tutorial, we’ll take a deeper look at the underlying mechanism.
Cell encoding is type class based: kantan.csv knows how to turn a type A
into a CSV cell, provided that there is an
implicit instance of CellEncoder[A]
in scope. All sane primitive types have default implementations
Int
, for example:implicitly[kantan.csv.CellEncoder[Int]]
// res0: kantan.csv.package.CellEncoder[Int] = kantan.codecs.Codec$$anon$1@b13c7c6
A more complete list of default instances can be found here
And so, when asCsvWriter
, writeCsv
or asCsv
are asked to turn a collection of elements A
into a CSV row,
it looks for a corresponding implicit CellEncoder
and relies on it for encoding:
import kantan.csv._
import kantan.csv.ops._
List(List(1, 2, 3), List(4, 5, 6)).asCsv(rfc)
// res1: String = """1,2,3
// 4,5,6
// """
In order to add support to non-standard types, all you need to do is implement an implicit CellEncoder
instance for
that type. Let’s do so, for example, for Joda DateTime
:
import kantan.csv._
import org.joda.time.DateTime
import org.joda.time.format.ISODateTimeFormat
implicit val jodaDateTime: CellEncoder[DateTime] = {
val format = ISODateTimeFormat.date()
CellEncoder.from(format.print)
}
And we can now encode collections of dates:
List(
List(new DateTime(), new DateTime().plusDays(1)),
List(new DateTime().plusDays(2), new DateTime().plusDays(3))
).asCsv(rfc)
// res2: String = """2022-09-06,2022-09-07
// 2022-09-08,2022-09-09
// """
If you want to learn more about: