diff options
author | vlad <vlad@driver.xyz> | 2017-06-13 10:25:55 -0700 |
---|---|---|
committer | vlad <vlad@driver.xyz> | 2017-06-13 10:25:55 -0700 |
commit | 0000a65ab4479a2a40e2d6468036438e9705b4aa (patch) | |
tree | 60c868828741e7e5367aa7b6d167abbdaf91d5b8 /src/main/scala/xyz/driver/common/db/EntityExtractorDerivation.scala | |
download | rest-query-0000a65ab4479a2a40e2d6468036438e9705b4aa.tar.gz rest-query-0000a65ab4479a2a40e2d6468036438e9705b4aa.tar.bz2 rest-query-0000a65ab4479a2a40e2d6468036438e9705b4aa.zip |
Initial extraction of Driver non-specific utilities
Diffstat (limited to 'src/main/scala/xyz/driver/common/db/EntityExtractorDerivation.scala')
-rw-r--r-- | src/main/scala/xyz/driver/common/db/EntityExtractorDerivation.scala | 71 |
1 files changed, 71 insertions, 0 deletions
diff --git a/src/main/scala/xyz/driver/common/db/EntityExtractorDerivation.scala b/src/main/scala/xyz/driver/common/db/EntityExtractorDerivation.scala new file mode 100644 index 0000000..0396ea5 --- /dev/null +++ b/src/main/scala/xyz/driver/common/db/EntityExtractorDerivation.scala @@ -0,0 +1,71 @@ +package xyz.driver.common.db + +import java.sql.ResultSet + +import io.getquill.NamingStrategy +import io.getquill.dsl.EncodingDsl + +import scala.language.experimental.macros +import scala.reflect.macros.blackbox + +trait EntityExtractorDerivation[Naming <: NamingStrategy] { + this: EncodingDsl => + + /** + * Simple Quill extractor derivation for [[T]] + * Only case classes available. Type parameters is not supported + * + * @tparam T + * @return + */ + def entityExtractor[T]: (ResultSet => T) = macro EntityExtractorDerivation.impl[T] +} + +object EntityExtractorDerivation { + def impl[T: c.WeakTypeTag](c: blackbox.Context): c.Tree = { + import c.universe._ + val namingStrategy = c.prefix.actualType + .baseType(c.weakTypeOf[EntityExtractorDerivation[NamingStrategy]].typeSymbol) + .typeArgs + .head + .typeSymbol + .companion + val functionBody = { + val tpe = weakTypeOf[T] + val resultOpt = tpe.decls.collectFirst { + // Find first constructor of T + case cons: MethodSymbol if cons.isConstructor => + // Create param list for constructor + val params = cons.paramLists.flatten.map { param => + val t = param.typeSignature + val paramName = param.name.toString + val col = q"$namingStrategy.column($paramName)" + // Resolve implicit decoders (from SqlContext) and apply ResultSet for each + val d = q"implicitly[${c.prefix}.Decoder[$t]]" + // Minus 1 cause Quill JDBC decoders make plus one. + // ¯\_(ツ)_/¯ + val i = q"row.findColumn($col) - 1" + val decoderName = TermName(paramName + "Decoder") + val valueName = TermName(paramName + "Value") + ( + q"val $decoderName = $d", + q"val $valueName = $decoderName($i, row)", + valueName + ) + } + // Call constructor with param list + q""" + ..${params.map(_._1)} + ..${params.map(_._2)} + new $tpe(..${params.map(_._3)}) + """ + } + resultOpt match { + case Some(result) => result + case None => c.abort(c.enclosingPosition, + s"Can not derive extractor for $tpe. Constructor not found.") + } + } + q"(row: java.sql.ResultSet) => $functionBody" + } +} |