scalaslickslick-2.0

Slick "===" compiling only in for comprehension


I am experiencing a strange behaviour with slick and I would like some help figuring out why it happens. The issue is that I have a query that reads as follows:

db.withSession { implicit session =>
  tables.users.where(_.id === UserId(1)).firstOption
}

This does not compile producing an error as follows:

inferred type arguments [Boolean] do not conform to method where's type parameter bounds [T <: scala.slick.lifted.Column[_]]

But if I rewrite the code as:

db.withSession { implicit session =>
  (for {
    u <- tables.users if u.id === UserId(1)
  } yield u).firstOption
}

It compiles and works fine.

The table is defined as follows:

class Users(tag: Tag) extends Table[User](tag, "users") {
  def id = column[UserId]("id", O.PrimaryKey, O.AutoInc, O.NotNull)
}

And I have an implicit conversion to map the UserId type:

implicit lazy val userIdColumnType = MappedColumnType.base[UserId, Int](_.value, UserId(_))

It looks like a type inference problem, but I can't really understand why it should happen.

Anyone has any on why this should behave differently in the two scenario I reported?

EDIT: After some investigation I found that when using where the implicit conversion for the userIdColumnType has to be in scope, while with the for comprehension it is not needed. Is there a good explanation for this?


Solution

  • You are using === from ScalaTest. It returns a Boolean. Slick's === returns a Column[Boolean]. The methods filter and where prevent using Boolean (at least in the latest version of Slick), to protect you from accidentally using == or also from using ScalaTest's === in your case, which does a local comparison of the underlying values instead of an equality comparison in the database, which is what you actualy want. For comprehensions are desugared to withFilter and can sometimes generate a Boolean value, so unfortunately we cannot disallow Boolean for comprehensions.

    To fix this you need to make sure, that Slick's === is picked in queries. Maybe you can affect this with the import order or scope. Or if you are unlucky you can't and they are incompatible.

    I am not sure how the userIdColumnType interacts here at the moment.