Общие макросы с пером - PullRequest
       33

Общие макросы с пером

0 голосов
/ 07 ноября 2018

Привет, поэтому я пытался создать некоторые общие функции, используя макросы и 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 голосов
/ 06 июля 2019

После 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
      })
    """
}
...