嗨,我一直在尝试使用宏和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] ^
我猜我从根本上误会了一些宏。任何启发将不胜感激!
谢谢!
答案 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
})
"""
}