I'm doing R&D whether we should or should not use Scala 2.11/Play 2.4/Slick 3.1 stack for out new app. I did some Scala programming few years ago and kept it as my favourite language for small personal projects but advanced concepts still are a mystery to me.
After reading this blog post by Matt Handler I want to replicate this behaviour in my PoC app but I run into some problems.
case class BaseModel[A] (id: Long, model: A)
object BaseModel {
import scala.language.implicitConversions
implicit def toModel[A](modelWithId: BaseModel[A]): A = modelWithId.model
}
case class Ingredient(name: String, description: String)
class IngredientsTable(tag: Tag) extends Table[BaseModel[Ingredient]](tag, "ingredients") {
def id = column[Long]("id", O.PrimaryKey, O.AutoInc)
def name = column[String]("name")
def description = column[String]("description")
def * = (id, name, description) <> ??? // ((BaseModel[Ingredient].apply _).tupled, BaseModel[Ingredient].unapply)
}
My question is what should I place instead of ???
as commented out pard doesn't work for obvious reason? I know I need to create there a custom Slick shape so it boxes/unboxes contained model val but how should I do it (Slick docs aren't too helpful in this matter)?
I tried to do something like that based on this answer but it gives me compile error as I taken this from earlier Slick version and apparently I don't understand what is going on here.
def * = (id, name, description) <> (
(id, name, description) => BaseModel[Ingredient](id, Ingredient(name, description)),
(f: BaseModel[Ingredient]) => Some((f.id, f.name, f.description))
)
Hopefully I'm looking for something more automatic (overriden tupled, unapply in BaseModel?) but anything working and any help at all appreciated. Even RTFM if pointed to the right place.
EDIT: JimN suggested an answer which works but needs quite a lot of boilerplate when creating each such mapping. Could you suggest an answer which would minimize the amount of boilerplate?
Here is what's added to the IngredientsTable
:
def toBaseModel(id: Long, name: String, description: String): BaseModel[Ingredient] = {
BaseModel[Ingredient](id, Ingredient(name, description))
}
def fromBaseModel(m: BaseModel[Ingredient]): Option[(Long, String, String)] = {
Some((m.id, m.name, m.description))
}
def * = (id, name, description) <> ((toBaseModel _).tupled, fromBaseModel)