Question

import scala.slick.driver.MySQLDriver.simple._

class RichTable[T](tag: Tag, name: String) extends Table[T](tag, name) {

  case class QueryExt[B](q: Query[RichTable.this.type, B])  {
    def whereEq[C](col: RichTable.this.type => Column[C], c: C) = {
      q.filter { fields =>
        col(fields) === c
      }
    }
  }

}

Then it complains

[error] /home/jilen/workspace/play-slick/src/main/scala/play/slick/SlickQueryExtension.scala:10: value === is not a member of slick.driver.MySQLDriver.simple.Column[C]
[error]         col(fields) === c
[error]                     ^
[error] /home/jilen/workspace/play-slick/src/main/scala/play/slick/SlickQueryExtension.scala:9: ambiguous implicit values:
[error]  both value BooleanColumnCanBeQueryCondition in object CanBeQueryCondition of type => scala.slick.lifted.CanBeQueryCondition[scala.slick.lifted.Column[Boolean]]
[error]  and value BooleanOptionColumnCanBeQueryCondition in object CanBeQueryCondition of type => scala.slick.lifted.CanBeQueryCondition[scala.slick.lifted.Column[Option[Boolean]]]
[error]  match expected type scala.slick.lifted.CanBeQueryCondition[Nothing]
[error]       q.filter { fields =>
[error]                ^
[error] two errors found
[error] (compile:compile) Compilation failed
[error] Total time: 0 s, completed Mar 6, 2014 1:21:48 AM

There have been questions about this, but the answers did not work for 2.0

How to parametrize Scala Slick queries by WHERE clause conditions?

Était-ce utile?

La solution

Slick doesn't have any information about C, so it doesn't know if it can and how it should map it to a database value and if it can use === on it. So you get a type error. You will have to use Scala's type system to restrict the type to one for which Slick knows how to map it. You can do this by providing a so-called Context Bound, in this case :BaseColumnType.

def whereEq[C:BaseColumnType](col: RichTable.this.type => Column[C], c: C) = {
  q.filter { fields =>
    col(fields) === c
  }
}

BaseColumnType is provided by Slick and using it in this way basically tells the Scala compiler to look for an implicit value of type BaseColumnType[C] in scope, where you call whereEq. Because then it is usually known what C will actually be. Slick comes with BaseColumnType[Int], BaseColumnType[String], etc. so at the call site, the Scala compiler can find one when your C is really an Int or String in that particular call and this way pass the info further to Slick.

Same for LiuTiger's question. abstract class Crud[..., PK:BaseColumnType] should do the trick, a trait doesn't work with context bounds. When implementing an abstract DAO be prepared to face a lot of challenges and get to the edges of your Scala type system skills and learn quite a bit about type inference order, implicit parameters, etc.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top