Slick codegen & tables with > 22 columns

508 views
Skip to first unread message

Bart Kummel

unread,
Apr 15, 2016, 2:55:03 AM4/15/16
to Slick / ScalaQuery

I'm new to Slick. I'm creating a test suite for a Java application with Scala, ScalaTest and Slick. I'm using slick to prepare data before the test and to do assertions on the data after the test. The database used has some tables with more than 22 columns. I use slick-codegen to generate my schema code.


For tables with more than 22 columns, slick-codegen does not generate a case class, but a HList-based custom type and a companion ‘constructor’ method. As I understand it, this is because the limitation that tuples and case classes can only have 22 fields. The way the code is generated, the fields of a Row-object can only be accessed by index.

I have a couple of questions about this:

  1. For what I understand, the 22 fields restriction for case classes is already fixed in Scala 2.11, right?
  2. If that's the case, would it be possible to customize slick-codegen to generate case classes for all tables? I looked into this: I managed to set override def hlistEnabled = false in an overridden SourceCodeGenerator. But this results in Cannot generate tuple for > 22 columns, please set hlistEnable=true or override compound. So I don’t get the point of being able to disbale HList. May be the catch is in the ‘or override compound’ part, but I don't understand what that means.
  3. Searching the internet on slick and 22 columns, I came across some solutions based on nested tuples. Would it be possible to customize the codegen to use this approach?
  4. If generating code with case classes with > 22 fields is not a viable option, I think it would be possible to generate an ordinary class, which has an ‘accessor’ function for each column, thus providing a ‘mapping’ from index-based access to name-based access. I’d be happy to implement the generation for this myself, but I think I need some pointers where to start. I think it should be able to override the standard codegen for this. I already use an overridden SourceCodeGenerator for some custom data types. But apart from this use case, the documentation of the code generator does not help me that much.

I would really appreciate some help here. Thanks in advance!

Roy Phillips

unread,
Apr 17, 2016, 7:53:56 AM4/17/16
to Slick / ScalaQuery
A solution that avoids the 22 column limit is to compose your mapped case class form other classes, leading to a cleaner design as well.
In the following example (less than 22 columns, but this works for 22+ as well), one for the fields in the case class is of a case class itself, constructed from two table columns - this pattern can be extended to logically group many columns into appropriate case class domain objects.
IntelliJ currently has an open issue where this projection is highlighted as a syntax error (https://youtrack.jetbrains.com/issue/SCL-8829) but it compiles and runs correctly.

class OrganizationTable(tag: Tag) extends Table[Organization](tag, "organization") {

 def id =           column[Long]         ("id", O.PrimaryKey, O.AutoInc)

 def name =         column[String]       ("name")

 def rating =       column[Int]          ("rating")

 def support =      column[Boolean]      ("support")

 def parentId =     column[Option[Long]] ("parent_id")

 def regionId =     column[Long]         ("region_id")

 def orgType =      column[String]       ("type")

 def sector =       column[String]       ("sector")

 def regType =      column[String]       ("reg_type")

 def regName =      column[String]       ("reg_id")

 def status =       column[String]       ("status")

 def created =      column[LocalDateTime]("created")

 def version =      column[Int]("version")


  def * = (

   id, regionId, name, rating, support, parentId, orgType, sector, (regType, regName), status, created, version).shaped <> (

   { case (id, regionId, name, rating, support, parentId, orgType, sector, reg, status, created, version) =>

     Organization(regionId, name, parentId, orgType, sector, Registration.tupled.apply(reg),
                  rating
, support, status, created, version, id)

   },

   { o: Organization =>

     Some(o.id, o.regionId, o.name, o.rating, o.support, o.parentId, o.orgType, o.sector,
         
Registration.unapply(o.reg).get, o.status, o.created, o.version)

   })

}



Bart Kummel

unread,
Apr 17, 2016, 8:11:36 AM4/17/16
to Slick / ScalaQuery
Hi Roy,

Thanks for your reply! I can see how this can work. However, how do I get slick-codegen to generate such code for me? I need to use this in a scenario where the database schema can change, and I don't want to have to change my code every time that happens, I want to just rerun the codegen in such a case. The thing is, the documentation of slick-codegen is a bit minimalistic, so I was hoping someone already figured this out.

Best regards,
Bart

Op zondag 17 april 2016 13:53:56 UTC+2 schreef Roy Phillips:

Bart Kummel

unread,
Apr 19, 2016, 8:11:31 AM4/19/16
to Slick / ScalaQuery
Hi,

I've just answered my own question at StackOverflow: https://stackoverflow.com/questions/36618280/slick-codegen-tables-with-22-columns/36717951#36717951

Best regards,
Bart

Op zondag 17 april 2016 14:11:36 UTC+2 schreef Bart Kummel:
Reply all
Reply to author
Forward
0 new messages