Reputation: 9325
I need to construct dynamic filter based on some criteria which involves optional column:
Criteria
case class Criteria(
name: Option[String] = None,
description: Option[String] = None,
)
Table mapping
class OrganizationsTable(tag: Tag) extends Table[OrganizationModel](tag, "organizations") {
def id = column[Long]("id", O.PrimaryKey)
def name = column[String]("name")
def description: Rep[Option[String]] = column[Option[String]]("description")
def * = (id, name, description) <> ((OrganizationModel.apply _).tupled, OrganizationModel.unapply)
}
Filter
organizations.filter { model =>
List(
criteria.name.map(model.name.like(_)),
criteria.description.map(v => model.description.isDefined && model.description.like(v))
)
.collect({case Some(cr) => cr})
// value && is not a member of slick.lifted.Rep[_1]
.reduceLeftOption(_ && _).getOrElse(true: Rep[Boolean])
}
But I'm getting compilation error:
value && is not a member of slick.lifted.Rep[1] [error]
.reduceLeftOption( && _).getOrElse(true: Rep[Boolean])
If I add get
to model.description
like this:
criteria.description.map(v => model.description.isDefined && model.description.get.like(v))
it compiles fine, but throws runtime exception:
slick.SlickException: Caught exception while computing default value for Rep[Option[_]].getOrElse -- This cannot be done lazily when the value is needed on the database side
How to build dynamic query in slick which involves optional column?
Upvotes: 3
Views: 1108
Reputation: 108101
This is a utility I use in a project at work:
implicit class OptionFilter[E, U, C[_]](query: Query[E, U, C]) {
import slick.lifted.CanBeQueryCondition
def optionalFilter[O, T <: Rep[_]](op: Option[O])(f:(E, O) => T)(
implicit wt: CanBeQueryCondition[T]): Query[E, U, C] =
op.map(o => query.withFilter(f(_,o))).getOrElse(query)
}
Usage
criteria.optionalFilter(model.description)(_.description.? like _)
Essentially it applies the filter to a query if the target value (e.g. model.description
) is defined, otherwise it just returns the original query.
Upvotes: 2