Question

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
    }

I am writing things like above to do dynamic query. really boring, any way better to do this ?

Was it helpful?

Solution

Maybe the MaybeFilter can help you https://gist.github.com/cvogt/9193220

OTHER TIPS

I think this is the correct migrated code for slick 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) 
  }
}

I modified the answer of cvogt in order to work with slick 2.1.0. Explanations of what have changed are in here.

Hope it helps someone :)

  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 }
    }
  }

Regards.

Corrected example:

//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

Complete example:

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

Are isLocked, isProcessed, etc Options?

Then you can also write things like

for (locked <- query.isLocked) { q = q.filter(_.isLocked is locked) }

if that's of any consolation :-}

Well, it seems like this code violates OCP. Try to take a look on this article - even though it's not on Scala, it explains how to properly design such methods.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top