ThaDon ThaDon - 1 year ago 54
Scala Question

joinLeft error: constructor cannot be instantiated to expected type

I'm converting some code from Slick 2.1 to 3.0.3, and when I migrated my join from using

I'm receiving this error and I'm not sure how to solve it:

[error] ContentRepoLocal.scala:84: constructor cannot be instantiated to expected type;
[error] found : (T1, T2)
[error] required: slick.lifted.Rep[Option[(repo.model.UserContentTable, repo.model.ContentTable)]]
[error] .map { case (u, (uc, c)) => (u, c.optionProjection) }
[error] ^
[error] ContentRepoLocal.scala:84: diverging implicit expansion for type slick.lifted.Shape[_ <: slick.lifted.FlatShapeLevel, Nothing, T, G]
[error] starting with method repColumnShape in trait RepShapeImplicits
[error] .map { case (u, (uc, c)) => (u, c.optionProjection) }

On this code:

def getContentsByUser(userId: UUID): Either[UserNotFoundError, List[Content]] = {

val subQuery =
for {
uc <- UserContentTable.query if uc.userId === userId.toString && (!uc.adopted.isDefined || !uc.adopted)
c <- ContentTable.query if uc.contentId ===
} yield (uc, c)

val query =
UserTable.query.filter( === userId.toString)
.joinLeft(subQuery).on { case (u, (uc, c)) => === uc.userId}
.map { case (u, (uc, c)) => (u, c.optionProjection) }




Got a little bit further with this by refactoring my subQuery to use the
comprehension syntax:

val query =
for (
(u, t) <- UserTable.query.filter( === userId.toString) joinLeft subQuery on { case (u, (uc, c)) => === uc.userId }
) yield (u, t)

This compiles. However, according to the documentation the
should be applying
to convert
values to

So when I refactor the line to read:

yield (u,

I get the error:

[error] missing parameter type for expanded function ((x$2) =>$2))
[error] ) yield (u,
[error] ^
[error] one error found

EDIT 2 : You can find a Minimal, Complete, and Verifiable example here.

EDIT 3: Confirmed this issue exists in Slick
as well

Answer Source

joinLeft joins subQuery as Option in Slick3. In this case, you have to re-map subQuery as follows:

val query =
   UserTable.query.filter( === userId.toString)
     .joinLeft(subQuery).on { case (u, (uc, c)) => === uc.userId}
     .map { case (u, sub) => (u, { case (uc, c) => c }) }