Scala: how to define an abstract copyable superclass for any case class?
<p>Please bear with me, there is some context until the OP makes sense. I'm using Slick 3.1.x and the slick code generator. btw The whole source code can be found in the <a href="https://github.com/bravegag/play-authenticate-usage-scala" rel="noreferrer">play-authenticate-usage-scala github project</a>. For this project I'd like to have a slick generic Dao to avoid repeating the same boilerplate code for every model.</p>

<p>I have a postgres sql script that creates the database using evolutions here:
<a href="https://github.com/bravegag/play-authenticate-usage-scala/blob/master/conf/evolutions/default/1.sql" rel="noreferrer">1.sql</a></p>

<p>I then invoke a generator that generates the following data model:
<a href="https://github.com/bravegag/play-authenticate-usage-scala/blob/master/app/generated/Tables.scala" rel="noreferrer">Tables.scala</a> </p>

<p>To be able to provide generic dao slick implementations for the model classes I need them to comply to some basic abstractions e.g.</p>

<ul>
<li><a href="https://github.com/bravegag/play-authenticate-usage-scala/blob/master/app/generated/TablesAdapter.scala#L7" rel="noreferrer">Entity</a> trait: Every entity has an <code>id</code> e.g. needed for dao's <code>findById</code></li>
<li><a href="https://github.com/bravegag/play-authenticate-usage-scala/blob/master/app/generated/TablesAdapter.scala#L18" rel="noreferrer">AutoIncEntity</a> trait declares the method <code>def copyWithNewId(id : PK) : Entity[PK]</code>. This is needed for the dao's implementation of <code>createAndFetch</code>that persists a new entity and retrieves the auto generated <code>id</code> PK in one step. </li>
</ul>

<p>This <code>copyWithNewId</code> is the point of the OP. Note that it is called <code>copyWithNewId</code> and not <code>copy</code> to avoid infinite recursion. To be able to implement the <a href="https://github.com/bravegag/play-authenticate-usage-scala/blob/master/app/dao/GenericDaoAutoIncImpl.scala#L14" rel="noreferrer">GenericDaoAutoIncImpl</a> that allows inserting and immediately fetching the auto generated <code>id</code>, the entity row requires a <code>copy(id = id)</code> method coming from the <code>&lt;Model&gt;Row</code> case class that at the point of defining the <code>GenericDaoAutoIncImpl</code> it is not yet known. The relevant implementation is the following:</p>

<pre><code>override def createAndFetch(entity: E): Future[Option[E]] = {
  val insertQuery = tableQuery returning tableQuery.map(_.id) 
                        into ((row, id) =&gt; row.copyWithNewId(id))
  db.run((insertQuery += entity).flatMap(row =&gt; findById(row.id)))
}
</code></pre>

<p>And this requires me to implement the <code>copyWithNewId</code> method in every <code>AutoInc</code> <code>id</code> generated model and that is not nice e.g.</p>

<pre><code>// generated code and modified later to adapt it for the generic dao 
case class UserRow(id: Long, ...) extends AutoIncEntity[Long] with Subject {
  override def copyWithNewId(id : Long) : Entity[Long] = this.copy(id = id)
}
</code></pre>

<p>However if I could - using some Scala trick - define my <code>&lt;Model&gt;Row</code> case classes subclass of a Base class that is copyable and copies itself except for the passed <code>id</code>i.e. <code>IdCopyable</code> with <code>copy(id = id)</code> then I would not need to implement over and over this <code>copyWithNewId</code> for every <code>&lt;Model&gt;Row</code>  generated case class.</p>

<p>Is there a way to abstract or "pull up" refactor <code>copy(id = id)</code> for any case class that contains an <code>id</code> attribute? is there any other recommended solution?</p>

<p><strong>UPDATE 1</strong> The following pretty much summarizes the problem I have:</p>

<pre><code>scala&gt; abstract class BaseA[A &lt;: BaseA[_]] { def copy(id : Int) : A }
defined class BaseA

scala&gt; case class A(id: Int) extends BaseA[A]
&lt;console&gt;:12: error: class A needs to be abstract, since method copy in class BaseA of type (id: Int)A is not defined
   case class A(id: Int) extends BaseA[A]
              ^

scala&gt; case class A(id: Int); val a = A(5); a.copy(6)
defined class A
a: A = A(5)
res0: A = A(6)
</code></pre>

<p><strong>UPDATE 2</strong> Using the proposed solution below I get the following compilation errors:</p>

<pre><code>[error] /home/bravegag/code/play-authenticate-usage-scala/app/dao/GenericDaoAutoIncImpl.scala:26: could not find implicit value for parameter gen: shapeless.Generic.Aux[E,Repr]
[error]     val insertQuery = tableQuery returning tableQuery.map(_.id) into ((row, id) =&gt; row.copyWithNewId(id))
[error]                                                                                                     ^
[error] /home/bravegag/code/play-authenticate-usage-scala/app/dao/GenericDaoAutoIncImpl.scala:27: value id is not a member of insertQuery.SingleInsertResult
[error]     db.run((insertQuery += entity).flatMap(row =&gt; findById(row.id)))
[error]                                                                ^
[error] two errors found
</code></pre>

<p><strong>UPDATE 3</strong> using and adapting the proposed lenses solution below I get the following compiler errors:</p>

<pre><code>import shapeless._, tag.@@
import shapeless._
import tag.$at$at

/**
  * Identifyable base for all Strong Entity Model types
  * @tparam PK Primary key type
  * @tparam E Actual case class EntityRow type
  */
trait AutoIncEntity[PK, E &lt;: AutoIncEntity[PK, E]] extends Entity[PK] { self: E =&gt;
  //------------------------------------------------------------------------
  // public
  //------------------------------------------------------------------------
  /**
    * Returns the entity with updated id as generated by the database
    * @param id The entity id
    * @return the entity with updated id as generated by the database
    */
  def copyWithNewId(id : PK)(implicit mkLens: MkFieldLens.Aux[E, Symbol @@ Witness.`"id"`.T, PK]) : E = {
    (lens[E] &gt;&gt; 'id).set(self)(id)
  }
}
</code></pre>

<p>I then get the following compiler error:</p>

<pre><code>[error] /home/bravegag/code/play-authenticate-usage-scala/app/dao/GenericDaoAutoIncImpl.scala:26: could not find implicit value for parameter mkLens: shapeless.MkFieldLens.Aux[E,shapeless.tag.@@[Symbol,String("id")],PK]
[error]     val insertQuery = tableQuery returning tableQuery.map(_.id) into ((row, id) =&gt; row.copyWithNewId(id))
[error]                                                                                                     ^
[error] /home/bravegag/code/play-authenticate-usage-scala/app/dao/GenericDaoAutoIncImpl.scala:27: value id is not a member of insertQuery.SingleInsertResult
[error]     db.run((insertQuery += entity).flatMap(row =&gt; findById(row.id)))
[error]                                                                ^
</code></pre>