Better sleek dynamic query coding style

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 the above for a dynamic query. really boring, is any better way to do this?

+4
source share
5 answers

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

+7
source

I modified cvogt's answer to work with slice 2.1.0 . An explanation of what has changed is in here .

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

Sincerely.

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

Full example:

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

+2
source

, 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) 
  }
}
+2

IsLocked, isProcessed ..

,

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

: -}

0

Well, this code seems to violate OCP. Try looking at this article - although it is not at Scala, it explains how to create such methods correctly.

-2
source

Source: https://habr.com/ru/post/1528920/


All Articles