Last active
November 27, 2016 03:14
-
-
Save 1178615156/9e6b4f5fe093f012177a93ef60f2aee1 to your computer and use it in GitHub Desktop.
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 scala.language.experimental.macros | |
import scala.reflect.macros.blackbox.Context | |
/** | |
* Created by yu jie shui on 2015/11/8 19:09. | |
*/ | |
object SortByName { | |
/** val field = "name" | |
* {{{ | |
* val table = { | |
* val id | |
* val name | |
* val age | |
* } | |
* }}} | |
* [[SortByName(table,field,true) ]] | |
* 等价于 | |
* {{{ | |
* table.sortBy(e => field match { | |
* case "id" => if (true) e.id.asc else e.id.desc | |
* case "name" => if (true) e.name.asc else e.name.desc | |
* case "age" => if (true) e.age.asc else e.age.desc | |
* }) | |
* }}} | |
* | |
* | |
*/ | |
def apply[EntityTable](entityTable: EntityTable, | |
sortField: String, | |
asc: Boolean) | |
: slick.lifted.Ordered = macro SortByNameImpl.apply[EntityTable] | |
} | |
class SortByNameImpl(val c: Context) { | |
import c.universe._ | |
def tableRepValue[EntityTable: c.WeakTypeTag]: Seq[c.universe.MethodSymbol] = { | |
val et = c.weakTypeOf[EntityTable] | |
val etMembers = et.members | |
.filter(_.isMethod).map(_.asMethod) | |
.filter(_.isPublic) | |
.filter(_.returnType.finalResultType.typeConstructor =:= typeOf[slick.lifted.Rep[_]].typeConstructor) | |
.filterNot(_.isConstructor) | |
.filterNot(_.name.toString == "column") | |
etMembers.toSeq | |
} | |
def applyPrefix[EntityTable: c.WeakTypeTag]( | |
entityTable: c.Expr[EntityTable], | |
asc: c.Expr[Boolean], | |
prefix: c.Expr[String]) | |
: c.Expr[PartialFunction[String, slick.lifted.Ordered]] = { | |
val etMembers = tableRepValue[EntityTable] | |
.map(e => e.name.toString -> e.info.resultType) | |
val nameCaseAsc = etMembers.map { | |
case (name, typ) => | |
val caseName = TermName(c.freshName("slick_sort_by_name")) | |
cq""" | |
$caseName:String if ($caseName==($prefix+$name)) =>{ | |
$entityTable.${name: TermName}.asc | |
} | |
""" | |
} | |
val nameCaseDesc = etMembers.map { | |
case (name, typ) => | |
val caseName = TermName(c.freshName("slick_sort_by_name")) | |
cq""" | |
$caseName:String if ($caseName==($prefix+$name)) =>{ | |
$entityTable.${name: TermName}.desc | |
} | |
""" | |
} | |
val rt = | |
q""" | |
{ | |
if ($asc) | |
PartialFunction((name:String)=>{(name match { | |
case ..$nameCaseAsc | |
}):slick.lifted.Ordered}) | |
else | |
PartialFunction((name:String)=>{(name match { | |
case ..$nameCaseDesc | |
}):slick.lifted.Ordered}) | |
} | |
""" | |
c.echo(c.enclosingPosition, show(rt)) | |
c.Expr[PartialFunction[String, slick.lifted.Ordered]](rt) | |
} | |
def apply[EntityTable: c.WeakTypeTag]( | |
entityTable: c.Expr[EntityTable], | |
sortField: c.Expr[String], | |
asc: c.Expr[Boolean]) = { | |
q""" | |
${applyPrefix(entityTable, asc, c.Expr[String]( q""" "" """))}($sortField) | |
""" | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment