Search code examples
scalaslick

Making a Slick query that filters from an optional id?


I would like to query an object by id, but if a fooId is also provided then I'd like to include it in the query.

def getById(id: Long, fooIdOpt: Option[Long]): Future[Option[Bar]] = {
  val query = for {
    b <- bars if b.id === id && fooIdOpt.fold(true)(b.fooId === _)
  } yield {            // Compiler error here ^
    b
  }
  db.run(query.result.headOption)
}

The issue here is that fooIdOpt.fold(true)(b.fooId === _) needs to return a Rep[Boolean], but I'm initializing the fold with a Boolean - a clear type violation of fold's method signature.

However I can't seem to find a way to pass a Rep[Boolean] that evaluates to true in as the fold initializer. Shooting in the dark, I've tried Rep(true), and LiftedLiteral[Boolean](true), but neither quite work.

I could abandon fold entirely and go with:

b <- bars if {
  val rep1 = b.id === id
  fooIdOpt.map(fooId => rep1 && b.fooId === fooId).getOrElse(rep1)
}

But that just seems so overly complicated, and a fooIdOpt match { case Some ... wouldn't look much better.

  1. Is there a way to instantiate a Rep[Boolean] literal that always evaluates to true?
  2. If not, is there an alternative to my attempts at fold, map, or match above that will allow me to build a query that optionally compares a fooId value?

Solution

  • As you've already figured out, the ifEmpty value type for fold needs to match that of b.fooId === _, which is Rep[Boolean]. One approach would be to apply bind to the ifEmpty value as shown below:

    val query = for {
      b <- bars if b.id === id && fooIdOpt.fold(true.bind)(b.fooId === _)
    } yield b