我尝试使用Shapeless实现与Slick的表和列定义类似的东西。
此代码将与第三方Java库一起使用,因此在某些时候我需要将HList转换为Array[Any]
。
即使后面的内容似乎有效,但它看起来并不是正确的方法:
import shapeless._
import ops.hlist._
trait ColumnType[A]
object ColumnType {
implicit object StringType extends ColumnType[String]
implicit object IntType extends ColumnType[Int]
implicit object BooleanType extends ColumnType[Boolean]
}
case class Column[T : ColumnType](name: String, description: String)
trait Logger[L <: HList] {
val columns: L
object javaTypes extends Poly1 {
implicit def caseInt = at[Int](i => new java.lang.Integer(i))
implicit def caseString = at[String](identity)
implicit def caseBoolean = at[Boolean](b => new java.lang.Boolean(b))
}
object extract extends Poly1 {
implicit def caseT[T : ColumnType] = at[Column[T]](_.asInstanceOf[T])
}
def apply[P <: Product, M <: HList](p: P)(
implicit
gen: Generic.Aux[P, L],
mapper: Mapper.Aux[javaTypes.type, L, M]
): List[Any] = gen.to(p).map(javaTypes).runtimeList
}
Logger
定义如下:
class AccessLog extends Logger[String :: Int :: Boolean :: HNil] {
val path = Column[String]("path", "uri path")
val statusCode = Column[Int]("statusCode", "status code")
val authenticated = Column[Boolean]("authenticated", "is user authenticated")
val columns = HList(path, statusCode, authenticated).map(extract)
}
将被使用:
val accessLog = new AccessLog
accessLog("1", 2, false).foreach(p => println(s"$p: ${p.getClass}"))
要求是columns
的类型应该与Logger的类型参数匹配,也是将传递的值转换为Java类型的方法。
我对定义extract
的方式特别不安。