Search code examples
scalaplayframeworkslickcirceplay-json

automatic JSON encoding/decoding with slick-codegen created case classes


I generated my scala model from a database with slick-codegen. Now the generation of Json mappers fails. How can I avoid doing everything by hand?

circe:

could not find implicit value for parameter encoder: io.circe.Encoder[UserController.this.db.UsersRow

play-json:

implicit val userFormat = Json.format[models.Tables#UsersRow]
No unapply or unapplySeq function found for class UsersRow: <none> / <none>

The slick-codegen generated code looks like:

package models

object Tables extends {
  val profile = slick.jdbc.PostgresProfile
} with Tables

trait Tables {
  val profile: slick.jdbc.JdbcProfile
  import profile.api._

  case class UsersRow(id: Int, username: String)
  //lots more code
}

Solution

  • You can use your own SourceCodeGenerator to create a circe implicit semi-automatic derivation for each case class.

    https://circe.github.io/circe/codecs/semiauto-derivation.html

    Code should look like ...

    new slick.codegen.SourceCodeGenerator(model){
      val importCirce =
        "import io.circe.Encoder\nimport io.circe.generic.semiauto._"
    
      val implicits = model.tables.map(t => {
        val name = entityName(t.name.table)
        s"implicit val ${name}Encoder: Encoder[${name}] = deriveEncoder[${name}]\n"
      }).mkString("\n")
    
      override def code: String =
        super.code + "\n" + importCirce + "\n\n" + implicits
    }
    

    Once the model is created you already have the decoder or encoder available

    import models.Tables._
    
    val user = new User("Peter", 1)
    println {
      user.asJson
    }
    
    

    you can check a full example here https://github.com/jgoday/scala-slick-customcodegen