Could you please explain to me how I can convert MappedProjection to ProvenShape which currently fails due to ambiguous implicit?
I use slick-pg for support of jsonb types in Postgres DB.
I have simple case class that I want to store as json and there is ID column with value from case class.
case class Topic(id: String, title: String)
class TopicRow(tag: Tag) extends Table[(String, Topic)](tag, Topic.tableName) {
  def id = column[String]("id", O.PrimaryKey)
  def json = column[Topic]("json")
  def * = (id, json)
}
earlier in the code I have conversion between json and case class
import spray.json._
implicit val TopicColumnType = MappedColumnType.base[Topic, JsValue ](
  { obj => obj.toJson }, { json => json.convertTo[Topic] }
)
What I don't like about TopicRow is that it maps to tuple. I'd like it to be something like this
class TopicRow(tag: Tag) extends Table[Topic](tag, Topic.tableName) {
  def id = column[String]("id", O.PrimaryKey)
  def json = column[Topic]("json")
  val tupled: ((String, Topic)) => (Topic) = tu => tu._2
  val unapply: (Topic) => Option[(String, Topic)] = t => Option((t.id, t))
  def * = (id, json) <> (tupled, unapply)
}
It fails to compile with error
Error:(43, 22) type mismatch;
 found   : slick.lifted.MappedProjection[co.younetworks.medstream.server.models.db.Topic,(String, co.younetworks.medstream.server.models.db.Topic)]
 required: slick.lifted.ProvenShape[co.younetworks.medstream.server.models.db.Topic]
So I specified explicitly every step of conversion like this
def * = {
  val shape: ProvenShape[Topic] = {
    val tupled: ((String, Topic)) => (Topic) = tu => tu._2
    val unapply: (Topic) => Option[(String, Topic)] = t => Option((t.id, t))
    val toToShapedValue: ToShapedValue[(Rep[String], Rep[Topic])] = anyToToShapedValue((id, json))
    val mappedProjection: MappedProjection[Topic, (String, Topic)] = toToShapedValue <>(tupled, unapply)
    ProvenShape.proveShapeOf(mappedProjection)
  }
  shape
}
that gives me error
Error:(52, 31) ambiguous implicit values:
 both method mappedProjectionShape in object MappedProjection of type [Level >: slick.lifted.FlatShapeLevel <: slick.lifted.ShapeLevel, T, P]=> slick.lifted.Shape[Level,slick.lifted.MappedProjection[T,P],T,slick.lifted.MappedProjection[T,P]]
 and method repColumnShape in trait RepShapeImplicits of type [T, Level <: slick.lifted.ShapeLevel](implicit evidence$1: slick.ast.BaseTypedType[T])slick.lifted.Shape[Level,slick.lifted.Rep[T],T,slick.lifted.Rep[T]]
 match expected type slick.lifted.Shape[_ <: slick.lifted.FlatShapeLevel, slick.lifted.MappedProjection[co.younetworks.medstream.server.models.db.Topic,(String, co.younetworks.medstream.server.models.db.Topic)], U, _]
      ProvenShape.proveShapeOf(mappedProjection)
                              ^
I suspect I confused compiler with presence of mapped column but I don't know how to fix it.
Well, explicit specification of implicit helped. It doesn't look pretty though.
class TopicRow(tag: Tag) extends Table[Topic](tag, Topic.tableName) with JsonMarshallers {
  def id = column[String]("id", O.PrimaryKey)
  def json = column[Topic]("json")
  private val fromTuple : ((String, Topic)) => (Topic) = { case (_, value) => value }
  private val toTuple = (v : Topic) => Option((v.id, v))
  def * = ProvenShape.proveShapeOf((id, json) <> (fromTuple, toTuple))(MappedProjection.mappedProjectionShape)
}
If anyone knows how to make it shorted please let me know.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With