Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Magnolia Sample
import magnolia._
import scala.language.experimental.macros
import scala.util.Try
final case class User(name: String, age: Int, admin: Boolean)
trait CsvDecoder[A] {
def decode(value: List[String]): Either[Throwable, A]
}
val columnSplitter = """,(?=([^\"]*\"[^\"]*\")*[^\"]*$)""".r
val rowSpitter = """\r?\n""".r
def decodeCsv[A](input: String)(implicit decoder: CsvDecoder[A]): List[A] =
input.linesIterator.map { line =>
val columns = columnSplitter.split(line).toList
decoder.decode(columns)
}.toList
.collect { case Right(x) => x }
// decoders for primitive types
def getFirst(strings: List[String]): Either[Throwable, String] =
strings.headOption.toRight(new RuntimeException("Not enough values in list"))
implicit val intDecoder: CsvDecoder[Int] = getFirst(_).flatMap(s => Try(s.toInt).toEither)
implicit val stringDecoder: CsvDecoder[String] = getFirst(_)
implicit val booleanDecoder: CsvDecoder[Boolean] = getFirst(_).flatMap(s => Try(s.toBoolean).toEither)
object MyDerivation {
type Typeclass[A] = CsvDecoder[A]
def combine[A](caseClass: CaseClass[CsvDecoder, A]): CsvDecoder[A] = { strings =>
caseClass.constructMonadic { param =>
param.typeclass.decode(strings.drop(param.index))
}
}
def dispatch[A](sealedTrait: SealedTrait[CsvDecoder, A]): CsvDecoder[A] = ???
implicit def gen[A]: Typeclass[A] = macro Magnolia.gen[A]
}
import MyDerivation._
val decoded = decodeCsv[User]("Alice,21,true\nBob,32,false\nCharlie,35,false")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment