Skip to content

Instantly share code, notes, and snippets.

@1178615156
Last active November 27, 2016 03:14
Show Gist options
  • Save 1178615156/9e6b4f5fe093f012177a93ef60f2aee1 to your computer and use it in GitHub Desktop.
Save 1178615156/9e6b4f5fe093f012177a93ef60f2aee1 to your computer and use it in GitHub Desktop.
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