2
votes

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?

2
Do you import === from some other library? - cvogt
Thank you for the answer! Yes, it's being added by ScalaTest as that code is part of some tests that I'm writing; is that the issue? If yes, how come it is correctly behaving if I put the userIdColumnType in scope? - Aldo Stracquadanio

2 Answers

5
votes

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.

0
votes

I fixed this by importing my driver api and making sure it was in scope

i.e. as I'm using a postgresql driver, import PostgresProfile.api._