My application's model includes a number of entities that share many common properties, and are operated on by many of the same classes.
If I was using an ORM, I'd define an abstract class with the common properties, setup class table inheritance for persistence, and have the classes that operate on all these entity types operate on the abstract class.
However, I am using Slick, not an ORM. I could easily jury-rig an ORM-like solution:
sealed trait Shape {
def id: Long
def color: String
}
case class Triangle(id: Long, color: String, a: Int, b: Int, c: Int) extends Shape
case class Square(id: Long, color: String, sideLength: Int) extends Shape
//Hides the fact that shape instances are persisted in two tables
class ShapeDAO {
def create(shape: Shape) : Unit
def update(shape: Shape) : Unit
def retrieve(id: Long): Option[Shape]
def delete(id: Long): Unit
}
I lose the composability that's such a big selling point for slick, but it seems like I might be able to get that back by adding something heinous like this:
def rawShape: Query =
(shapes joinLeft triangles on (shapes.id === triangles.id)
joinLeft squares on (shapes.id === squares.id)) map {
shape_type match {
case "triangle" => Triangle(shape, triangle)
case "square" => Square(shape, square)
}
I could then join off of rawShape or otherwise use it in cases where I need more flexibility.
How bad is what I'm suggesting? Complicated queries that might benefit from being able to build off of something like rawQuery are very rare in this application... for the most part we're just CRUD-ing single entities in very simple ways. Having a common base class and a single DAO that encapsulates all the messy details of getting shapes would be a big win for the project, in that it would keep classes that have to deal with shapes simple.