带套筒的通用宏

时间:2018-11-06 21:39:34

标签: scala scala-macros quill.io

嗨,我一直在尝试使用宏和Quill创建一些通用函数。

这是我对宏的实现:

class Impl(val c: Context) {
  import c.universe._
  def all[T](tblName: Tree, ctx: Tree)(implicit t: WeakTypeTag[T]): Tree =
    q"""
      import ${ctx}._
      implicit val schema = schemaMeta[$t](${tblName})
      run(quote {
        query[$t]
      }) 
    """
}

object Macros {
  def all[T](tblName: String, ctx: MysqlAsyncContext[Literal.type]): Future[List[T]] = macro Impl.all[T]
}

我已经尝试在以下代码中使用它:

case class Language(id: Short, iso639_1: String, name: String) 

object Language {
    val tableName = "Languages"
    def all()(implicit mysql: MysqlAsyncContext[Literal.type], ec: ExecutionContext): Future[List[Language]] =
        Macros.all[Language](tableName, mysql)
}

但是随后出现以下错误:

Language.scala:99:25: type mismatch;
[error]  found   : mysql.Quoted[mysql.EntityQuery[Language]]{def quoted: io.getquill.ast.Entity; def ast: io.getquill.ast.Entity; def id1101286793(): Unit; val liftings: Object}
[error]  required: io.getquill.MysqlAsyncContext[io.getquill.Literal.type]#EntityQuery[com.github.pokeboston.libghpagesapi.normalized.Language]
[error]     Macros.all[Language]("Languages", mysql)
[error]                         ^

但是我知道传递给宏的ctx实际上是MysqlAsyncContext,因为当我将宏代码更改为:

class Impl(val c: Context) {
  import c.universe._
  def all[T](tblName: Tree, ctx: Tree)(implicit t: WeakTypeTag[T]): Tree =
    q"""
      import ${ctx}._
      implicit val schema = schemaMeta[$t](${tblName})
      $ctx
    """
}

它给了我以下错误:

Language.scala:99:25: type mismatch;
[error]  found   : io.getquill.MysqlAsyncContext[io.getquill.Literal.type]
[error]  required: scala.concurrent.Future[List[Language]]
[error]     Macros.all[Language]("Languages", mysql)
[error]                         ^

我猜我从根本上误会了一些宏。任何启发将不胜感激!

谢谢!

1 个答案:

答案 0 :(得分:0)

quill-example之后,您应该扩展AsyncContext。

第一个写入宏:

import scala.reflect.macros.whitebox.{Context => MacroContext}

class AllAsyncMacro(val c: MacroContext) {

  import c.universe._

  def all[T](tblName: Tree)(ex: Tree)(t: WeakTypeTag[T]): Tree =
    q"""
      import ${c.prefix}._
      run(quote {
        query[$t]
      }) 
    """
}

然后创建特征(不在同一项目中,在其他模块中)

trait QueriesAsync {
  this: AsyncContext[_, _, _] =>
  def all[T](tblName: String)(ex: ExecutionContext): Future[List[T]] = macro AllAsyncMacro.all[T]
}

最后使用它(在您的示例中更改为Mysql):

  val ctx = new PostgresAsyncContext(SnakeCase, "async.postgres") with QueriesAsync

  def all()(implicit ex: ExecutionContext): Future[List[Language]] =
    ctx.all[Language](tableName)(ex)

我实现了更多方法:

trait QueriesAsync {
  this: AsyncContext[_, _, _] =>
  def all[T](tblName: String)(ex: ExecutionContext): Future[List[T]] = macro AllAsyncMacro.all[T]

  def insertOrUpdate[T](entity: T, filter: (T) => Boolean)(ex: ExecutionContext): Future[Unit] = macro AllAsyncMacro.insertOrUpdate[T]

  def create[T](entity: T): Future[Long] = macro AllAsyncMacro.create[T]

  def merge[T](entity: T): Future[Long] = macro AllAsyncMacro.merge[T]

  def deleteByFilter[T](filter: (T) => Boolean): Future[Long] = macro AllAsyncMacro.deleteByFilter[T]
}

请参阅:

import scala.reflect.macros.whitebox.{Context => MacroContext}


class AllAsyncMacro(val c: MacroContext) {

  import c.universe._

  def all[T](tblName: Tree)(ex: Tree)(t: WeakTypeTag[T]): Tree =
    q"""
      import ${c.prefix}._
      run(quote {
        query[$t]
      }) 
    """

  def insertOrUpdate[T](entity: Tree, filter: Tree)(ex: Tree)(implicit t: WeakTypeTag[T]): Tree =
    q"""
      import ${c.prefix}._
      if (run(${c.prefix}.quote {
        ${c.prefix}.query[$t].filter($filter).update(lift($entity))
      }) == 0) {
          run(quote {
            query[$t].insert(lift($entity))
          })
      }
      ()
    """

  def create[T](entity: Tree)(implicit t: WeakTypeTag[T]): Tree =
    q"""
      import ${c.prefix}._
          run(quote {
            query[$t].insert(lift($entity))
          })
    """

  def merge[T](entity: Tree)(implicit t: WeakTypeTag[T]): Tree =
    q"""
      import ${c.prefix}._
      run(${c.prefix}.quote {
        ${c.prefix}.query[$t].update(lift($entity))
      })
    """

  def deleteByFilter[T](filter: Tree)(implicit t: WeakTypeTag[T]): Tree =
    q"""
      import ${c.prefix}._
      run(${c.prefix}.quote {
        ${c.prefix}.query[$t].filter($filter).delete
      })
    """
}