如何在ScalaQuery中编写查询以创建可重用的特质?

13

我在组合不同的查询组件成一个单一的查询时遇到了一些问题。我的目标是创建一组特征(例如,SoftDeletable、HasName、SortedByName、WithTimestamps),我可以将它们简单地混入到表对象中以添加这种行为。

理想情况下,它应该如下所示:

abstract class BaseModel[Tuple <: Product,CaseClass](tableName: String)
     extends Table[Tuple](tableName) {
  def id = column[Int]("id", O.AutoInc, O.PrimaryKey)

  def mapped: MappedProjection[CaseClass, TupleClass]

  def allQuery = this.map(_.mapped)
  final def all = database.withSession { implicit session: Session => 
    allQuery.list() 
  }

  ...
}

trait SoftDeletable[Tuple  <: Product, CaseClass]
    extends BaseModel[Tuple,CaseClass] {
  def isActive = column[String]("is_active")

  def * = super.* ~ isActive
  def allQuery = /* here, I'd like to compose super.allQuery 
                    with a filter that returns rows where isActive is true */
}

trait HasName[Tuple <: Product] extends Table[Tuple] {
  def name = column[String]("name")

  def * = super.* ~ name
}

trait SortedByName[Tuple <: Product] extends HasName[Tuple {
  override def allQuery = super.allQuery /* compose somehow 
                                             with (_ <- Query orderBy name */
}

我能用ScalaQuery做这些事情吗?主要的难点在于:

  1. 如何将 SoftDeletable.allQuerySortedByName.allQuery 中的过滤器与排序与 BaseModel.allQuery 进行清晰地组合?

  2. 通过在子类实现中添加 * 方法的列,Table 的元组类型参数不再匹配 - 是否有一种方法使这些特性逐步向最终具体类的列元组添加新类型?(我不认为会有,但如果有我错过了什么就太好了)。

  3. 我需要在每个特性中重复长元组声明,如果表格有五六列,这将变得非常笨拙。是否可以使用类型成员避免执行以下操作:

    case class Foo
    
    class Foos[(Int,Int,Boolean,String), Foo] extends 
      Table[(Int,Int,Boolean,String)] with 
      SoftDeletable[(Int,Int,Boolean,String), Foo] with 
      SortedByName[(Int,Int,Boolean,String), Foo] with 
      HasName[(Int,Int,Boolean,String)] {
    }
    
    我能避免所有这些重复吗?根据 IRC 上 jesnor 的建议,我能够这样避免其中的一些:
    abstract class SoftDeletableBaseModel[TupleClass <: Product, CaseClass](tableName: String)
            extends BaseModel[TupleClass, CaseClass](tableName)
            with SoftDeletable[TupleClass,CaseClass]
    
    换句话说,通过组合特定的特征,我不需要重复整个元组声明;当然,缺点是无法轻松混合各种特征 - 我需要创建许多具体的子类来避免这种重复。是否还有其他方法?
    更新:所以我意识到我不需要使用单独的CaseClass和TupleClass类型参数。由于 case 类实现了 Product*,您可以将 case 类名直接传递到 Table 中,从而解决了问题 3。
    trait SoftDeletable[CaseClass] extends BaseModel[CaseClass] { ... }
    
    class Models extends BaseModel[Model]("models") with SoftDeletable[Model] { ... }
    

不是一个答案,但如果您可以从表类型中获得一个返回其列的函数,对于两个特征,然后将它们组合起来(f1,f2)=>(t:table.type)=>(f1(t),f2(t)),您就有了一个可以传递给map的函数,它将等效于table.map(t =>((trait1col2,trait1col2),(trait2col1,trait2col2)))。 - nafg
顺便说一句,我正在尝试解决这个问题的一部分:http://stackoverflow.com/questions/11408072/trouble-getting-scala-type-inference-to-work - nafg
1个回答

1

如果您的问题只是添加排序,那不就是一个flatMap的问题吗?

def sortBy[T,U,C](q: Query[T,U], col: NamedColumn[C]) = q.flatMap(_ => Query orderBy col)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接