Estoy tratando de crear algo de abstracción similar a SQL y me he topado con un problema.¿Cuál es la forma recomendada de pasar los resultados de macrocomputaciones al tiempo de ejecución?
Ésta es una “tabla de base de datos” simplificada:
trait Coffee {
def id: Long
def name: String
def brand: String
}
Ésta es mi consulta abstracción:
import language.experimental.macros
object Query {
def from[T] =
macro QueryMacros.fromMacro[T]
}
class From[T] {
def select[S](s: T => S): Select[T] =
macro QueryMacros.selectMacro[T, S]
}
class Select[T] {
def where(pred: T => Boolean): Where =
macro QueryMacros.whereMacro[T]
}
class Where(val result: String)
Ésta es mi macro aplicación:
import scala.reflect.macros.Context
object QueryMacros {
val result = new StringBuilder
def fromMacro[T : c.WeakTypeTag](c: Context): c.Expr[From[T]] = {
result ++= ("FROM " + c.weakTypeOf[T])
c.universe.reify(new From[T])
}
def selectMacro[T : c.WeakTypeTag, S : c.WeakTypeTag](c: Context)(s: c.Expr[T => S]): c.Expr[Select[T]] = {
result ++= ("SELECT " + s.tree)
c.universe.reify(new Select[T])
}
def whereMacro[S](c: Context)(pred: c.Expr[S]): c.Expr[Where] = {
result ++= ("WHERE " + pred.tree)
c.universe.reify(new Where(result.toString))
}
}
Y esta es mi código de ejemplo:
object Main extends App {
println("Query start")
val query =
Query.from[Coffee]
.select(_.id)
.where(_.brand == "FairTrade")
println(query.result)
println("Query end")
}
compila y funciona muy bien, pero la salida es:
Query start
Query end
Básicamente, result
parece estar vacío. Esperaba que mantuviera las cuerdas acumuladas de los árboles.
¿Cómo puedo pasar mis datos de la etapa de compilación de macros a la etapa siguiente, para que se muestren en el tiempo de ejecución? Por supuesto, podría pasar la cadena actual al siguiente método explícitamente, pero me gustaría evitar eso.
Hola Eugene, gracias, echaré un vistazo. Parece que hay una solución verdadera. :-) – soc