3

I have a domain that looks like this:

package object tryme {
  type ALL = AlarmMessage :+: PassMessage :+: HeyMessage :+: CNil
}
import com.tryme._

trait PayloadKind
trait Command extends PayloadKind
trait Event extends PayloadKind

trait Message[+T <: PayloadKind] {
  val id: String
  val payload: T
}

case class Alarm(severity: Int) extends Event
case class Pass(reason: String) extends Event
case class Hey(order: String) extends Command

case class AlarmMessage(id: String, payload: Alarm) extends Message[Event]
case class PassMessage(id: String, payload: Pass) extends Message[Event]
case class HeyMessage(id: String, payload: Hey) extends Message[Command]

case class AvroMessage(
    id:    String,
    cargo: ALL
)

If I create an AvroMessage with cargo = HeyMessage, I'm able to serialize/de-serialse this successfully.

When I inspect the cargo field of the deserialized AvroMessage object it looks like this:

Inr(Inr(Inl(HeyMessage(art333,Hey(wow)))))

In Shapeless, how can I unwrap/strip all the Inr/Inls? Ideally I don't want to care (post de-serialization) that the payload is a HeyMessage (or any other type) if I can avoid it. I'm going to cast the cargo to Message[PayloadKind], but first I need to unwrap it.

(I saw the answer to a similar question here, but I confess I don't understand how it works, and wasn't able to adapt it.)

PySerial Killer
  • 428
  • 1
  • 9
  • 26
Greg
  • 10,696
  • 22
  • 68
  • 98

2 Answers2

1

You can use shapeless.ops.coproduct.Selector

val coproduct = Inr(Inr(Inl(HeyMessage(art333, Hey(wow)))))
Selector[ALL, HeyMessage].apply(coproduct).get

Result is HeyMessage(art333,Hey(wow)).

https://github.com/milessabin/shapeless/blob/master/core/src/main/scala/shapeless/ops/coproduct.scala#L41-L60

Dmytro Mitin
  • 48,194
  • 3
  • 28
  • 66
1

You can use extension methods from syntax subpackage:

import shapeless.syntax._
// select returns an Option
coproduct.select[HeyMessage].get
Oleg Pyzhcov
  • 7,323
  • 1
  • 18
  • 30