我正在试图概括设置Squeryl(Slick带来同样的问题AFAIK)。我想避免为许多通用方法明确命名每个案例类。
table[Person]
table[Bookmark]
etc.
这也适用于生成索引,并为每个案例类创建围绕CRUD方法的包装器方法。
理想情况下,我想要做的是拥有一个类列表并将它们放入表中,添加索引并添加包装器方法:
val listOfClasses = List(classOf[Person], classOf[Bookmark])
listOfClasses.foreach(clazz => {
val tbl = table[clazz]
tbl.id is indexed
etc.
})
我认为Scala Macros会适用于此处,因为我认为您不能将值作为类型参数。此外,我需要为每种类型的表单生成方法:
def insert(model: Person): Person = persons.insert(model)
我在Macros上有一个例子,但我不知道如何生成通用数据结构。
我有一个简单的例子来说明我想要的东西:
def makeList_impl(c: Context)(clazz: c.Expr[Class[_]]): c.Expr[Unit] = {
import c.universe._
reify {
println(List[clazz.splice]()) // ERROR: error: type splice is not a member of c.Expr[Class[_]]
}
}
def makeList(clazz: Class[_]): Unit = macro makeList_impl
我该怎么做?或者Scala Macros是错误的工具吗?
答案 0 :(得分:3)
不幸的是,reify
对于您的用例来说不够灵活,但有好消息。在宏观天堂(最有可能在2.11.0),我们有一个更好的工具来构建树,称为quasiquotes:http://docs.scala-lang.org/overviews/macros/quasiquotes.html。
scala> def makeList_impl(c: Context)(clazz: c.Expr[Class[_]]): c.Expr[Any] = {
| import c.universe._
| val ConstantType(Constant(tpe: Type)) = clazz.tree.tpe
| c.Expr[Any](q"List[$tpe]()")
| }
makeList_impl: (c: scala.reflect.macros.Context)(clazz: c.Expr[Class[_]])c.Expr[Any]
scala> def makeList(clazz: Class[_]): Any = macro makeList_impl
defined term macro makeList: (clazz: Class[_])Any
scala> makeList(classOf[Int])
res2: List[Int] = List()
scala> makeList(classOf[String])
res3: List[String] = List()
Quosequotes甚至可以在2.10.x中使用,只需对构建过程进行一些小调整(http://docs.scala-lang.org/overviews/macros/paradise.html#macro_paradise_for_210x),因此您可能需要尝试一下。
答案 1 :(得分:1)
这可能不会满足您的所有需求,但它可能会有所帮助:
table
方法的签名如下所示:
protected def table[T]()(implicit manifestT: Manifest[T]): Table[T]
如您所见,它采用隐式Manifest
对象。该对象由编译器自动传递,并包含有关类型T
的信息。这实际上是Squeryl用来检查数据库实体类型的。
你可以像这样明确地传递这些清单:
val listOfManifests = List(manifest[Person], manifest[Bookmark])
listOfManifests.foreach(manifest => {
val tbl = table()(manifest)
tbl.id is indexed
etc.
})
不幸的是,此代码中的tbl
类型与Table[_ <: CommonSupertypeOfAllGivenEntities]
类似,这意味着它上面的所有操作都必须与具体类型的数据库实体无关。