Created
June 9, 2020 04:44
-
-
Save szoio/50aa1b47d3b376c53d21f9e41dc07113 to your computer and use it in GitHub Desktop.
Magnolia Sample
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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