CommandHandler UserCommand , UserCommand a CreateUser, UpdatePassword ( , UserCommand sealed).
UserCommand CreateUser :+: UpdatePassword :+: CNil.cnilCommandHandler coproductConsCommandHandler CommandHandler .genericCommandHandler , UserCommand ( Generic[UserCommand]).
CommandHandler (<: UserCommand):
import shapeless._
trait CommandHandler[C] {
def processCommand(command: C): Unit
}
object CommandHandler {
implicit val cnilCommandHandler: CommandHandler[CNil] =
new CommandHandler[CNil] {
override def processCommand(t: CNil): Unit = ()
}
implicit def coproductConsCommandHandler[L, R <: Coproduct](implicit
lch: CommandHandler[L],
rch: CommandHandler[R]
): CommandHandler[L :+: R] =
new CommandHandler[L :+: R] {
override def processCommand(t: L :+: R): Unit = t match {
case Inl(l) => lch.processCommand(l)
case Inr(r) => rch.processCommand(r)
}
}
implicit def genericCommandHandler[A, G](implicit
gen: Generic.Aux[A, G],
cch: Lazy[CommandHandler[G]]
): CommandHandler[A] =
new CommandHandler[A] {
def processCommand(a: A): Unit = cch.value.processCommand(gen.to(a))
}
}
UserCommand:
sealed trait UserCommand
final case class CreateUser(id: String) extends UserCommand
final case class UpdatePassword(id: String, password: String) extends UserCommand
object UserCommand {
implicit val createUserCommandHandler: CommandHandler[CreateUser] =
new CommandHandler[CreateUser] {
override def processCommand(command: CreateUser) = println(command)
}
implicit val updateUserPasswordCommandHandler: CommandHandler[UpdatePassword] =
new CommandHandler[UpdatePassword] {
override def processCommand(command: UpdatePassword) = println(command)
}
}
... CommandHandlerRunner, UserCommand:
object CommandHandlerRunner {
def processCommand[C](command: C)(implicit commandHandler: CommandHandler[C]) =
commandHandler.processCommand(command)
}
val cmd1: UserCommand = CreateUser("foo")
val cmd2: UserCommand = UpdatePassword("id", "open sesame")
CommandHandlerRunner.processCommand(cmd)
// CreateUser(foo)
List(cmd1, cmd2).foreach(CommandHandlerRunner.processCommand[UserCommand] _)
// CreateUser(foo)
// UpdatePassword(id,open sesame)
, AllCommandHandler, DBCommand :
sealed trait DBCommand
final case class Get(id: Int) extends DBCommand
final case class Save[A](a: A) extends DBCommand
CommandHandler Get Save, CommandHandler[DBCommand].