At Foursquare, we have some helper methods/implicits for this situation. With the following code:
sealed class Identity[A](protected val _value: A) {
def applyIf[B >: A](pred: Boolean, f: A => B): B = if (pred) f(_value) else _value
def applyOpt[B](opt: Option[B])(f: (A, B) => A): A = opt.map(b => f(_value, b)).getOrElse(_value)
}
object Identity {
implicit def wrapIdentity[A](anything: A): Identity[A] = new Identity(anything)
}
Then, as long as the wrapIdentity implicit is in scope, you can write code like:
val query = (User
.where(_.id eqs someId)
.applyIf(something, _.modify(_.likes push List("like"))))
.applyIf(somethingElse, _.modify(_.dislikes push List("dislike"))))
query.updateMulti()
The inferred type usually does the Right Thing. Sometimes you can get yourself in a pickle with the phantom types, but there's usually a way out of it.
Usage of the similar applyOpt method is left as an exercise.
--j