我在db中有不同类型的实体,我希望能够以某种条件安全地过滤它们。我使用Slick进行数据库访问,但我认为这并不重要。
例如,假设我有User和Post实体。用户有id和email字段,Post有id和title字段。
现在我使用ADT来表示过滤器。看起来像这样:
sealed trait Filter {
def byId(id: Long): Filter = and(ById(id))
def byEmail(email: String): Filter = and(ByEmail(email))
def byTitle(title: String): Filter = and(ByTitle(title))
def and(other: Filter): Filter = And(this, other)
}
object Filter {
def apply(): Filter = NoFilter
}
case class ById(id: Long) extends Filter
case class ByEmail(email: String) extends Filter
case class ByTitle(title: String) extends Filter
case class And(a: Filter, b: Filter) extends Filter
case object NoFilter extends Filter
在UserDao中解释它。 PostDao看起来一样:
trait Dao[A] {
def find(filter: Filter, offset: Int, limit: Int):Seq[A]
}
object UserDao extends Dao[User]{
override def find(filter: Filter, offset: Int, limit: Int): Seq[Any] = {
filterTable(filter).drop(offset).take(limit).result
}
private def filterTable(table: Query[UserTable, User, Seq], filter: Filter): Query[UserTable, User, Seq] =
filter match {
case ById(id) => table.filter(_.id === id)
case ByEmail(email) => table.filter(_.email === email)
case And(a, b) => filterTable(filterTable(table, a), b)
case NoFilter => table
case other =>
log.warn(s"Filter not supported $other")
table
}
}
由通用服务使用:
class Service[A](dao: Dao[A]) {
def find(filter: Filter): Seq[A] = {
// do some stuff
dao.find(filter, offset = 0, limit = 100)
// do some other stuff
}
}
如您所见,但它不安全。虽然按标题过滤用户不会失败,但它没有意义,可能是导致错误的原因。我想也许我为不同的实体创建了不同的ADT集合,但是我将不得不复制非常相似的过滤器(例如id过滤器)。总而言之,我希望有过滤器:
ByTitle
ById
,And
,Or
,In
等。我该怎么办?也许ADT不是我需要的?
答案 0 :(得分:1)
如果你创建了一堆"标记"您的域对象的特征,然后您可以使用它可以过滤的数据类型参数化Filter
类型:
trait Filter[-T]
case class ById(id: Long) extends Filter[HasId]
case class ByEmail(email: String) extends Filter[HasEmail]
case class ByTitle(title: String) extends Filter[HasTitle]
case class And[A, B](a: Filter[A], b: Filter[B]) extends Filter[A with B]
case class Or[A, B](a: Filter[A], b: Filter[B]) extends Filter[A with B]
现在,您可以声明filterTable
来约束它将接受的过滤器类型:
def filterTable(table: Query[UserTable, User, Seq], filter: Filter[User]) = ...
所以,filterTable(myTable, ById(1) and ByEmail("foo"))
会编译,但是
filterTable(myTable, ByTitle("foo"))
不会。