slickslick-2.0

slick: nested (embedded) classes DRY


If can define nested classes (embedded in JPA) following learning slick2 like this:

case class Person(name: Name, address: Address)
case class Name(given: String, family: String)
case class Address(street: String, city: String)

class Directory(tag: Tag) extends Table[Person](tag, "directory") {
  def givenName   = column["String"] ( "given_name" )
  def familyName  = column["String"] ( "family_name" )
  def street      = column["String"] ( "street" )
  def city        = column["String"] ( "city" )

  def * = (name, address) <> (Person.tupled, Person.unapply)
  def name = (givenName, familyName) <> (Name.tupled, Name.unapply)
  def address = (street, city) <> (Address.tupled, Address.unapply)
}

I would not like to write the definition of street, city and address in every table I embed Adress. I would like to write something like below, but this does not compile for the obvious reasons, because column is a method on Table etc... Is it possible to reuse column definitions somehow?

object Adresses {
    def street      = column["String"] ( "street" )
    def city        = column["String"] ( "city" )
    def address = (street, city) <> (Address.tupled, Address.unapply)
}

class Directory(tag: Tag) extends Table[Person](tag, "directory") {
      def givenName   = column["String"] ( "given_name" )
      def familyName  = column["String"] ( "family_name" )


      def * = (name, Adresses.address) <> (Person.tupled, Person.unapply)  //address from Adresses
      def name = (givenName, familyName) <> (Name.tupled, Name.unapply)
}

Solution

  • You can make Adresses a trait that inherits from the class Table (yep that works).

    trait Adresses[T] extends Table[T]{
        def street      = column["String"] ( "street" )
        def city        = column["String"] ( "city" )
        def address = (street, city) <> (Address.tupled, Address.unapply)
    }
    
    class Directory(tag: Tag) extends Table[Person](tag, "directory") with Adresses[Person] {
          def givenName   = column["String"] ( "given_name" )
          def familyName  = column["String"] ( "family_name" )
    
    
          def * = (name, address) <> (Person.tupled, Person.unapply)  //address from Adresses
          def name = (givenName, familyName) <> (Name.tupled, Name.unapply)
    }