Reusable Table classes in Scala Slick

79 Views Asked by At

In a Play application, I have a few tables and classes that share the same structure. I want to keep them different to maintain application semantics (yay static typing!). However, I'd like to avoid duplicating boilerplate code.

For example, here's class Region.

case class Region(id: Int, name:String)

and here is its Slick's table query class:

class RegionsTable(tag:Tag) extends Table[Region](tag, "regions") {
  def id = column[Int]("id", O.AutoInc, O.PrimaryKey)
  def name = column[String]("name", O.Unique)
  
  def * = (id, name) <> (Region.tupled, Region.unapply)
}

How can I avoid duplicating the table query class for each of the other classes that share Region's structure?

1

There are 1 best solutions below

0
Ivan Kurchenko On BEST ANSWER

Perhaps not very Slick native solution, but refactoring might look like:

import slick.jdbc.H2Profile.api._
import scala.reflect.ClassTag

case class Region(id: Int, name: String)
case class Country(id: Int, name: String)

class IdNameTable[T](tag: Tag, tableName: String, apply: (Int, String) => T, unapply: T => Option[(Int, String)])
                    (implicit classTag: ClassTag[T]) extends Table[T](tag, tableName) {
  def id = column[Int]("id", O.AutoInc, O.PrimaryKey)
  def name = column[String]("name", O.Unique)
  def * = (id, name) <> (apply.tupled, unapply)
}

class RegionsTable(tag: Tag) extends IdNameTable[Region](tag, "regions", Region, Region.unapply)

class CountryTable(tag: Tag) extends IdNameTable[Country](tag, "country", Country, Country.unapply)

Working Scatie example: https://scastie.scala-lang.org/fR7BzS1jSKSXptE9CTxXyA