更好的光滑动态查询编码风格

时间:2014-02-26 09:08:39

标签: scala slick

private def buildQuery(query: TweetQuery) = {
      var q = Tweets.map { t =>
        t
      }
      query.isLocked.foreach { isLocked =>
        q = q.filter(_.isLocked === isLocked)
      }
      query.isProcessed.foreach { isProcessed =>
        q = q.filter(_.processFinished === isProcessed)
      }
      query.maxScheduleAt.foreach { maxScheduleAt =>
        q = q.filter(_.expectScheduleAt < maxScheduleAt)
      }
      query.minScheduleAt.foreach { minScheduleAt =>
        q = q.filter(_.expectScheduleAt > minScheduleAt)
      }
      query.status.foreach { status =>
        q = q.filter(_.status === status)
      }
      query.scheduleType.foreach { scheduleType =>
        q = q.filter(_.scheduleType === scheduleType)
      }
      q
    }

我正在写上面的内容来做动态查询。真的很无聊,还有什么方法可以做到这一点?

5 个答案:

答案 0 :(得分:7)

也许MaybeFilter可以帮助你https://gist.github.com/cvogt/9193220

答案 1 :(得分:2)

我修改了 cvogt 的答案,以便使用 slick 2.1.0 。有关变更的说明见here

希望它可以帮助某人:)

  case class MaybeFilter[X, Y](val query: scala.slick.lifted.Query[X, Y, Seq]) {
    def filter(op: Option[_])(f:(X) => Column[Option[Boolean]]) = {
      op map { o => MaybeFilter(query.filter(f)) } getOrElse { this }
    }
  }

问候。

更正示例:

//Class definition
import scala.slick.driver.H2Driver.simple._
import scala.slick.lifted.{ProvenShape, ForeignKeyQuery}

// A Suppliers table with 6 columns: id, name, street, city, state, zip
class Suppliers(tag: Tag)
  extends Table[(Int, String, String, String, String, String)](tag, "SUPPLIERS") {

  // This is the primary key column:
  def id: Column[Int] = column[Int]("SUP_ID", O.PrimaryKey)
  def name: Column[String] = column[String]("SUP_NAME")
  def street: Column[String] = column[String]("STREET")
  def city: Column[String] = column[String]("CITY")
  def state: Column[String] = column[String]("STATE")
  def zip: Column[String] = column[String]("ZIP")

  // Every table needs a * projection with the same type as the table's type parameter
  def * : ProvenShape[(Int, String, String, String, String, String)] =
    (id, name, street, city, state, zip)
}

//I changed the name of the def from filter to filteredBy to ease the
//implicit conversion 
case class MaybeFilter[X, Y](val query: scala.slick.lifted.Query[X, Y, Seq]) {
  def filteredBy(op: Option[_])(f:(X) => Column[Option[Boolean]]) = {
    op map { o => MaybeFilter(query.filter(f)) } getOrElse { this }
  }
}

//Implicit conversion to the MaybeFilter in order to minimize ceremony
implicit def maybeFilterConversor[X,Y](q:Query[X,Y,Seq]) = new MaybeFilter(q)

val suppliers: TableQuery[Suppliers] = TableQuery[Suppliers]

suppliers += (101, "Acme, Inc.", "99 Market Street", "Groundsville", "CA", "95199")

//Dynamic query here
//try this asigment   val nameFilter:Option[String] = Some("cme")   and see the results
val nameFilter:Option[String] = Some("Acme")
//also try to assign None in here like this   val supIDFilter:Option[Int] = None   and see the results
val supIDFilter:Option[Int] = Some(101)

suppliers
  .filteredBy(supIDFilter){_.id === supIDFilter}
  .filteredBy(nameFilter){_.name like nameFilter.map("%" + _ + "%").getOrElse("")}
  .query.list

完整示例:

https://github.com/neowinx/hello-slick-2.1-dynamic-filter

答案 2 :(得分:2)

我认为这是光滑的2.1.0的正确迁移代码

case class MaybeFilter[X, Y](val query: Query[X, Y, Seq]) {
  def filter[T, R: CanBeQueryCondition](data: Option[T])(f: T => X => R) = {
    data.map(v => MaybeFilter(query.withFilter(f(v)))).getOrElse(this) 
  }
}

答案 3 :(得分:0)

isLocked,isProcessed等选项?

然后你也可以写像

这样的东西
for (locked <- query.isLocked) { q = q.filter(_.isLocked is locked) }

如果有任何安慰: - }

答案 4 :(得分:-2)

好吧,看起来这段代码违反了OCP。试着看看this article - 尽管它不在Scala上,它解释了如何正确设计这些方法。