Here's how you can add a type variable to not maintain two parallel-but-similar case classes:
case class UserEntityF[F[_]](id: Option[Long] = None, username: F[String], password: F[String])
type Id[A] = A
// You can also just use Option if you don't care
// for the domain-specific type
sealed trait Updatable[+A]
case class Update[A](a :A) extends Updatable[A]
case object Keep extends Updatable[Nothing]
type UserEntity = UserEntityF[Id]
type UserEntityUpdate = UserEntityF[Updatable]
Here's how you can add another type variable to erase certains fields from the *Update
version:
case class UserEntityF[F[_], G[_]](id: G[Option[Long]] = None, username: F[String], password: F[String])
type Id[A] = A
type Forget[A] = ()
// You can also just use Option if you don't care
// for the domain-specific type
sealed trait Updatable[+A]
case class Update[A](a :A) extends Updatable[A]
case object Keep extends Updatable[Nothing]
type UserEntity = UserEntityF[Id, Id]
type UserEntityUpdate = UserEntityF[Updatable, Forget]