Search code examples
scalaimplicit-conversionsqueryl

KeyedEntity in Squeryl 0.9.6


Version 0.9.6 of Squeryl introduces a new way to declare classes that have an associated primary key, through the use of the KeyedEntityDef typeclass. Still the old way to declare

import org.squeryl.KeyedEntity

case class Foo(id: Long, myField: String) extends KeyedEntity[Long]

is supported.

I am trying to migrate an existing application that makes use of Squeryl 0.9.5 to the new version, to make use of custom primitive types, and I am facing a compilation problem. Here is an example of a trait that does not compile anymore

trait Retrievable[A <: KeyedEntity[Long]] {
  def table: Table[A]

  def get(id: Long): Option[A] = inTransaction {
    table.lookup(id)
  }
}

It was meant to be used like this:

case class Foo(id: Long, myField: String) extends KeyedEntity[Long]

object Foo extends Retrievable[Foo] {
  def table = DB.something
}

...

val foo = Foo.get(235)

Now, when I try to compile, I get the message

The method requires an implicit org.squeryl.KeyedEntityDef[A, Long] in scope, or that it extends the trait KeyedEntity[{K}]

although A does extend KeyedEntity[Long]. Even adding an implicit in scope, like

trait Retrievable[A <: KeyedEntity[Long]] {
  def table: Table[A]
  implicit val ev: <:<[A, KeyedEntity[Long]]

  def get(id: Long): Option[A] = inTransaction {
    table.lookup(id)
  }
}

does not help the implicit resolution, and the trait fails to compile.

Does anyone have a clue why the compiler is not feeding the implicit in the lookup method?


Solution

  • The signature for the lookup method was changed so that it accepts the KeyedEntityDef as an implicit parameter. For backwards compatibility, there is a KeyedEntityDef available for the KeyedEntity type. It's found in QueryDsl (see the kedForKeyedEntities implicit method), and is meant to be imported into scope as part of the "TypeMode" (i.e. PrimitiveTypeMode) that you're using. The quick answer is that you have two choices:

    • Make sure PrimitiveTypeMode._ is in scope where your Retrievable trait is defined
    • To make it more flexible, have your get method accept the same implicit parameters lookup does def get(id: Long)(implicit ked: KeyedEntityDef[T,K], dsl: QueryDsl): Option[A] and then pass them through table.lookup(id)(ked, dsl). That will push their resolution off until your get method is called and allow it to be used with whatever custom TypeMode you define.