Arne Claassen
Arne Claassen

Reputation: 14404

Typed projection with Slick

I'm trying to define a Type on the query side to map my join so that I can avoid returning a tuple of values that I have to manually apply to my projection case class post query.

Given a relationship like:

case class Parent(id: Int, name: String, extra: String)

class ParentTable(tag: Tag) extends Table[Parent](tag, "parent") {
  def id = column[Int]("id", O.PrimaryKey, O.AutoInc)
  def name = column[String]("name")
  def extra = column[String]("extra")
  def * = (id, name, extra) <> (Parent.tupled, Parent.unapply)
}

val parents = TableQuery[ParentTable]

case class Child(id: Int, parentId: Int, name: String, extra:  String)

class ChildTable(tag: Tag) extends Table[Child](tag, "child") {
  def id = column[Int]("id", O.PrimaryKey, O.AutoInc)
  def parentId = column[Int]("parent_id")
  def parent = foreignKey("parent_fk", parentId, parents)(_.id)
  def name = column[String]("name")
  def extra = column[String]("extra")
  def * = (id, parentId, name, extra) <> (Child.tupled, Child.unapply)
}
val children = TableQuery[ChildTable]

I want to project into a case class like:

  case class ChildWithParentName(id: Int, name: String, parentName: String)

The join and projection looks like:

val q = for {
  c <- children
  p <- parents if c.parentId === p.id
} yield (c.id,c.name,p.name)

I put this in a function and allow children and parents to be parameterized. The function doesn't run the query, because sometimes I want .result and sometimes I want .result.headOption, so my function signature is:

Query[(Rep[Int], Rep[String], Rep[String]), (Int, String, String), Seq]

I would like to create a Type on the Query side with a shape something like:

class ChildParentProjection(val id: Rep[Int], 
                            val name: Rep[String], 
                            val parentName[String])

so that I could get a function signature like:

Query[ChildParentProjection, ChildWithParentName, Seq]

Is that possible in slick?

Upvotes: 1

Views: 279

Answers (1)

Nabih Nebbache
Nabih Nebbache

Reputation: 60

I don't really understand why you would like to use the class ChildParentProjection. if you want to return a Seq[ChildWithParentName] when executing result on the query, you'll have to map the tuple resulting from your monadic join to the ChildWithParentName class like this :

val q = for {
c <- children
p <- parents if c.parentId === p.id
} yield (c.id,c.name,p.name) <> (ChildWithParentName.tupled,ChildWithParentName.unapply)

I wish I have understood your question

Upvotes: 1

Related Questions